android 应用程序进程启动过程

前言:

应用程序的启动过程就是此时AMS服务已经创建成功并拉起了Launcher界面,此时在Launcher界面点击某个应用,会先判断这个应用程序需要的应用程序进程是否存在,不存在就会请求Zygote进程将需要的应用程序进程启动(PS:全篇讲的是应用程序进程的启动过程,并不是应用程序的启动过程如根Activity的启动)

相关文章:
android 系统启动流程

一:应用程序进程的启动流程

应用程序的启动流程主要可以总结为两个部分
1.AMS发送启动应用程序进程的请求
2.Zygote进程接收请求并创建应用程序进程
接下来我们就从这两个方面进行解析

二:框架图

以下是整个应用程序进程的启动过程,抽出了比较重要的部分,不是完全,可当作参考


应用程序启动过程

三:AMS发送启动应用程序的请求

AMS调用startProcessLocked来想Zygote进程发送启动应用程序请求

  private final void startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
...省略
            if (!app.isolated) {
                if (ArrayUtils.isEmpty(permGids)) {
                    gids = new int[2];
                } else {
                    gids = new int[permGids.length + 2];
                    System.arraycopy(permGids, 0, gids, 2, permGids.length);
                }
                gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
                gids[1] = UserHandle.getUserGid(UserHandle.getUserId(uid));
            }

...省略
            if (entryPoint == null) entryPoint = "android.app.ActivityThread";
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                    app.processName);
            checkTime(startTime, "startProcess: asking zygote to start proc");

            Process.ProcessStartResult startResult = Process.start(entryPoint,
                    app.processName, uid, uid, gids, debugFlags, mountExternal,
                    app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                    app.info.dataDir, entryPointArgs);
...省略
        } catch (RuntimeException e) {
...省略
        }
    }
...省略
    }

在startProcessLocked方法中可以看出最后是调用了Process.start()方法,传入了app相关信息、uid等参数,其中有一个参数是entryPoint ,如果为空的话赋值"android.app.ActivityThread",对于这个类想必大家都很熟悉,我们先看Process.start又调用了startViaZygote

public static final ProcessStartResult start(final String processClass,
                              final String niceName,
                              int uid, int gid, int[] gids,
                              int debugFlags, int mountExternal,
                              int targetSdkVersion,
                              String seInfo,
                              String abi,
                              String instructionSet,
                              String appDataDir,
                              String[] zygoteArgs) {
    try {
        return startViaZygote(processClass, niceName, uid, gid, gids,
                debugFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, zygoteArgs);
    } catch (ZygoteStartFailedEx ex) {
...省略
    }
}

看下startViaZygote具体做了些什么

 private static ProcessStartResult startViaZygote(final String processClass,
                                  final String niceName,
                                  final int uid, final int gid,
                                  final int[] gids,
                                  int debugFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String abi,
                                  String instructionSet,
                                  String appDataDir,
                                  String[] extraArgs)
                                  throws ZygoteStartFailedEx {
        synchronized(Process.class) {
...省略
             //保存启动参数的List
            ArrayList<String> argsForZygote = new ArrayList<String>();
            argsForZygote.add("--runtime-args");
            argsForZygote.add("--setuid=" + uid);
            argsForZygote.add("--setgid=" + gid);
...省略
            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());
            }
         ...
            argsForZygote.add(processClass);
            if (extraArgs != null) {
                for (String arg : extraArgs) {
                    argsForZygote.add(arg);
                }
            }
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
        }
    }

可以看到这个方法创建了一个List,把uid、gid、processClass(如果为空取值:android.app.ActivityThread)等都放入了这个List对象里面,然后调用了zygoteSendArgsAndGetResult

 private static ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, ArrayList<String> args)
            throws ZygoteStartFailedEx {
        try {
//获取Zygote的BufferedWriter ,然后把参数写入
            final BufferedWriter writer = zygoteState.writer;
            final DataInputStream inputStream = zygoteState.inputStream;
            writer.write(Integer.toString(args.size()));
            writer.newLine();
            int sz = args.size();
            for (int i = 0; i < sz; i++) {
                String arg = args.get(i);
                if (arg.indexOf('\n') >= 0) {
                    throw new ZygoteStartFailedEx(
                            "embedded newlines not allowed");
                }
                writer.write(arg);
                writer.newLine();
            }
            writer.flush();
            ProcessStartResult result = new ProcessStartResult();
            result.pid = inputStream.readInt();
            if (result.pid < 0) {
                throw new ZygoteStartFailedEx("fork() failed");
            }
            result.usingWrapper = inputStream.readBoolean();
            return result;
        } catch (IOException ex) {
            zygoteState.close();
            throw new ZygoteStartFailedEx(ex);
        }
    }

可以看到zygoteSendArgsAndGetResult方法其实就是把刚才保存启动的应用程序进程的信息List写入ZygoteState里面,我们看下ZygoteState这个参数是怎么生成的

private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
    if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
        try {
//与Zygote进程创建的服务端Socket建立链接
            primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);
        } catch (IOException ioe) {
            throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
        }
    }
    if (primaryZygoteState.matches(abi)) {
        return primaryZygoteState;
    }
    // The primary zygote didn't match. Try the secondary.
    if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
        try {
        secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET);
        } catch (IOException ioe) {
            throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
        }
    }

    if (secondaryZygoteState.matches(abi)) {
        return secondaryZygoteState;
    }

    throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);

ZygoteState.connect(ZYGOTE_SOCKET)与Zygote进程创建的服务端Socket建立链接,如果连接name为“zygote”的Socket返回的primaryZygoteState与当前的abi不匹配,则会 ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET),这两个Socket区别就是:name为”zygote”的Socket是运行在64位Zygote进程中的,而name为“zygote_secondary”的Socket则运行在32位Zygote进程中。既然应用程序进程是通过Zygote进程fock产生的,当要连接Zygote中的Socket时,也需要保证位数的一致。

至此:AMS发送启动应用程序的请求告一段落

四:Zygote进程接收请求并创建应用程序进程

在Zygote进程初始化的时候,会调用ZygoteInit的main方法,main方法中调用了registerZygoteSocket创建了Zygote的Socket服务端

public static void main(String argv[]) {
...省略
        try {
...省略
            //注册Zygote用的Socket
            registerZygoteSocket(socketName);
...省略
           //预加载类和资源
           preload();//2
...省略
            if (startSystemServer) {
            //启动SystemServer进程
                startSystemServer(abiList, socketName);
            }
            Log.i(TAG, "Accepting command socket connections");
            //等待客户端请求
            runSelectLoop(abiList);
            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run();
        } catch (RuntimeException ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }

在runSelectLoop方法中来等待客户端的请求,就是上一步所说的操作。当请求来了runSelectLoop方法会调用runOnce()这个方法

 boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
        String args[];
        Arguments parsedArgs = null;
        FileDescriptor[] descriptors;
        try {
            args = readArgumentList();
            descriptors = mSocket.getAncillaryFileDescriptors();
        } catch (IOException ex) {
            Log.w(TAG, "IOException on command socket " + ex.getMessage());
            closeSocket();
            return true;
        }
...省略
        try {
            parsedArgs = new Arguments(args);
...省略
             //Zygote进程foke出请求的应用程序进程
            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                    parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
                    parsedArgs.appDataDir);
        } catch (ErrnoException ex) {
...省略
        }
       try {
            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);
            }
        } finally {
            IoUtils.closeQuietly(childPipeFd);
            IoUtils.closeQuietly(serverPipeFd);
        }
    }

可以看到forkAndSpecialize方法返回的pid如果是0的话会调用handleChildProc,如果不是0的话会调用handleParentProc
我们主要看下handleParentProc()方法

 private void handleChildProc(Arguments parsedArgs,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
            throws ZygoteInit.MethodAndArgsCaller {
...省略
            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
                    parsedArgs.remainingArgs, null /* classLoader */);
        }
    }

看下RuntimeInit.zygoteInit

 public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
        if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
        redirectLogStreams();
        commonInit();
        nativeZygoteInit();
        applicationInit(targetSdkVersion, argv, classLoader);
    }

nativeZygoteInit()方法是一个native方法,我们不做过多赘述,但是这个方法也很重要,阿简认为记住结论即可,nativeZygoteInit方法的作用是:前线程注册到Binder驱动程序中,创建的线程就加入了Binder线程池中,这样新创建的应用程序进程就支持Binder进程间通信了
我们接下来看下zygoteInit方法中调用的applicationInit方法做了些什么

  private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
...省略
        final Arguments args;
        try {
            args = new Arguments(argv);
        } catch (IllegalArgumentException ex) {
            Slog.e(TAG, ex.getMessage());       
            return;
        }
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        invokeStaticMain(args.startClass, args.startArgs, classLoader);
    }

可以看到调用了invokeStaticMain()方法

private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
        throws ZygoteInit.MethodAndArgsCaller {
    Class<?> cl;
    try {
        cl = Class.forName(className, true, classLoader);
    } catch (ClassNotFoundException ex) {
        throw new RuntimeException(
                "Missing class when invoking static main " + className,
                ex);
    }
    Method m;
    try {
        m = cl.getMethod("main", new Class[] { String[].class });
    } catch (NoSuchMethodException ex) {
        throw new RuntimeException(
                "Missing static main on " + className, ex);
    }
...省略
    throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}

这个方法中className就是我们传入的”android.app.ActivityThread“类,这里就是反射调用了ActivityThread的main方法

至此:Zygote进程接收请求并创建应用程序进程告一段落

参考资料:《android进阶解密》

END

女神镇楼
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容