美文网首页
学记记录:应用程序启动过程(一)

学记记录:应用程序启动过程(一)

作者: nullpt | 来源:发表于2020-02-03 09:37 被阅读0次

    源代码版本:Android9.0

    最近在调研启动优化相关的知识,所以用几篇文章在这里做一下学习记录~~~

    应用程序进程的创建过程

    进程:每个App在启动前必须先创建一个进程,该进程是由Zygote fork出来的,进程具有独立的资源空间,用于承载App上运行的各种Activity/Service等组件。进程对于上层应用来说是完全透明的,大多数情况一个App就运行在一个进程中,除非在AndroidManifest.xml中配置Android:process属性,或通过native代码fork进程。

    每当ActivityManagerService需要创建一个新的应用程序进程来启动一个应用程序组件时,他就会调用ActivityManagerService类的成员函数startProcessLockedZygote进程发送一个创建应用程序进程的请求。

    具体过程分析如下:(解析添加到了注释当中)

    • 1.ActivityManagerService.startProcessLocked
    /frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
    

    首先可以确定的是,这个方法的重载和同名函数是非常多的,我确实没有搞懂哪个是我们需要看的~,通过《Android系统源代码情景分析》这本书再配合注释,大概猜到了我们可能要找的那一个(版本不同,方法参数和返回值已经变化了不少)。

     /**
         * @return {@code true} if process start is successful, false otherwise.
         */
        @GuardedBy("this")
        private final boolean startProcessLocked(ProcessRecord app, String hostingType,
                String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride) {
    
            ......
            //从这里开始
            try {
                try {
                    final int userId = UserHandle.getUserId(app.uid);
                    AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);
                } catch (RemoteException e) {
                    throw e.rethrowAsRuntimeException();
                }
                //首先获得要创建应用程序进程的用户id和用户组id
                int uid = app.uid;
                int[] gids = null;
                int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
                if (!app.isolated) {
                    int[] permGids = null;
                    
                    ......
    
                    /*
                     添加共享的应用程序和配置文件gid,以便应用程序可以共享一些资源(例如共享库)并访问用户范围的资源
                     */
                    if (ArrayUtils.isEmpty(permGids)) {
                        gids = new int[3];
                    } else {
                        gids = new int[permGids.length + 3];
                        System.arraycopy(permGids, 0, gids, 3, permGids.length);
                    }
                    gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
                    gids[1] = UserHandle.getCacheAppGid(UserHandle.getAppId(uid));
                    gids[2] = UserHandle.getUserGid(UserHandle.getUserId(uid));
    
                    // Replace any invalid GIDs
                    if (gids[0] == UserHandle.ERR_GID) gids[0] = gids[2];
                    if (gids[1] == UserHandle.ERR_GID) gids[1] = gids[2];
                }
               
                ......
    
                // Start the process.  It will either succeed and return a result containing
                // the PID of the new process, or else throw a RuntimeException.
    
                //这里指定了新进程的入口函数是androoid.app.ActivityThread类当中的main主函数
                final String entryPoint = "android.app.ActivityThread";
    
                //继续向这个函数当中走
                return startProcessLocked(hostingType, hostingNameStr, entryPoint, app, uid, gids,
                        runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith,
                        startTime);
            } catch (RuntimeException e) {
                ......
                return false;
            }
        }
    
        @GuardedBy("this")
        private boolean startProcessLocked(String hostingType, String hostingNameStr, String entryPoint,
                ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
                String seInfo, String requiredAbi, String instructionSet, String invokeWith,
                long startTime) {
            ......
            //该方法中,我们想追寻的线索和这个函数相关,继续深入
            final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint,
                                app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo,
                                requiredAbi, instructionSet, invokeWith, app.startTime);
    
            ......
        }
    
    private ProcessStartResult startProcess(String hostingType, String entryPoint,
                ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
                String seInfo, String requiredAbi, String instructionSet, String invokeWith,
                long startTime) {
            try {
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                        app.processName);
                checkTime(startTime, "startProcess: asking zygote to start proc");
                final ProcessStartResult startResult;
                //这里我们可以看到,对于非Web的服务开启,走的是else
                if (hostingType.equals("webview_service")) {
                    startResult = startWebView(entryPoint,
                            app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                            app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                            app.info.dataDir, null,
                            new String[] {PROC_START_SEQ_IDENT + app.startSeq});
                } else {
                    //到这里就和《Android系统源代码情景分析》这本书对上了。
                    //这个应用进程最终是由Process类的静态成员函数start来创建的。
                    //随着版本的不同,代码中添加了许多不同以往的参数配置,功能处理,但是主线是没有变化的。
                    startResult = Process.start(entryPoint,
                            app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                            app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                            app.info.dataDir, invokeWith,
                            new String[] {PROC_START_SEQ_IDENT + app.startSeq});
                }
                checkTime(startTime, "startProcess: returned from zygote!");
                return startResult;
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            }
        }
    
    • 2.Process.start
    frameworks/base/core/java/android/os/Process.java
    

    从这里开始,源代码的内容就和书上体现的不一样了,Process类中的startViaZygote方法已经不存在,同时进程的开启也是通过ZygoteProcess.start方法完成

    /**
         * State associated with the zygote process.
         * @hide
         */
        public static final ZygoteProcess zygoteProcess =
                new ZygoteProcess(ZYGOTE_SOCKET, SECONDARY_ZYGOTE_SOCKET);
    
       / **
         *~~~注释google翻译~~~
         *开启一个新的进程。
         *
         * <p>如果启用了进程,则会创建一个新进程,并且
         * <var> processClass </ var>的static main()函数在那里执行。
         *该函数返回后,该过程将继续运行。
         *
         * <p>如果未启用进程,则调用方的新线程
         *创建了进程,并在其中调用<var> processClass </ var>的main()。
         *
         * <p> niceName参数(如果不是一个空字符串)是一个自定义名称
         *提供给进程,而不是使用processClass。这使您能够
         *即使您使用的是相同的基础,也可以使流程易于识别
         * <var> processClass </ var>以启动它们。
         *
         *当invokeWith不为null时,该过程将作为一个全新的应用程序启动
         *不是合子叉。请注意,这仅适用于uid 0或
         * runtimeFlags包含DEBUG_ENABLE_DEBUGGER。
         *
         * @param processClass用作流程主条目的类
         *点。
         * @param niceName用于该过程的更易读的名称。
         * @param uid进程将在其下运行的用户ID。
         * @param gid将在其下运行进程的组ID。
         * @param gids与该进程关联的其他组ID。
         * @param runtimeFlags运行时的其他标志。
         * @param targetSdkVersion应用程序的目标SDK版本。
         * @param seInfo可为新进程提供空的SELinux信息。
         * @param abi非空,此应用程序应以ABI开头。
         * @paramstructionSet为null,确定要使用的指令集。
         * @param appDataDir空-确定应用程序的数据目录。
         * @param invokeWith null-确定要调用的命令。
         * @param zygoteArgs提供给zygote进程的其他参数。
         *
         * @return一个对象,描述尝试启动该过程的结果。
         * @致命启动失败时抛出RuntimeException
         *
         * {@hide}
         * /
        public static final ProcessStartResult start(final String processClass,
                                      final String niceName,
                                      int uid, int gid, int[] gids,
                                      int runtimeFlags, int mountExternal,
                                      int targetSdkVersion,
                                      String seInfo,
                                      String abi,
                                      String instructionSet,
                                      String appDataDir,
                                      String invokeWith,
                                      String[] zygoteArgs) {
            //这里调用了ZygoteProcess对象的start方法,继续追踪
            return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                        runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                        abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
        }
    
    public final Process.ProcessStartResult start(final String processClass,
                                                      final String niceName,
                                                      int uid, int gid, int[] gids,
                                                      int runtimeFlags, int mountExternal,
                                                      int targetSdkVersion,
                                                      String seInfo,
                                                      String abi,
                                                      String instructionSet,
                                                      String appDataDir,
                                                      String invokeWith,
                                                      String[] zygoteArgs) {
            try {
                 //看到这里是???Android9.0源代码是把Process中的start函数迁到了ZygoteProcess类中
                //继续追踪startViaZygote方法
                return startViaZygote(processClass, niceName, uid, gid, gids,
                        runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                        abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */,
                        zygoteArgs);
            } catch (ZygoteStartFailedEx ex) {
                Log.e(LOG_TAG,
                        "Starting VM process through Zygote failed");
                throw new RuntimeException(
                        "Starting VM process through Zygote failed", ex);
            }
        }
    
    • 3.ZygoteProcess.start
    frameworks/base/core/java/android/os/ZygoteProcess.java
    
    / **
         *通过zygote机制启动新进程。
         *
         * @param processClass要运行其静态main()的类名
         * @param niceName'nice'进程名称出现在ps中
         * @param uid一个POSIX uid,新进程应将setuid()设置为
         * @param gid一个新进程shuold setgid()要的POSIX gid
         * @param引导null-ok;补充组ID的列表,
         *新进程应将setgroup()设置为。
         * @param runtimeFlags运行时的其他标志。
         * @param targetSdkVersion应用程序的目标SDK版本。
         * @param seInfo可为新进程提供空的SELinux信息。
         * @param abi该过程应使用的ABI。
         * @paramstructionSet为null,确定要使用的指令集。
         * @param appDataDir空-确定应用程序的数据目录。
         * @param startChildZygote启动一个子合子。这将创建一个新的合子过程
         *具有从此合子过程克隆的状态的*。
         * @param extraArgs提供给合子过程的其他参数。
         * @return一个对象,描述尝试启动该过程的结果。
         * @如果流程由于任何原因启动失败,则抛出ZygoteStartFailedEx
         * /
        private Process.ProcessStartResult startViaZygote(final String processClass,
                                                          final String niceName,
                                                          final int uid, final int gid,
                                                          final int[] gids,
                                                          int runtimeFlags, int mountExternal,
                                                          int targetSdkVersion,
                                                          String seInfo,
                                                          String abi,
                                                          String instructionSet,
                                                          String appDataDir,
                                                          String invokeWith,
                                                          boolean startChildZygote,
                                                          String[] extraArgs)
                                                          throws ZygoteStartFailedEx {
            //这里首先将要创建的应用程序进程的启动参数保存在一个字符串列表中
            ArrayList<String> argsForZygote = new ArrayList<String>();
    
            // --runtime-args, --setuid=, --setgid=,
            // and --setgroups= must go first
            //在历史版本中,这里有一个“--runtime-init”,表示在创建应用程序中初始化运行时库,以及启动一个binder线程池。
            //现在换成了“--runtime-args”,暂时不清楚是否保留了原有的意思,后续相关代码处解释~~~
            argsForZygote.add("--runtime-args");
            argsForZygote.add("--setuid=" + uid);
            argsForZygote.add("--setgid=" + gid);
            argsForZygote.add("--runtime-flags=" + runtimeFlags);
            if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
                argsForZygote.add("--mount-external-default");
            } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
                argsForZygote.add("--mount-external-read");
            } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
                argsForZygote.add("--mount-external-write");
            }
            argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
    
            // --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());
            }
    
            ......
    
            synchronized(mLock) {
                //这里去请求Zygote进程创建应用程序,同时开启和Zygote通信的socket
                return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
            }
        }
    
    • 4.ZygoteProcess.zygoteSendArgsAndGetResult
    frameworks/base/core/java/android/os/ZygoteProcess.java
    

    在历史版本中,这个方法中会开启ZygoteSocket用于跨进程通信,现在这一步被提前,当调用到这个方法时本地Socket已经开启。

        @GuardedBy("mLock")
        private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
                ZygoteState zygoteState, ArrayList<String> args)
                throws ZygoteStartFailedEx {
            try {
                // Throw early if any of the arguments are malformed. This means we can
                // avoid writing a partial response to the zygote.
                int sz = args.size();
                for (int i = 0; i < sz; i++) {
                    if (args.get(i).indexOf('\n') >= 0) {
                        throw new ZygoteStartFailedEx("embedded newlines not allowed");
                    }
                }
    
                /**
                 * See com.android.internal.os.SystemZygoteInit.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, followed by boolean to
                 * indicate whether a wrapper process was used.
                 */
                final BufferedWriter writer = zygoteState.writer;
                final DataInputStream inputStream = zygoteState.inputStream;
    
                //这里将参数写入到LocalSocket中,以便于可以将他们传到Zygote进程。
                //Zygote进程接受到这些数据之后,就会创建一个新的应用程序进程。
                //并且将这个新创建的应用程序进程的PID返回给Activity的管理服务ActivityManagerService;
                writer.write(Integer.toString(args.size()));
                writer.newLine();
    
                for (int i = 0; i < sz; i++) {
                    String arg = args.get(i);
                    writer.write(arg);
                    writer.newLine();
                }
    
                writer.flush();
    
                // Should there be a timeout on this?
                Process.ProcessStartResult result = new Process.ProcessStartResult();
    
                // Always read the entire result from the input stream to avoid leaving
                // bytes in the stream for future process starts to accidentally stumble
                // upon.
                result.pid = inputStream.readInt();
                result.usingWrapper = inputStream.readBoolean();
    
                if (result.pid < 0) {
                    throw new ZygoteStartFailedEx("fork() failed");
                }
                return result;
            } catch (IOException ex) {
                zygoteState.close();
                throw new ZygoteStartFailedEx(ex);
            }
        }
    

    调研发现,Zygote进程启动完成之后,会在一个名称为Zygote”的Socket上等待Activity管理服务ActivityManagerService向他发送新的创建应用程序进程的请求。因此这一步完成之后,Zygote进程就会在ZygoteInit类的静态成员函数runSelectLoopMode中接收到一个创建一个新的应用程序进程的请求。
    然而事情并没有这么简单,9.0版本ZygoteInit类中就没有runSelectLoopMode函数,于是只能从头分析,我们来看看ZygoteInitmain主函数干了什么。

    • 5.ZygoteInit.main
    frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
    
       public static void main(String argv[]) {
            ZygoteServer zygoteServer = new ZygoteServer();
    
            //标记Zygote开始。 这确保线程创建将抛出一个错误。
            ZygoteHooks.startZygoteNoThreadCreation();
    
            // Zygote goes into its own process group.
            try {
                Os.setpgid(0, 0);
            } catch (ErrnoException ex) {
                throw new RuntimeException("Failed to setpgid(0,0)", ex);
            }
    
            final Runnable caller;
            try {
                // Report Zygote start time to tron unless it is a runtime restart
                if (!"1".equals(SystemProperties.get("sys.boot_completed"))) {
                    MetricsLogger.histogram(null, "boot_zygote_init",
                            (int) SystemClock.elapsedRealtime());
                }
    
                String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
                TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
                        Trace.TRACE_TAG_DALVIK);
                bootTimingsTraceLog.traceBegin("ZygoteInit");
                RuntimeInit.enableDdms();
    
                boolean startSystemServer = false;
                String socketName = "zygote";
                String abiList = null;
                boolean enableLazyPreload = false;
                for (int i = 1; i < argv.length; i++) {
                    if ("start-system-server".equals(argv[i])) {
                        startSystemServer = true;
                    } else if ("--enable-lazy-preload".equals(argv[i])) {
                        enableLazyPreload = true;
                    } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                        abiList = argv[i].substring(ABI_LIST_ARG.length());
                    } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                        socketName = argv[i].substring(SOCKET_NAME_ARG.length());
                    } else {
                        throw new RuntimeException("Unknown command line argument: " + argv[i]);
                    }
                }
    
                if (abiList == null) {
                    throw new RuntimeException("No ABI list supplied.");
                }
    
                zygoteServer.registerServerSocketFromEnv(socketName);
                // In some configurations, we avoid preloading resources and classes eagerly.
                // In such cases, we will preload things prior to our first fork.
                if (!enableLazyPreload) {
                    bootTimingsTraceLog.traceBegin("ZygotePreload");
                    EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                        SystemClock.uptimeMillis());
                    preload(bootTimingsTraceLog);
                    EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                        SystemClock.uptimeMillis());
                    bootTimingsTraceLog.traceEnd(); // ZygotePreload
                } else {
                    Zygote.resetNicePriority();
                }
    
                // Do an initial gc to clean up after startup
                bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
                gcAndFinalize();
                bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC
    
                bootTimingsTraceLog.traceEnd(); // ZygoteInit
                // Disable tracing so that forked processes do not inherit stale tracing tags from
                // Zygote.
                Trace.setTracingEnabled(false, 0);
    
                Zygote.nativeSecurityInit();
    
                // Zygote process unmounts root storage spaces.
                Zygote.nativeUnmountStorageOnInit();
    
                ZygoteHooks.stopZygoteNoThreadCreation();
    
                if (startSystemServer) {
                    Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
    
                    // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
                    // child (system_server) process.
                    if (r != null) {
                        r.run();
                        return;
                    }
                }
    
                Log.i(TAG, "Accepting command socket connections");
    
                // The select loop returns early in the child process after a fork and
                // loops forever in the zygote.
                //这里看起来就是开启loop循环的地方了,深入函数
                caller = zygoteServer.runSelectLoop(abiList);
            } catch (Throwable ex) {
                Log.e(TAG, "System zygote died with exception", ex);
                throw ex;
            } finally {
                zygoteServer.closeServerSocket();
            }
    
            // We're in the child process and have exited the select loop. Proceed to execute the
            // command.
            if (caller != null) {
                caller.run();
            }
        }
    

    果然,runSelectLoopMode方法被转移到了ZygoteServer当中。

    frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
    
        Runnable runSelectLoop(String abiList) {
            ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
            ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
    
            fds.add(mServerSocket.getFileDescriptor());
            peers.add(null);
    
            while (true) {
                StructPollfd[] pollFds = new StructPollfd[fds.size()];
                for (int i = 0; i < pollFds.length; ++i) {
                    pollFds[i] = new StructPollfd();
                    pollFds[i].fd = fds.get(i);
                    pollFds[i].events = (short) POLLIN;
                }
                try {
                    Os.poll(pollFds, -1);
                } catch (ErrnoException ex) {
                    throw new RuntimeException("poll failed", ex);
                }
                for (int i = pollFds.length - 1; i >= 0; --i) {
                    if ((pollFds[i].revents & POLLIN) == 0) {
                        continue;
                    }
    
                    if (i == 0) {
                        ZygoteConnection newPeer = acceptCommandPeer(abiList);
                        peers.add(newPeer);
                        fds.add(newPeer.getFileDesciptor());
                    } else {
                        try {
                            ZygoteConnection connection = peers.get(i);
                            final Runnable command = connection.processOneCommand(this);
    
                            if (mIsForkChild) {
                                //当前处于子进程里。 我们应该总是有一个命令可以在此运行
                                 //如果processOneCommand尚未调用“ exec”,则执行阶段。
                                if (command == null) {
                                    throw new IllegalStateException("command == null");
                                }
    
                                return command;
                            } else {
                                //当前处于服务中-永远不要运行任何命令。
                                if (command != null) {
                                    throw new IllegalStateException("command != null");
                                }
    
                                //我们不知道套接字的远端是关闭的还是运行
                                 //直到我们尝试从processOneCommand读取该消息为止。 这显示为我们的常规处理循环中的常规POLLIN事件。
                                if (connection.isClosedByPeer()) {
                                    connection.closeSocket();
                                    peers.remove(i);
                                    fds.remove(i);
                                }
                            }
                        } catch (Exception e) {
                            if (!mIsForkChild) {
                                //当前在服务中,因此这里发生的任何异常都是
                                 //在处理命令或从
                                 //控制套接字。 对此类异常大声喧that,以便
                                 //我们确切知道失败和失败原因。
    
                                Slog.e(TAG, "Exception executing zygote command: ", e);
    
                                //确保套接字已关闭,以便另一端立即知道
                                 //出现了问题,并且不会超时等待
                                 //回应。
                                ZygoteConnection conn = peers.remove(i);
                                conn.closeSocket();
    
                                fds.remove(i);
                            } else {
                                //当前在子进程里,所以这里捕获到的任何异常都已发生
                                 //在执行ActivityThread.main(或任何其他main()之前)
                                 // 方法)。 记录异常的详细信息,并简化该过程。
                                Log.e(TAG, "Caught post-fork exception in child process.", e);
                                throw e;
                            }
                        } finally {
                            //如Zygote进程是子进程,则重置子标志
                             //Zygote。 在Runnable之后,此循环将不使用该标志
                             //返回。
                            mIsForkChild = false;
                        }
                    }
                }
            }
        }
    

    这里,在接收到创建新进程的请求之后,会调用到ZygoteConnection类的成员函数processOneCommand,接下来继续分析,以便于了解他究竟是如何创建一个应用程序进程的。

    • 6.ZygoteConnection.processOneCommand
    frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
    
    / **
          *从命令套接字读取一个启动命令。 如果成功,子进程将被分叉,
          *在子级中返回调用子级main方法(或等效方法)的{@code Runnable}
          *过程。 {@code null}始终在父进程(Zygote)中返回。
          *
          *如果客户端关闭套接字,则会设置一个{@code EOF}条件,调用者可以测试该条件
          *用于通过调用{@code ZygoteConnection.isClosedByPeer}。
          * /
        Runnable processOneCommand(ZygoteServer zygoteServer) {
            String args[];
            Arguments parsedArgs = null;
            FileDescriptor[] descriptors;
    
            try {
                //这里获取即将要创建的应用程序进程的启动参数
                args = readArgumentList();
                descriptors = mSocket.getAncillaryFileDescriptors();
            } catch (IOException ex) {
                throw new IllegalStateException("IOException on command socket", ex);
            }
    
            // readArgumentList returns null 仅在达到EOF且无可用数据时
            // 这仅在远程套接字断开连接时才会发生。
            if (args == null) {
                isEof = true;
                return null;
            }
    
            int pid = -1;
            FileDescriptor childPipeFd = null;
            FileDescriptor serverPipeFd = null;
    
            //这里讲读出来的进程启动参数封装到Arguments以便于进一步解析
            parsedArgs = new Arguments(args);
    
            
    
           / **
              *为了避免将描述符泄漏给Zygote子级,
              *本机代码必须关闭两个Zygote套接字描述符
              *在子进程中从Zygote-root切换到
              *正在启动的应用程序的UID和特权。
              *
              *为了避免“坏文件描述符”错误时
              *关闭两个LocalSocket对象,即Posix文件
              *描述符通过关闭的dup2()调用释放
              *套接字,并将打开的描述符替换为/ dev / null。
              * /
    
            int [] fdsToClose = { -1, -1 };
    
            FileDescriptor fd = mSocket.getFileDescriptor();
    
            if (fd != null) {
                fdsToClose[0] = fd.getInt$();
            }
    
            //获取Zygote服务Socket的 
            fd = zygoteServer.getServerSocketFileDescriptor();
    
            if (fd != null) {
                fdsToClose[1] = fd.getInt$();
            }
    
            fd = null;
    
            //这里是关键点,最终调用到Zygote的静态成员函数去创建一个应用程序进程。
            //同时将应用程序进程的进程参数传进去
            //这个函数最终是通过函数fock在当前进程中创建的一个子进程,因此,当他返回值等于0时,
            //就表示是在新创建的子进程中执行的,这是会走到下面的pid==0的判断里面
            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                    parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                    parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
                    parsedArgs.instructionSet, parsedArgs.appDataDir);
    
            try {
                if (pid == 0) {
                    // in child
                    zygoteServer.setForkChild();
    
                    zygoteServer.closeServerSocket();
                    IoUtils.closeQuietly(serverPipeFd);
                    serverPipeFd = null;
    
                    //这里是运行在子进程当中,通过该方法来启动这个进程
                    return handleChildProc(parsedArgs, descriptors, childPipeFd,
                            parsedArgs.startChildZygote);
                } else {
                    // In the parent. A pid < 0 indicates a failure and will be handled in
                    // handleParentProc.
                    IoUtils.closeQuietly(childPipeFd);
                    childPipeFd = null;
                    handleParentProc(pid, descriptors, serverPipeFd);
                    return null;
                }
            } finally {
                IoUtils.closeQuietly(childPipeFd);
                IoUtils.closeQuietly(serverPipeFd);
            }
        }
    
    • 7.ZygoteConnection.handleChildProc
    frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
    
       private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
                FileDescriptor pipeFd, boolean isZygote) {
            ......
            if (parsedArgs.invokeWith != null) {
                ......
            } else {
                //这里通过判断是初始化Zygote子进程还是Zygote进程
                //对于handleChildProc来说当然是子进程
                //给isZygote赋值的是parsedArgs.startChildZygote
                //    else if (arg.equals("--start-child-zygote")) {
                //         startChildZygote = true;
                //    }
                if (!isZygote) {
                    return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
                            null /* classLoader */);
                } else {
                    //这里会为新创建的子进程初始化运行时库,以及启动一个Binder线程池
                    return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
                            parsedArgs.remainingArgs, null /* classLoader */);
                }
            }
        }
    
    • 8.ZygoteInit.childZygoteInit
    frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
    

    这里只做了一个中转,最终调用到的是RuntimeInit的静态方法findStaticMain

    static final Runnable childZygoteInit(
                int targetSdkVersion, String[] argv, ClassLoader classLoader) {
            RuntimeInit.Arguments args = new RuntimeInit.Arguments(argv);
            return RuntimeInit.findStaticMain(args.startClass, args.startArgs, classLoader);
        }
    
    //RuntimeInit
    protected static Runnable findStaticMain(String className, String[] argv,
                ClassLoader classLoader) {
            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);
            } catch (SecurityException ex) {
                throw new RuntimeException(
                        "Problem getting static main on " + className, ex);
            }
    
            int modifiers = m.getModifiers();
            if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
                throw new RuntimeException(
                        "Main method is not public and static on " + className);
            }
    
            /*
             * This throw gets caught in ZygoteInit.main(), which responds
             * by invoking the exception's run() method. This arrangement
             * clears up all the stack frames that were required in setting
             * up the process.
             */
            return new MethodAndArgsCaller(m, argv);
        }
    

    很明显,这个方法就是通过className去反射目标主函数,不知道记不记得第一步当中的final String entryPoint = "android.app.ActivityThread";。这个参数一直跟了一路没有用到,终于在这里用到了~~~
    因此,这一步其实是调用到了ActivityThread的main函数入口。简单来说,至此,一个新的应用程序进程就启动完成,但是实际上这里还有一些骚操作~~,有兴趣自己去看一下代码喽~~
    当然,伴随着应用进程启动的还有Binder线程池和创建消息循环,那些就是后话了,有兴趣的可以先自行去了解~~~

    相关文章

      网友评论

          本文标题:学记记录:应用程序启动过程(一)

          本文链接:https://www.haomeiwen.com/subject/ujbgthtx.html