问题的引入:
卸载应用的时候,system_server被kill掉导致系统重启
Log
05-01 11:05:25.661595 462 473 E ProcessKiller: Process system_server (1194) has open file/mnt/asec/com.netease.newsreader.activity-2/base.apk
05-01 11:05:25.661670 462 473 W ProcessKiller: Sending Terminated to process 1194
在代码中查找ProcessKiller,得到
android/system/vold/Process.cpp
void Process::killProcessesWithOpenFiles(const char*path, int signal) {
DIR* dir;
structdirent* de;
if (!(dir= opendir("/proc"))) {
SLOGE("opendir failed (%s)", strerror(errno));
return;
}
while((de = readdir(dir))) {
intpid = getPid(de->d_name);
charname[PATH_MAX];
if(pid == -1)
continue;
getProcessName(pid, name, sizeof(name));
charopenfile[PATH_MAX];
if(checkFileDescriptorSymLinks(pid, path, openfile, sizeof(openfile))) {
SLOGE("Process %s (%d) has open file %s", name, pid, openfile);
}else if (checkFileMaps(pid, path, openfile, sizeof(openfile))) {
SLOGE("Process %s (%d) has open filemap for %s", name, pid,openfile);
}else if (checkSymLink(pid, path, "cwd")) {
SLOGE("Process %s (%d) has cwd within %s", name, pid, path);
}else if (checkSymLink(pid, path, "root")) {
SLOGE("Process %s (%d) has chroot within %s", name, pid,path);
}else if (checkSymLink(pid, path, "exe")) {
SLOGE("Process %s (%d) has executable path within %s", name,pid, path);
}else if(checkSocketLink(pid, path)) {
SLOGE("Process %s (%d) has socket related to %s", name, pid,path);
}else {
continue;
}
if(signal != 0) {
SLOGW("Sending %s to process%d", strsignal(signal), pid);
kill(pid, signal);
}
}
closedir(dir);
}
分析killProcessesWithOpenFiles
查看/proc,里面存放的是进程相关信息
/proc/[pid]/fd 里是[pid]这个进程打开的文件fd,ls –l 可以看到对应的文件链接
killProcessesWithOpenFiles 的原理就是遍历proc目录,再遍历fd目录,如果发现文件链接就是要查找的路径,就发送一个kill命令
这里猜想一种方式,用来强制关闭文件,来解决本例中的问题,本例是由于/mnt/asec/com.netease.newsreader.activity-2/base.apk被打开了,导致卸载应用的时候,调用了killProcessesWithOpenFiles,把system_server kill掉了导致系统重启,由于不知道在哪里打开处理的,
这里尝试这个不得已的方法,就是强制把system_server里打开的/mnt/asec/com.netease.newsreader.activity-2/base.apk的文件描述符close掉
以/mnt/asec/com.netease.newsreader.activity-2为例
查看system_server的pid
ps |grep system_server
ps |grep system_server
system 1155 516 2809436 191304 SyS_epoll_ 7f804d6260 S system_server
根据得到的pid 1155到proc里进行查看
root:/proc/1155/fd # ls -l | grep mnt
ls -l | grep mnt
lr-x------ root root 2015-05-02 14:30 199 ->/mnt/asec/com.netease.newsreader.activity-2/base.apk
得到打开/mnt/asec/com.netease.newsreader.activity-2/base.apk的fd199
这样就可以通过发送信号的方式在system_server里close(fd)
system_server注册信号
kill –l 查看信号
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6)SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35)SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40)SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51)SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60)SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
修改system_server的程序
vi ./frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
//test
void sigTest(intsig)
{
if (sig == 38)
{
ALOGI("=====testsystem_server===== sig = %d", sig);
}
else
{
ALOGI("=====else testsystem_server===== sig = %d", sig);
}
}
// Utility routine to fork zygote and specializethe child process.
static pid_t ForkAndSpecializeCommon(JNIEnv* env,uid_t uid, gid_t gid, jintArray javaGids,
jint debug_flags,jobjectArray javaRlimits,
jlongpermittedCapabilities, jlong effectiveCapabilities,
jintmount_external,
jstringjava_se_info, jstring java_se_name,
boolis_system_server, jintArray fdsToClose,
jstringinstructionSet, jstring dataDir) {
SetSigChldHandler();
pid_t pid =fork();
if (pid ==0) {
// Thechild process.
gMallocLeakZygoteChild = 1;
// Cleanup any descriptors which must be closed immediately
DetachDescriptors(env, fdsToClose);
// Keepcapabilities across UID change, unless we're staying root.
if (uid!= 0) {
EnableKeepCapabilities(env);
}
DropCapabilitiesBoundingSet(env);
//
signal(38, sigTest);
//
手机root后进行测试,不root没有kill发送信号的权限
ps | grep system_serv
system 1088 447 2730844 207340 SyS_epoll_ 7fa9081260 S system_server
得到pid 1088,发送信号,这里使用约定的38
root:/ # kill -38 1088
07-02 16:19:17.891: I/Zygote(1088): =====testsystem_server===== sig = 38
现在有另外一个问题,如何跨进程把fd传给system_server
一个方法是回避这个问题,让system_server到/proc/ 里进行遍历查找,和Process.cpp里一样
或者通过socket等方法传送数据
小结
通过分析测试,可以认识到Process::killProcessesWithOpenFiles(const char*path, int signal)的处理原理和/proc/的内容结构,另外通过信号和system_server进行交互的处理方法可以揭开system_server的面纱。