Android4.4的zygote进程(下)
Posted 悠然红茶
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android4.4的zygote进程(下)相关的知识,希望对你有一定的参考价值。
3.2.4启动android系统服务——startSystemServer()
接下来就是启动Android的重头戏了,此时ZygoteInit的main()函数会调用startSystemServer(),该函数用于启动整个Android系统的系统服务。其大体做法是先fork一个子进程,然后在子进程中做一些初始化动作,继而执行SystemServer类的main()静态函数。需要注意的是,startSystemServer()并不是在函数体内直接调用Java类的main()函数的,而是通过抛异常的方式,在startSystemServer()之外加以处理的。
startSystemServer()的代码如下:
private static boolean startSystemServer()
throws MethodAndArgsCaller, RuntimeException
. . . . . .
/* Hardcoded command line to start the system server */
String args[] =
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,
3001,3002,3003,3006,3007",
"--capabilities=" + capabilities + "," + capabilities,
"--runtime-init",
"--nice-name=system_server",
"com.android.server.SystemServer",
;
ZygoteConnection.Arguments parsedArgs = null;
int pid;
try
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
// fork出系统服务对应的进程
pid = Zygote.forkSystemServer(parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids, parsedArgs.debugFlags, null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
catch (IllegalArgumentException ex)
throw new RuntimeException(ex);
// 对新fork出的系统进程,执行handleSystemServerProcess()
if (pid == 0)
handleSystemServerProcess(parsedArgs);
return true;
args[]中的字符串 | 对应 |
"--setuid=1000" | parsedArgs.uid |
"--setgid=1000" | parsedArgs.gid |
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008, | parsedArgs.gids |
"--capabilities=" + capabilities + "," + capabilities | capabilitiesSpecified = true; permittedCapabilities = Long.decode(capStrings[0]); effectiveCapabilites = Long.decode(capString[1]); |
"--runtime-init" | parsedArgs.runtimeInit设为true |
"--nice-name=system_server" | parsedArgs.niceName |
"com.android.server.SystemServer" | parsedArgs.remainingArgs |
3.2.4.1Zygote.forkSystemServer()
Zygote.forkSystemServer()的代码如下:
【libcore/dalvik/src/main/java/dalvik/system/Zygote.java】
public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities)
preFork();
int pid = nativeForkSystemServer(uid, gid, gids, debugFlags, rlimits,
permittedCapabilities, effectiveCapabilities);
postFork();
return pid;
其中的nativeForkSystemServer()是个native成员函数,其对应的C++层函数为Dalvik_dalvik_system_Zygote_forkSystemServer()。
【dalvik/vm/native/dalvik_system_Zygote.cpp】
const DalvikNativeMethod dvm_dalvik_system_Zygote[] =
"nativeFork", "()I",
Dalvik_dalvik_system_Zygote_fork ,
"nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;)I",
Dalvik_dalvik_system_Zygote_forkAndSpecialize ,
"nativeForkSystemServer", "(II[II[[IJJ)I",
Dalvik_dalvik_system_Zygote_forkSystemServer ,
NULL, NULL, NULL ,
;
static void Dalvik_dalvik_system_Zygote_forkSystemServer(
const u4* args, JValue* pResult)
pid_t pid;
pid = forkAndSpecializeCommon(args, true);
if (pid > 0)
int status;
ALOGI("System server process %d has been created", pid);
gDvm.systemServerPid = pid;
if (waitpid(pid, &status, WNOHANG) == pid)
ALOGE("System server process %d has died. Restarting Zygote!", pid);
kill(getpid(), SIGKILL);
RETURN_INT(pid);
forkAndSpecializeCommon()内部其实会调用fork(),而后设置gid、uid等信息。
3.2.4.2SystemServer的handleSystemServerProgress()函数
接着,startSystemServer()会在新fork出的子进程中调用handleSystemServerProgress(),让这个新进程成为真正的系统进程(SystemServer进程)。
// 对新fork出的系统进程,执行handleSystemServerProcess()
if (pid == 0)
handleSystemServerProcess(parsedArgs);
注意,调用handleSystemServerProcess()时,程序是运行在新fork出的进程中的。handleSystemServerProcess()的代码如下:
【frameworks/base/core/java/com/android/internal/os/ZygoteInit.java】
private static void handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs)
throws ZygoteInit.MethodAndArgsCaller
closeServerSocket();
Libcore.os.umask(S_IRWXG | S_IRWXO);
if (parsedArgs.niceName != null)
Process.setArgV0(parsedArgs.niceName); // niceName就是”system_server”
if (parsedArgs.invokeWith != null)
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
null, parsedArgs.remainingArgs);
else
// 此时的remainingArgs就是”com.android.server.SystemServer”
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);
3.2.4.2.1closeServerSocket()
因为当前已经不是运行在zygote进程里了,所以zygote里的那个监听socket就应该关闭了。这就是closeServerSocket()的意义,其代码如下:
static void closeServerSocket()
try
if (sServerSocket != null)
FileDescriptor fd = sServerSocket.getFileDescriptor();
sServerSocket.close();
if (fd != null)
Libcore.os.close(fd);
catch (IOException ex)
Log.e(TAG, "Zygote: error closing sockets", ex);
catch (libcore.io.ErrnoException ex)
Log.e(TAG, "Zygote: error closing descriptor", ex);
sServerSocket = null;
在handleSystemServerProcess()函数里,parsedArgs.niceName就是“system_server”,而且因为parsedArgs.invokeWith没有指定,所以其值为null,于是程序会走到RuntimeInit.zygoteInit()。
3.2.4.2.2RuntimeInit.zygoteInit()
RuntimeInit.zygoteInit()的代码如下:
【frameworks/base/core/java/com/android/internal/os/RuntimeInit.java】
public static final void zygoteInit(int targetSdkVersion, String[] argv)
throws ZygoteInit.MethodAndArgsCaller
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
redirectLogStreams();
commonInit();
nativeZygoteInit();
applicationInit(targetSdkVersion, argv);
3.2.4.2.2.1.调用redirectLogStreams()
首先,在新fork出的系统进程里,需要重新定向系统输出流。
public static void redirectLogStreams()
System.out.close();
System.setOut(new AndroidPrintStream(Log.INFO, "System.out"));
System.err.close();
System.setErr(new AndroidPrintStream(Log.WARN, "System.err"));
3.2.4.2.2.2.调用commonInit()
private static final void commonInit()
. . . . . .
Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());
TimezoneGetter.setInstance(new TimezoneGetter()
. . . . . .
. . . . . .
String trace = SystemProperties.get("ro.kernel.android.tracing");
. . . . . .
initialized = true;
当前正处于系统进程的主线程中,可以调用Thread.setDefaultUncaughtExceptionHandler()来设置一个默认的异常处理器,处理程序中的未捕获异常。其他的初始化动作,我们暂不深究。
3.2.4.2.2.3.调用nativeZygoteInit()
接下来调用的nativeZygoteInit()是个JNI函数,在AndroidRuntime.cpp文件中可以看到:
【frameworks/base/core/jni/AndroidRuntime.cpp】
static JNINativeMethod gMethods[] =
"nativeFinishInit", "()V",
(void*) com_android_internal_os_RuntimeInit_nativeFinishInit ,
"nativeZygoteInit", "()V",
(void*) com_android_internal_os_RuntimeInit_nativeZygoteInit ,
"nativeSetExitWithoutCleanup", "(Z)V",
(void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup ,
;
nativeZygoteInit()对应的本地函数为com_android_internal_os_RuntimeInit_nativeZygoteInit()。
static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
gCurRuntime->onZygoteInit();
gCurRuntime是C++层的AndroidRuntime类的静态变量。在AndroidRuntime构造之时,
gCurRuntime = this。不过实际调用的onZygoteInit()应该是AndroidRuntime的子类AppRuntime的:
【frameworks/base/cmds/app_process/App_main.cpp】
class AppRuntime : public AndroidRuntime
. . . . . .
virtual void onZygoteInit()
// Re-enable tracing now that we're no longer in Zygote.
atrace_set_tracing_enabled(true);
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\\n");
proc->startThreadPool();
里面构造了进程的ProcessState全局对象,而且启动了线程池。
ProcessState对象是典型的单例模式,它的self()函数如下:
sp<ProcessState> ProcessState::self()
Mutex::Autolock _l(gProcessMutex);
if (gProcess != NULL)
return gProcess;
gProcess = new ProcessState;
return gProcess;
ProcessState对于Binder通信机制而言非常重要,现在system server进程的PrecessState算是初始化完毕了。
我们整理一下思路,画一张startSystemServer()的调用关系图:
接下来我们来讲上图中zygoteInit()调用的最后一行:applicationInit()。
3.2.4.2.2.4.调用applicationInit()
applicationInit()函数的代码如下:
【frameworks/base/core/java/com/android/internal/os/RuntimeInit.java】
private static void applicationInit(int targetSdkVersion, String[] argv)
throws ZygoteInit.MethodAndArgsCaller
nativeSetExitWithoutCleanup(true);
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
final Arguments args;
try
args = new Arguments(argv);
catch (IllegalArgumentException ex)
Slog.e(TAG, ex.getMessage());
return;
invokeStaticMain(args.startClass, args.startArgs);
其中的invokeStaticMain()一句最为关键,它承担向外抛出“特殊异常”的作用。我们先画一张startSystemServer()的调用关系图:
看到了吧,最后一步抛出了异常。这相当于一个“特殊的goto语句”!上面的cl = Class.forName(className)一句,其实加载的就是SystemServer类。这个类名是从前文的parsedArgs.remainingArgs得来的,其值就是“com.android.server.SystemServer”。此处抛出的异常,会被本进程的catch语句接住,在那里才会执行SystemServer类的main()函数。示意图如下:
如上图所示,新fork出的SystemServer子进程直接跳过了中间那句runSelectLoop(),径直跳转到caller.run()一步了。
当然,父进程Zygote在fork动作后,会退出startSystemServer()函数,并走到runSelectLoop(),从而进入一种循环监听状态,每当Activity Manager Service向它发出“启动新应用进程”的命令时,它又会fork一个子进程,并在子进程里抛出一个异常,这样子进程还是会跳转到catch一句。
我们可以把上面的示意图再丰富一下:
还有一点需要说明一下,fork出的SystemServer进程在跳转到catch语句后,会执行SystemServer类的main()函数,而其他情况下,fork出的应用进程在跳转的catch语句后,则会执行ActivityThread类的main()函数。这个ActivityThread对于应用程序而言非常重要,但因为和本篇主题关系不大,我们就不在这里展开讲了。
3.2.4.3 SystemServer的main()函数
前文我们已经看到了,startSystemServer()创建的新进程在执行完applicationInit()之后,会抛出一个异常,并由新fork出的SystemServer子进程的catch语句接住,继而执行SystemServer类的main()函数。
那么SystemServer的main()函数又在做什么事情呢?其调用关系图如下:
在Android4.4版本中,ServerThread已经不再继承于Thread了,它现在只是个辅助类,其命名还残留有旧代码的味道。在以前的Android版本中,ServerThread的确继承于Thread,而且在线程的run()成员函数里,做着类似addService、systemReady的工作。
因为本文主要是阐述zygote进程的,所以我们就不在这里继续细说system server进程啦,有兴趣的同学可以继续研究。我们还是回过头继续说zygote里的动作吧。
3.2.5监听zygote socket
3.2.5.1runSelectLoop()
ZygoteInit的main()函数在调用完startSystemServer()之后,会进一步走到runSelectLoop()。runSelectInit()的代码如下:
【frameworks/base/core/java/com/android/internal/os/ZygoteInit.java】
private static void runSelectLoop() throws MethodAndArgsCaller
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
FileDescriptor[] fdArray = new FileDescriptor[4];
fds.add(sServerSocket.getFileDescriptor());
peers.add(null);
int loopCount = GC_LOOP_COUNT;
while (true)
int index;
if (loopCount <= 0)
gc();
loopCount = GC_LOOP_COUNT;
else
loopCount--;
try
fdArray = fds.toArray(fdArray);
index = selectReadable(fdArray);
catch (IOException ex)
throw new RuntimeException("Error in select()", ex);
if (index < 0)
throw new RuntimeException("Error in select()");
else if (index == 0)
ZygoteConnection newPeer = acceptCommandPeer();
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
else
boolean done;
done = peers.get(index).runOnce();
if (done)
peers.remove(index);
fds.remove(index);
在一个while循环中,不断调用selectReadable()。该函数是个native函数,对应C++层的com_android_internal_os_ZygoteInit_selectReadable()。
【frameworks/base/core/jni/com_android_internal_os_ZygoteInit.cpp】
static jint com_android_internal_os_ZygoteInit_selectReadable (JNIEnv *env, jobject clazz,
jobjectArray fds)
. . . . . .
int err;
do
err = select (nfds, &fdset, NULL, NULL, NULL);
while (err < 0 && errno == EINTR);
. . . . . .
for (jsize i = 0; i < length; i++)
jobject fdObj = env->GetObjectArrayElement(fds, i);
. . . . . .
int fd = jniGetFDFromFileDescriptor(env, fdObj);
. . . . . .
if (FD_ISSET(fd, &fdset))
return (jint)i;
return -1;
可以看到,主要就是调用select()而已。在Linux的socket编程中,select()负责监视若干文件描述符的变化情况,我们常见的变化情况有:读、写、异常等等。在zygote中,
err = select (nfds, &fdset, NULL, NULL, NULL);一句的最后三个参数都为NULL,表示该select()操作只打算监视文件描述符的“读变化”,而且如果没有可读的文件,select()就维持阻塞状态。
在被监视的文件描述符数组(fds)中,第一个文件描述符对应着“zygote接收其他进程连接申请的那个socket(及sServerSocket)”,一旦它发生了变化,我们就尝试建立一个ZygoteConnection。
// (index == 0)的情况
ZygoteConnection newPeer = acceptCommandPeer();
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
看到了吗,新创建的ZygoteConnection会被再次写入文件描述符数组(fds)。
如果select动作发现文件描述符数组(fds)的其他文件描述符有东西可读了,说明有其他进程通过某个已建立好的ZygoteConnection发来了命令,此时我们需要调用runOnce()。
// (index > 0)的情况
boolean done;
done = peers.get(index).runOnce();
if (done)
peers.remove(index);
fds.remove(index);
建立ZygoteConnection的acceptCommandPeer()的代码如下:
private static ZygoteConnection acceptCommandPeer()
try
return new ZygoteConnection(sServerSocket.accept());
catch (IOException ex)
throw new RuntimeException(
"IOException during accept()", ex);
3.2.5.1.1ZygoteConnection的runOnce()
ZygoteConnection的runOnce()代码截选如下:
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;
. . . . . .
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors();
. . . . . .
int pid = -1;
FileDescriptor childPipeFd = null;
FileDescriptor serverPipeFd = null;
try
parsedArgs = new Arguments(args);
. . . . . .
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal,
parsedArgs.seInfo, parsedArgs.niceName);
. . . . . .
if (pid == 0)
// in child
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
return true;
else
// in parent...pid of < 0 means failure
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
. . . . . .
3.2.5.1.2readArgumentList()
runOnce()中从socket中读取参数数据的动作是由readArgumentList()完成的,该函数的代码如下:
private String[] readArgumentList()
throws IOException
int argc;
. . . . . .
String s = mSocketReader.readLine();
. . . . . .
argc = Integer.parseInt(s);
. . . . . .
String[] result = new String[argc];
for (int i = 0; i < argc; i++)
result[i] = mSocketReader.readLine();
if (result[i] == null)
// We got an unexpected EOF.
throw new IOException("truncated request");
return result;
可是是谁在向这个socket写入参数的呢?当然是AMS啦。
我们知道,当AMS需要启动一个新进程时,会调用类似下面的句子:
Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, null);
包括ActivityThread类名等重要信息的参数,最终就会通过socket传递给zygote。
3.2.5.1.3handleChildProc()
runOnce()在读完参数之后,会进一步调用到handleChildProc()。正如前文所说,该函数会间接抛出特殊的MethodAndArgsCaller异常,只不过此时抛出的异常携带的类名为ActivityThread。
private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
FileDescriptor pipeFd, PrintStream newStderr)
throws ZygoteInit.MethodAndArgsCaller
closeSocket();
ZygoteInit.closeServerSocket();
. . . . . .
if (parsedArgs.niceName != null)
Process.setArgV0(parsedArgs.niceName);
if (parsedArgs.runtimeInit)
if (parsedArgs.invokeWith != null)
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
pipeFd, parsedArgs.remainingArgs);
else
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs);
else
String className;
. . . . . .
className = parsedArgs.remainingArgs[0];
. . . . . .
String[] mainArgs = new String[parsedArgs.remainingArgs.length - 1];
System.arraycopy(parsedArgs.remainingArgs, 1,
mainArgs, 0, mainArgs.length);
if (parsedArgs.invokeWith != null)
WrapperInit.execStandalone(parsedArgs.invokeWith,
parsedArgs.classpath, className, mainArgs);
else
ClassLoader cloader;
if (parsedArgs.classpath != null)
cloader = new PathClassLoader(parsedArgs.classpath,
ClassLoader.getSystemClassLoader());
else
cloader = ClassLoader.getSystemClassLoader();
try
ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
catch (RuntimeException ex)
logAndPrintError(newStderr, "Error starting.", ex);
4小结
至此,zygote进程就阐述完毕了。作为一个最原始的“受精卵”,它必须在合适的时机进行必要的细胞分裂。分裂动作也没什么大的花样,不过就是fork()新进程而已。如果fork()出的新进程是system server,那么其最终执行的就是SystemServer类的main()函数,而如果fork()出的新进程是普通的用户进程的话,那么其最终执行的就是ActivityThread类的main()函数。有关ActivityThread的细节,我们有时间再深入探讨,这里就不细说了。
本篇文章和我的上一篇文章《Android4.4的init进程》可以算是姊妹篇啦。读完这两篇文章,我相信大家对Android的启动流程能有一些大面上的认识了。
以上是关于Android4.4的zygote进程(下)的主要内容,如果未能解决你的问题,请参考以下文章