美文网首页
应用程序进程启动过程学习记录

应用程序进程启动过程学习记录

作者: 打工崽 | 来源:发表于2021-06-07 03:37 被阅读0次

    应用程序进程创建过程分为两个部分,分别为AMS发送启动应用程序进程请求,还有Zygote接收请求并创建应用程序进程

    1. AMS发送启动应用程序进程请求

    AMS想要启动应用程序进程,就需要向Zygote进程发送创建应用程序进程的请求,AMS会通过调用startProcessLocked方法向Zygote进程发送请求,如下

    AMS的startProcessLocked方法

    private final boolean startProcessLocked(ProcessRecord app, String hostingType,
                String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride) {
    ···
                int uid = app.uid;
                int[] gids = null;
                int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
                if (!app.isolated) {
                    int[] permGids = null;
                    try {
                        checkTime(startTime, "startProcess: getting gids from package manager");
                        final IPackageManager pm = AppGlobals.getPackageManager();
                        permGids = pm.getPackageGids(app.info.packageName,
                                MATCH_DEBUG_TRIAGED_MISSING, app.userId);
                        StorageManagerInternal storageManagerInternal = LocalServices.getService(
                                StorageManagerInternal.class);
                        mountExternal = storageManagerInternal.getExternalStorageMountMode(uid,
                                app.info.packageName);
                    } catch (RemoteException e) {
                        throw e.rethrowAsRuntimeException();
                    }
    
                    /*
                     * Add shared application and profile GIDs so applications can share some
                     * resources like shared libraries and access user-wide resources
                     */
                    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));
    ···
                final String seInfo = app.info.seInfo
                        + (TextUtils.isEmpty(app.info.seInfoUser) ? "" : app.info.seInfoUser);
                // Start the process.  It will either succeed and return a result containing
                // the PID of the new process, or else throw a RuntimeException.
                final String entryPoint = "android.app.ActivityThread";
    
                return startProcessLocked(hostingType, hostingNameStr, entryPoint, app, uid, gids,
                        runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith,
                        startTime);
            } catch (RuntimeException e) {
                Slog.e(TAG, "Failure starting process " + app.processName, e);
    
                forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false,
                        false, true, false, false, UserHandle.getUserId(app.userId), "start failure");
                return false;
            }
        }
    

    开头uid处得到创建应用程序进程的用户ID

    中间注释下的if处对用户组ID进行创建和赋值

    末尾会有一个entryPoint的String常量被赋值为了ActivityThread,即应用程序进程主线程的类名

    最后return处返回了另一个startProcessLocked重载方法,如下

    AMS的startProcessLocked方法

    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);
                        synchronized (ActivityManagerService.this) {
                            handleProcessStartedLocked(app, startResult, startSeq);
                        }
                    } catch (RuntimeException e) {
                        synchronized (ActivityManagerService.this) {
                            Slog.e(TAG, "Failure starting process " + app.processName, e);
                            mPendingStarts.remove(startSeq);
                            app.pendingStart = false;
                            forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid),
                                    false, false, true, false, false,
                                    UserHandle.getUserId(app.userId), "start failure");
                        }
                    }
                });
                return true;
            } else {
                try {
                    final ProcessStartResult startResult = startProcess(hostingType, entryPoint, app,
                            uid, gids, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet,
                            invokeWith, startTime);
                    handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,
                            startSeq, false);
                } catch (RuntimeException e) {
                    Slog.e(TAG, "Failure starting process " + app.processName, e);
                    app.pendingStart = false;
                    forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid),
                            false, false, true, false, false,
                            UserHandle.getUserId(app.userId), "start failure");
                }
                return app.pid > 0;
            }
        }
    

    两个final处都调用了startProcess方法,顾名思义创建进程,如下

    AMS的startProcess方法

    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;
                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 {
                    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);
            }
        }
    

    如果hostingType不是webview_service,那么就调用Process的start方法,将之前得到的应用程序进程用户ID和用户组ID传进去,entryPoint上面我们也解释过了,我们看看这个start方法

    Process的start方法

    public static ProcessStartResult start(@NonNull final String processClass,
                                               @Nullable final String niceName,
                                               int uid, int gid, @Nullable int[] gids,
                                               int runtimeFlags,
                                               int mountExternal,
                                               int targetSdkVersion,
                                               @Nullable String seInfo,
                                               @NonNull String abi,
                                               @Nullable String instructionSet,
                                               @Nullable String appDataDir,
                                               @Nullable String invokeWith,
                                               @Nullable String packageName,
                                               int zygotePolicyFlags,
                                               boolean isTopApp,
                                               @Nullable long[] disabledCompatChanges,
                                               @Nullable Map<String, Pair<String, Long>>
                                                       pkgDataInfoMap,
                                               @Nullable Map<String, Pair<String, Long>>
                                                       whitelistedDataInfoMap,
                                               boolean bindMountAppsData,
                                               boolean bindMountAppStorageDirs,
                                               @Nullable String[] zygoteArgs) {
            return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
                        runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                        abi, instructionSet, appDataDir, invokeWith, packageName,
                        zygotePolicyFlags, isTopApp, disabledCompatChanges,
                        pkgDataInfoMap, whitelistedDataInfoMap, bindMountAppsData,
                        bindMountAppStorageDirs, zygoteArgs);
        }
    

    很明显这里返回的是ZygoteProcess的start方法,其中ZygoteProcess用于保持和Zygote进程的通信状态,start方法如下

    ZygoteProcess的start方法

    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 {
                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);
            }
        }
    

    在try中返回了startViaZygote方法

    ZygoteProcess的startViaZygote方法

    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
            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");
            }
     ···
            synchronized(mLock) {
                return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
            }
        }
    

    创建了argsForZygote集合,是一个字符串列表,并将启动应用程序的进程的启动参数保存其中,在同步块中调用zygoteSendAndGetResult方法,这个方法有两个参数

    a. 第一个参数调用openZygoteSocketIfNeeded方法

    b. 第二个参数是保存应用进程的启动参数的argsForZygote

    zygoteSendArgsAndGetResult方法如下所示

    ZygoteProcess的zygoteSendArgsAndGetResult方法

    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;
    
                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);
            }
        }
    

    这个方法的主要作用就是将传入的应用进程的启动参数argsForZygote写入ZygoteState中

    ZygoteState是ZygoteProcess的静态内部类,用于表示和Zygote进程通信的状态

    结合上文,我们知道ZygoteState其实是由openZygoteSocketIfNeeded方法返回的,那么我们看看这个方法

    ZygoteProcess的openZygoteSocketIfNeeded方法

    private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
            Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
    
            if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
                try {
                    primaryZygoteState = ZygoteState.connect(mSocket);
                } catch (IOException ioe) {
                    throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
                }
                maybeSetApiBlacklistExemptions(primaryZygoteState, false);
                maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
            }
            if (primaryZygoteState.matches(abi)) {
                return primaryZygoteState;
            }
    
            // The primary zygote didn't match. Try the secondary.
            if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
                try {
                    secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
                } catch (IOException ioe) {
                    throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
                }
                maybeSetApiBlacklistExemptions(secondaryZygoteState, false);
                maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
            }
    
            if (secondaryZygoteState.matches(abi)) {
                return secondaryZygoteState;
            }
    
            throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
        }
    

    在系统启动流程一文中我们学习过Zygote的main方法会创建name为zygote的Server端Socket,第一个try处的connect方法与名称为ZYGOTE_SOCKET的Socket端建立连接,其值就为zygote,也就是说与Zygote进程建立连接,并返回一个ZygoteState类型的primaryZygoteState对象

    第2个if处如果primaryZygoteState与启动应用程序进程所需的ABI不匹配,则会在第2个try处连接name为zygote_secondary的Socket

    我们在系统启动流程一文中也学习过Zygote的启动脚本有4种,name为zygote的为主模式,name为zygote_secondary的为辅模式,上一段的简单意思就是如果连接Zygote主模式返回的ZygoteState与启动应用进程所需的ABI不匹配,那么就连接辅模式,如果辅模式也不匹配,则在最下方抛出Fail异常


    2. Zygote接收请求并创建应用程序进程

    Socket连接成功并匹配ABI后会返回ZygoteState类型的对象,上文分析zygoteSendArgsAndGetResult方法时说过会将应用程序的启动参数argsForZygote写入ZygoteState中,这样Zygote进程就会收到一个创建新应用程序的请求,我们回到ZygoteInit的main方法中

    ZygoteInit的main方法

    public static void main(String argv[]) {
    ···
                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();
                }
    
    ···
                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.
                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();
            }
        }
    

    这些我在系统启动流程一文中有过记录,简单说就是这里通过registerZygoteSocket方法创建了一个Server端Socket,这个name为zygote的Socket用来等待AMS请求Zygote,以创建新的应用程序进程

    preload方法用于预加载类和资源,forkSystemServer用于创建SystemServer进程,runSelectLoop方法用于等待AMS请求创建新的应用程序进程,我们看看runSelectLoop方法

    ZygoteServer的runSelectLoop方法

    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);
    ···
        }
    

    这里先是创建了一个集合peers,结合最后一个try中的peers.get方法,我们得知最后一句中processOneCommand方法用于处理AMS的请求数据,我们跟进

    ZygoteConnection的processOneCommand方法

    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);
            }
    ···
            parsedArgs = new Arguments(args);
    ···
            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);
            }
        }
    

    第1个try块中调用readArgumentList方法来获取应用程序进程的启动参数,并在下面封装到parsedArgs对象里

    紧接着调用forkAndSpecialize方法创建应用程序进程,参数为parsedArgs中存储的应用程序进程启动参数,返回一个pid值。此方法主要就是通过fork当前进程来创造一个子进程的

    在最后一个try块中的条件判断pid是否为0,如果为0说明当前代码逻辑运行在新创建的应用程序进程中,这时就会return一个handleChildProc方法来处理应用程序进程,如下

    ZygoteConnection的handleChildProc方法

    private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
                FileDescriptor pipeFd, boolean isZygote) {
    ···
            // End of the postFork event.
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            if (parsedArgs.invokeWith != null) {
                WrapperInit.execApplication(parsedArgs.invokeWith,
                        parsedArgs.niceName, parsedArgs.targetSdkVersion,
                        VMRuntime.getCurrentInstructionSet(),
                        pipeFd, parsedArgs.remainingArgs);
    
                // Should not get here.
                throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
            } else {
                if (!isZygote) {
                    return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
                            null /* classLoader */);
                } else {
                    return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
                            parsedArgs.remainingArgs, null /* classLoader */);
                }
            }
        }
    

    这个方法里调用了ZygoteInit的zygoteInit方法

    ZygoteInit的zygoteInit方法

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

    倒数第2行调用nativeZygoteInit方法就会在新创建的应用程序进程中创建Binder线程池,最后返回了applicationInit方法

    RuntimeInit的application方法

    protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
                ClassLoader classLoader) {
            // If the application calls System.exit(), terminate the process
            // immediately without running any shutdown hooks.  It is not possible to
            // shutdown an Android application gracefully.  Among other things, the
            // Android runtime shutdown hooks close the Binder driver, which can cause
            // leftover running threads to crash before the process actually exits.
            nativeSetExitWithoutCleanup(true);
    
            // We want to be fairly aggressive about heap utilization, to avoid
            // holding on to a lot of memory that isn't needed.
            VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
            VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
    
            final Arguments args = new Arguments(argv);
    
            // The end of of the RuntimeInit event (see #zygoteInit).
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    
            // Remaining arguments are passed to the start class's static main
            return findStaticMain(args.startClass, args.startArgs, classLoader);
        }
    

    最后返回findStaticMain方法,需要注意的是,args.startClass这个参数,就是我们开头提到的android.app.ActivityThread参数,我们查看这个方法

    RuntimeInit的findStaticMain方法

    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);
        }
    

    可以看到开头的第1个try块中通过Class.forName反射拿到android.app.ActivityThread类,第2个try块中通过cl.getMethod拿到android.app.ActivityThread类的main方法,并将main方法最后传入MethodAndArgsCaller返回,进入这个类

    RuntimeInit的MethodAndArgsCaller类

    static class MethodAndArgsCaller implements Runnable {
            /** method to call */
            private final Method mMethod;
    
            /** argument array */
            private final String[] mArgs;
    
            public MethodAndArgsCaller(Method method, String[] args) {
                mMethod = method;
                mArgs = args;
            }
    
            public void run() {
                try {
                    mMethod.invoke(null, new Object[] { mArgs });
                } catch (IllegalAccessException ex) {
                    throw new RuntimeException(ex);
                } catch (InvocationTargetException ex) {
                    Throwable cause = ex.getCause();
                    if (cause instanceof RuntimeException) {
                        throw (RuntimeException) cause;
                    } else if (cause instanceof Error) {
                        throw (Error) cause;
                    }
                    throw new RuntimeException(ex);
                }
            }
        }
    

    这是一个静态内部类,run方法里的try块中,mMethod调用invoke方法,这里mMethod就是ActivityThread的main方法,调用invoke后,main方法就会被动态调用,应用程序进程就进入了ActivityThread的main方法里。

    到这里,应用程序进程就创建完成并且运行了主线程的管理类ActivityThread


    3. Binder线程池的启动

    应用程序进程创建过程中会启动Binder线程池,我们查看ZygoteInit类的zygoteInit方法,如下

    ZygoteInit的zygoteInit方法

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

    上面也说过,nativeZygoteInit会创建Binder线程池,点进去

    ZygoteInit的nativeZygoteInit方法

    private static final native void nativeZygoteInit();
    

    很明显这是一个JNI方法,那么它对应的函数就是AndroidRuntime.cpp的JNINativeMethod,数组中我们得知它对应的函数是com_android_internal_os_ZygoteInit_nativeZygoteInit,如下

    AndroidRuntime的nativeZygoteInit方法

    const JNINativeMethod methods[] = {
            { "nativeZygoteInit", "()V",
                (void*) com_android_internal_os_ZygoteInit_nativeZygoteInit },
        };
    

    就是他,我们继续看

    static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
    {
        gCurRuntime->onZygoteInit();
    }
    

    gCurRuntime是AndroidRuntime类型的指针,它是在AndroidRuntime初始化时就创建的,如下

    AndroidRuntime的gCurRuntime变量

    static AndroidRuntime* gCurRuntime = NULL;
    ···
    AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
            mExitWithoutCleanup(false),
            mArgBlockStart(argBlockStart),
            mArgBlockLength(argBlockLength)
    {
    ···
        gCurRuntime = this;
    }
    

    AppRuntime继承自AndroidRuntime,AppRuntime创建时就会调用AndroidRuntime的构造函数,gCurRuntime就会被初始化,它指向的是AppRuntime,我们来查看AppRuntime的onZygoteInit函数,AppRuntime在app_main.cpp中,如下

    app_main的onZygoteInit方法

    virtual void onZygoteInit()
        {
            sp<ProcessState> proc = ProcessState::self();
            ALOGV("App process: starting thread pool.\n");
            proc->startThreadPool();
        }
    

    最后一行会调用ProcessStart的startThreadPool函数来启动Binder线程池

    ProcessState的startThreadPool方法

    void ProcessState::startThreadPool()
    {
        AutoMutex_1(mLock);
        if(!mThreadPoolStarted){
            mThreadPoolStarted = true;
            spawnPooledThread(true);
        }
    }
    

    支持Binder通信的进程中,都有一个ProcessState类,它里面有一个mThreadPoolStarted变量,用于表示Binder线程池是否已经被启动过,默认为false,每次调用startThreadPool函数时都会先检查一次,确保Binder只会被启动一次

    如果Binder未启动,则先设置flag为true,并调用spawnPooledThread方法来创建线程池中的第一个线程,也就是线程池的主线程,如下

    ProcessState的spawnPooledThread方法

    void ProcessState::spawnPooledThread(bool isMain)
    {
        if (mThreadPoolStarted) {
            String8 name = makeBinderThreadName();
            ALOGV("Spawning new pooled thread, name=%s\n", name.string());
            sp<Thread> t = new PoolThread(isMain);
            t->run(name.string());
        }
    }
    

    可以看到Binder线程为一个PoolThread,最后调用run方法来启动一个新的线程,来看看PoolThread类做了什么

    ProcessState的PoolThread类

    class PoolThread : public Thread
    {
    ···
    protected:
        virtual bool threadLoop()
        {
            IPCThreadState::self()->joinThreadPool(mIsMain);
            return false;
        }
        
        const bool mIsMain;
    };
    

    继承了Thread类,方法体里调用IPCThreadState的joinThreadPool函数,将当前线程注册到Binder驱动中,这样我们创建的线程就加入了Binder线程池中,新创建的应用程序进程就支持Binder进程间通信了,我们只需要创建当前进程的Binder对象,并将它注册的ServiceManager就可以实现Binder进程间的通信,而不必关心进程间是如何进行通信的


    4. 消息循环的创建过程

    在上文中我们已经提到,静态内部类MethodAndArgsCaller中的run方法里,mMethod会调用invoke方法启动ActivityThread的main方法,我们看看ActivityThread的main方法,如下

    ActivityThread的main方法

    public static void main(String[] args) {
    ···
            Looper.prepareMainLooper();
    
            // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
            // It will be in the format "seq=114"
            long startSeq = 0;
            if (args != null) {
                for (int i = args.length - 1; i >= 0; --i) {
                    if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                        startSeq = Long.parseLong(
                                args[i].substring(PROC_START_SEQ_IDENT.length()));
                    }
                }
            }
            ActivityThread thread = new ActivityThread();
            thread.attach(false, startSeq);
    
            if (sMainThreadHandler == null) {
                sMainThreadHandler = thread.getHandler();
            }
    
            if (false) {
                Looper.myLooper().setMessageLogging(new
                        LogPrinter(Log.DEBUG, "ActivityThread"));
            }
    
            // End of event ActivityThreadMain.
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            Looper.loop();
    
            throw new RuntimeException("Main thread loop unexpectedly exited");
        }
    

    ActivityThread类用于管理当前应用程序进程的主线程,开头Looper.prepare()创建主线程的消息循环Looper

    通过new ActivityThread()的方式创建ActivityThread

    紧接着判断Handler类型的sMainThreadHandler是否为null,如果为null则在getHandler获取H类并赋值给sMainThreadHandler,这个H类继承自Handler,是ActivityThread的内部类,用于处理主线程的消息循环

    最后Looper.loop()开启消息循环,Looper可以开始处理消息,这样运行在应用程序进程中的应用程序可以方便的使用消息处理机制


    基于Android10.0,API 28,欢迎指正。

    相关文章

      网友评论

          本文标题:应用程序进程启动过程学习记录

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