继System进程的启动流程第二部分之后,我们来分析Launcher进程的启动,
Launcher进程的启动
。public class Process { ...... public static final int start(final String processClass, final String niceName, int uid, int gid, int[] gids, int debugFlags, String[] zygoteArgs) { if (supportsProcesses()) { try { return startViaZygote(processClass, niceName, uid, gid, gids, debugFlags, zygoteArgs); } catch (ZygoteStartFailedEx ex) { ...... } } else { ...... return 0; } } ......}调用startViaZygote函数进一步操作。
public class Process { ...... private static int startViaZygote(final String processClass, final String niceName, final int uid, final int gid, final int[] gids, int debugFlags, String[] extraArgs) throws ZygoteStartFailedEx { int pid; synchronized(Process.class) { ArrayList<string>argsForZygote = new ArrayList<string>(); // --runtime-init, --setuid=, --setgid=, // and --setgroups= must go first argsForZygote.add(--runtime-init); argsForZygote.add(--setuid= + uid); argsForZygote.add(--setgid= + gid); if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) { argsForZygote.add(--enable-safemode); } if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) { argsForZygote.add(--enable-debugger); } if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) { argsForZygote.add(--enable-checkjni); } if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) { argsForZygote.add(--enable-assert); } //TODO optionally enable debuger //argsForZygote.add(--enable-debugger); // --setgroups is a comma-separated list if (gids != null && gids.length > 0) { StringBuilder sb = new StringBuilder(); sb.append(--setgroups=); int sz = gids.length; for (int i = 0; i < sz; i++) { if (i != 0) { sb.append(','); } sb.append(gids[i]); } argsForZygote.add(sb.toString()); } if (niceName != null) { argsForZygote.add(--nice-name= + niceName); } argsForZygote.add(processClass); if (extraArgs != null) { for (String arg : extraArgs) { argsForZygote.add(arg); } } pid = zygoteSendArgsAndGetPid(argsForZygote); } } ......}</string></string>这个函数将创建进程的参数放到argsForZygote列表中去,如参数--runtime-init表示要为新创建的进程初始化运行时库,然后调用zygoteSendAndGetPid函数进一步操作。
public class Process { ...... private static int zygoteSendArgsAndGetPid(ArrayList<string>args) throws ZygoteStartFailedEx { int pid; openZygoteSocketIfNeeded(); try { /** * See com.android.internal.os.ZygoteInit.readArgumentList() * Presently the wire format to the zygote process is: * a) a count of arguments (argc, in essence) * b) a number of newline-separated argument strings equal to count * * After the zygote process reads these it will write the pid of * the child or -1 on failure. */ sZygoteWriter.write(Integer.toString(args.size()));//向Zygote进程发送通信数据 sZygoteWriter.newLine(); int sz = args.size(); for (int i = 0; i < sz; i++) { String arg = args.get(i); if (arg.indexOf('') >= 0) { throw new ZygoteStartFailedEx( embedded newlines not allowed); } sZygoteWriter.write(arg); sZygoteWriter.newLine(); } sZygoteWriter.flush(); // Should there be a timeout on this? pid = sZygoteInputStream.readInt(); if (pid < 0) { throw new ZygoteStartFailedEx(fork() failed); } } catch (IOException ex) { ...... } return pid; } ......}</string>这里的sZygoteWriter是一个Socket写入流,是由openZygoteSocketIfNeeded函数打开的:
public class Process { ...... /** * Tries to open socket to Zygote process if not already open. If * already open, does nothing. May block and retry. */ private static void openZygoteSocketIfNeeded() throws ZygoteStartFailedEx { int retryCount; if (sPreviousZygoteOpenFailed) { /* * If we've failed before, expect that we'll fail again and * don't pause for retries. */ retryCount = 0; } else { retryCount = 10; } /* * See bug #811181: Sometimes runtime can make it up before zygote. * Really, we'd like to do something better to avoid this condition, * but for now just wait a bit... */ for (int retry = 0 ; (sZygoteSocket == null) && (retry < (retryCount + 1)) ; retry++ ) { if (retry > 0) { try { Log.i(Zygote, Zygote not up yet, sleeping...); Thread.sleep(ZYGOTE_RETRY_MILLIS); } catch (InterruptedException ex) { // should never happen } } try { sZygoteSocket = new LocalSocket();//创建一个LocalSocket对象 sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET, LocalSocketAddress.Namespace.RESERVED));//和设备文件/dev/socket/zygote绑定,就相当于与Zygote进程中名称为zygote的Socket建立了连接 sZygoteInputStream = new DataInputStream(sZygoteSocket.getInputStream());//输入流,以便获得Zygote进程发送过来的通信数据 sZygoteWriter = new BufferedWriter( new OutputStreamWriter( sZygoteSocket.getOutputStream()),//输出流,以便可以向Zygote进程发送通信数据 256); Log.i(Zygote, Process: zygote socket opened); sPreviousZygoteOpenFailed = false; break; } catch (IOException ex) { ...... } } ...... } ......}
Process类有一个类型为LocalSocket的静态成员变量sZygoteSocket,它是Zygote进程中一个名称为zygote的Socket建立连接的。Zygote进程在启动时,会在内部创建一个名称为zygote”的Socket,这个Socket是与设备文件/dev/socket/zygote绑定在一起的。
这个Socket由frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中的ZygoteInit类在runSelectLoopMode函数侦听的。
当将数据通过Socket接口发送出去后,就会执行下面这个语句:
done = peers.get(index).runOnce();这里从peers.get(index)得到的是一个ZygoteConnection对象,表示一个Socket连接,因此,接下来就是调用ZygoteConnection.runOnce函数进一步处理了。
class ZygoteConnection { ...... boolean runOnce() throws ZygoteInit.MethodAndArgsCaller { String args[]; Arguments parsedArgs = null; FileDescriptor[] descriptors; try { args = readArgumentList(); descriptors = mSocket.getAncillaryFileDescriptors(); } catch (IOException ex) { ...... return true; } ...... /** the stderr of the most recent request, if avail */ PrintStream newStderr = null; if (descriptors != null && descriptors.length >= 3) { newStderr = new PrintStream( new FileOutputStream(descriptors[2])); } int pid; try { parsedArgs = new Arguments(args); applyUidSecurityPolicy(parsedArgs, peer); applyDebuggerSecurityPolicy(parsedArgs); applyRlimitSecurityPolicy(parsedArgs, peer); applyCapabilitiesSecurityPolicy(parsedArgs, peer); int[][] rlimits = null; if (parsedArgs.rlimits != null) { rlimits = parsedArgs.rlimits.toArray(intArray2d); } pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits); } catch (IllegalArgumentException ex) { ...... } catch (ZygoteSecurityException ex) { ...... } if (pid == 0) { // in child handleChildProc(parsedArgs, descriptors, newStderr); // should never happen return true; } else { /* pid != 0 */ // in parent...pid of < 0 means failure return handleParentProc(pid, descriptors, parsedArgs); } } ......}真正创建进程的地方就是在这里了:
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits);详情请参考Dalvik虚拟机进程和线程的创建过程分析。
applyRlimitSecurityPolicy用于安全检查,只有System进程和root进程才能请求Zygote进程,让它创建进程。
private static void applyRlimitSecurityPolicy( Arguments args, Credentials peer) throws ZygoteSecurityException { int peerUid = peer.getUid(); if (!(peerUid == 0 || peerUid == Process.SYSTEM_UID)) { // All peers with UID other than root or SYSTEM_UID if (args.rlimits != null) { throw new ZygoteSecurityException( This UID may not specify rlimits.); } } }还有一处安全问题需要注意,现在uid为0,但是在forkAndSpecializeCommon中fork后,又自降uid了,
电脑资料
《Launcher进程的启动》(https://www.unjs.com)。/* * Utility routine to fork zygote and specialize the child process. */static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer){ pid_t pid; uid_t uid = (uid_t) args[0]; gid_t gid = (gid_t) args[1]; ArrayObject* gids = (ArrayObject *)args[2]; u4 debugFlags = args[3]; ArrayObject *rlimits = (ArrayObject *)args[4]; int64_t permittedCapabilities, effectiveCapabilities; if (isSystemServer) { /* * Don't use GET_ARG_LONG here for now. gcc is generating code * that uses register d8 as a temporary, and that's coming out * scrambled in the child process. b/3138621 */ //permittedCapabilities = GET_ARG_LONG(args, 5); //effectiveCapabilities = GET_ARG_LONG(args, 7); permittedCapabilities = args[5] | (int64_t) args[6] << 32; effectiveCapabilities = args[7] | (int64_t) args[8] << 32; } else { permittedCapabilities = effectiveCapabilities = 0; } if (!gDvm.zygote) { ...... return -1; } ...... pid = fork(); if (pid == 0) { int err; ...... err = setgroupsIntarray(gids); ...... err = setrlimitsFromArray(rlimits); ...... err = setgid(gid); ...... err = setuid(uid); ...... err = setCapabilities(permittedCapabilities, effectiveCapabilities); ...... enableDebugFeatures(debugFlags); ...... gDvm.zygote = false; if (!dvmInitAfterZygote()) { ...... dvmAbort(); } } else if (pid > 0) { /* the parent process */ } return pid;}返回到runOnce,我们先来看父进程Zygote的执行路线。
private boolean handleParentProc(int pid, FileDescriptor[] descriptors, Arguments parsedArgs) { if(pid > 0) { // Try to move the new child into the peer's process group. try { ZygoteInit.setpgid(pid, ZygoteInit.getpgid(peer.getPid())); } catch (IOException ex) { // This exception is expected in the case where // the peer is not in our session // TODO get rid of this log message in the case where // getsid(0) != getsid(peer.getPid()) Log.i(TAG, Zygote: setpgid failed. This is + normal if peer is not in our session); } } try { if (descriptors != null) { for (FileDescriptor fd: descriptors) { ZygoteInit.closeDescriptor(fd); } } } catch (IOException ex) { Log.e(TAG, Error closing passed descriptors in + parent process, ex); } try { mSocketOutStream.writeInt(pid);//向System进程写回pid } catch (IOException ex) { Log.e(TAG, Error reading from command socket, ex); return true; } /* * If the peer wants to use the socket to wait on the * newly spawned process, then we're all done. */ if (parsedArgs.peerWait) { try { mSocket.close(); } catch (IOException ex) { Log.e(TAG, Zygote: error closing sockets, ex); } return true; } return false; }还记得,zygoteSendArgsAndGetPid中:
pid = sZygoteInputStream.readInt();System进程在等待获得Zygote进程发送过来的通信数据,此时可以返回了。
返回后System进程就可以调用Looper.loop()启动子线程的消息处理机制。如下所示:
class ServerThread extends Thread {@Override public void run() { ...... Looper.prepare(); ...... try { ...... Slog.i(TAG, Activity Manager); context = ActivityManagerService.main(factoryTest); ...... Slog.i(TAG, Package Manager); pm = PackageManagerService.main(context, factoryTest != SystemServer.FACTORY_TEST_OFF);//以后分析 ActivityManagerService.setSystemProcess(); ...... ((ActivityManagerService)ActivityManagerNative.getDefault()) .systemReady(new Runnable() { public void run() { } }); ...... } catch (RuntimeException e) { Slog.e(System, Failure starting core service, e); } ...... Looper.loop(); Slog.d(TAG, System ServerThread is exiting!); }}
接下来,我们说新创建的Launcher进程,也就是Zygote进程创建的子进程。
class ZygoteConnection { ...... private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, PrintStream newStderr) throws ZygoteInit.MethodAndArgsCaller { ...... if (parsedArgs.runtimeInit) { RuntimeInit.zygoteInit(parsedArgs.remainingArgs); } else { ...... } } ......}
public class RuntimeInit { ...... public static final void zygoteInit(String[] argv) throws ZygoteInit.MethodAndArgsCaller { // TODO: Doing this here works, but it seems kind of arbitrary. Find // a better place. The goal is to set it up for applications, but not // tools like am. System.setOut(new AndroidPrintStream(Log.INFO, System.out)); System.setErr(new AndroidPrintStream(Log.WARN, System.err)); commonInit(); zygoteInitNative(); int curArg = 0; for ( /* curArg */ ; curArg < argv.length; curArg++) { String arg = argv[curArg]; if (arg.equals(--)) { curArg++; break; } else if (!arg.startsWith(--)) { break; } else if (arg.startsWith(--nice-name=)) { String niceName = arg.substring(arg.indexOf('=') + 1); Process.setArgV0(niceName); } } if (curArg == argv.length) { Slog.e(TAG, Missing classname argument to RuntimeInit!); // let the process exit return; } // Remaining arguments are passed to the start class's static main String startClass = argv[curArg++]; String[] startArgs = new String[argv.length - curArg]; System.arraycopy(argv, curArg, startArgs, 0, startArgs.length); invokeStaticMain(startClass, startArgs); } ......}zygoteInitNative开启了子线程的Binder线程池,请参考System进程的启动流程第一部分。
invokeStaticMain也参考System进程的启动流程第一部分。开始执行android.app.ActivityThread类的main函数。
public final class ActivityThread { ...... public static final void main(String[] args) { SamplingProfilerIntegration.start(); Process.setArgV0(从这里我们可以看出,这个函数首先会在进程中创建一个ActivityThread对象:
ActivityThread thread = new ActivityThread();然后进入主线程消息循环中:Looper.prepareMainLooper();Looper.loop();下一节Home界面的启动中我们将分析,如下代码
ActivityThread thread = new ActivityThread(); thread.attach(false);