2020-02-25

其实https://www.imooc.com/learn/153 李宁老师有讲

对于我们的这个跑步机来说,本身就是不正常的,经常使用shell命令,来完成不非常规的操作
如pm, am, ps, kill
所以打包系统的同学,有时候就就不再怎么得,就把root权限给禁用,或者adb shell 有root权限,但是app则没有,这种坑遇到两次,一次是艺维,一次是鉴丰立久佳t910的打包。

何为root权限

root权限就是超级管理员的权限,获取root权限后,几乎可以干任何事,比如杀掉系统级进程。执行adb shell后,输入su,如果有,则$会变成#,证明获取root权限,但是有时候需要删除system目录下文件,则需要退出android shell,重新挂载一下adb root,adb remount

为何会出现root问题

常规的有以下三种

  1. /system/xbin/su不存在
  2. /system/xbin/su权限问题
  3. /system/xbin/su不允许第三方应用获取root权限

非常规的情况

  1. 系统中有多个su文件,一个放在system/bin目录下,一个放在system/xbin目录下

/system/xbin/su不存在

一般没有被root的Android手机属于这种情况。

/system/xbin/su权限问题

一些Android开发板系统中含有 /system/xbin/su,但是运行权限没有给第三方应用,像下面这个权限就不对,应该加上对「其他用户」的可执行权限。

1
2
root@android:/ $ ls -l /system/xbin/su                                       
-rwx--x--- root shell 157400 2016-01-18 09:01 su

这个就对了:

1
2
3
chmod 06755 /system/xbin/su
root@android:/ $ ls -l /system/xbin/su
-rwx--x--x root shell 157400 2016-01-18 09:01 su

/system/xbin/su不允许第三方应用获取root权限

1
2
3
root@android:/ $ su
su: uid 10061 not allowed to su
root@android:/

解决方案是更换不过滤uid的su文件,这样你的应用就可以正常调用了。

说明:以上是以adb shell进行模拟应用身份进行root,看会输出什么信息以作出对应解决方案。

查看当前应用(Helloworld)的 uid(u0_a61),并切到该用户下,然后再运行su就相当于该APP在调用su命令了。这样就解决了不同问题在Logcat中看到的只是如标题一样的单一的错误信息的问题。

1
2
3
4
root@android:/ # ps
u0_a61 12218 120 1259632 40368 ffffffff b6e2da80 S com.example.helloworld
root@android:/ # su u0_a61
root@android:/ $ su

多个su的情况

多个su的情况是在/system/bin里有一个,在/system/xbin里也有一个,但是对于android系统来说,优先使用的是/system/bin目录下su,我们遇到文件就是在/system/bin目录下有su文件,但是执行这个su会有write failed: EPIPE (Broken pipe)异常抛出,所以给打包系统的同学说删除/system/bin下的su即可。

su可执行程序在哪

su文件在system/extras/su/su.c
su 命令,总体说来还是c程序
入口也是在main函数,从源码中可以看到
是root并且是shell 进程才是允许执行的
把第三行注释则所有应用都可以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
int main(int argc, char** argv) {
uid_t current_uid = getuid();
if (current_uid != AID_ROOT && current_uid != AID_SHELL) error(1, 0, "not allowed");

// Handle -h and --help.
++argv;
if (*argv && (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0)) {
fprintf(stderr,
"usage: su [UID[,GID[,GID2]...]] [COMMAND [ARG...]]\n"
"\n"
"Switch to WHO (default 'root') and run the given command (default sh).\n"
"\n"
"where WHO is a comma-separated list of user, group,\n"
"and supplementary groups in that order.\n"
"\n");
return 0;
}

// The default user is root.
uid_t uid = 0;
gid_t gid = 0;

// If there are any arguments, the first argument is the uid/gid/supplementary groups.
if (*argv) {
gid_t gids[10];
int gids_count = sizeof(gids)/sizeof(gids[0]);
extract_uidgids(*argv, &uid, &gid, gids, &gids_count);
if (gids_count) {
if (setgroups(gids_count, gids)) {
error(1, errno, "setgroups failed");
}
}
++argv;
}

if (setgid(gid)) error(1, errno, "setgid failed");
if (setuid(uid)) error(1, errno, "setuid failed");

// Reset parts of the environment.
setenv("PATH", _PATH_DEFPATH, 1);
unsetenv("IFS");
struct passwd* pw = getpwuid(uid);
setenv("LOGNAME", pw->pw_name, 1);
setenv("USER", pw->pw_name, 1);

// Set up the arguments for exec.
char* exec_args[argc + 1]; // Having too much space is fine.
size_t i = 0;
for (; *argv != NULL; ++i) {
exec_args[i] = *argv++;
}
// Default to the standard shell.
if (i == 0) exec_args[i++] = "/system/bin/sh";
exec_args[i] = NULL;

execvp(exec_args[0], exec_args);
error(1, errno, "failed to exec %s", exec_args[0]);
}