Android12的启动

Android设备的启动必须经历3个阶段,即BootLoader、Linux kernel和Android系统服务,默认情况下他们都有各自的启动界面。

第一个系统进程init

严格意义上来说,Android系统实际上是运行于Linux内核之上的一系列“服务进程”,并不算是一个完整意义上的“操作系统”。这些进程是维持设备正常工作的关键,而他们的老祖宗就是init

作为Android中第一个被启动的进程,init的PID值为0。它通过解析init.rc脚本来构建出系统的初始运行形态——其他Android系统服务程序大多是在这个“rc”脚本中描述并被相继启动的。Init.rc不但语法相对简单,而且因为采用了纯文本的编写方式,所以可读性很高,是开发商控制Android系统启动状态的一大利器。

关于init.rc的语法可以参考官方文档,一个完整的init.rc脚本由4种类型的生命组成,即:

  • Action(动作)

    动作一般格式如下:

    on <trigger>  #触发条件
    	 <command>  ##执行命令
    	 <command>  #执行多个命令
    

    从源码实现的角度来说,当相应的事件发生后,系统会对init.rc中的各进行匹配——只要发现符合条件的Action,就会把它加入“命令执行队列”的尾部(除非这个Action在队列中已经存在),然后系统再对这些命令按顺序执行。

    常见事件

    triggerDescription
    boot这是init程序启动后触发的第一个事件
    <name> = <value>当属性满足特定时触发。后面有关于属性的进一步介绍
    device-added < path>
    device-removed 当设备节点添加/删除时触发此事件
    service-exited 当指定的服务存在时触发
  • Commands

    命令在所属事件发生时被一个个地执行

  • Services

    Services其实是可执行程序,他们在特定的约束下会被init程序运行或者重启,他的一般格式为:

    serice <name><pathname> [<argument>]*
    	<option>
    	<option>
    

    name表示service的名称。pathname表示service的所在路径。argument为参数,option为service的约束选项

  • Options

    Services中的可用选项

    optionDescription
    critical表明这是对设备至关重要的一个服务。如果他在四分钟内退出超过四次,则设备将重启进入恢复模式
    disabled此服务不会自动启动,而是需要通过显式调用服务名来启动
    setenv <name><value>设置环境变量为某个值

综合以上的分析就会发现,其实init.rc的语法可以用一个统一的形式来理解。如下所示

On <SOMETHING-HAPPEND>

<WHAT-TO-DO>

对于Action来说,他是当发生时去执行命令;而对于Service来说,他是always发生的(不需要启动触发条件),然后去启动指定的可执行文件(并且由Option来限制执行条件)。

根据文档中描述,会有下面四个事件依次被触发:

Init uses the following sequence of triggers during early boot. These are the built-in triggers defined in init.cpp.

  1. early-init - The first in the sequence, triggered after cgroups has been configured but before ueventd’s coldboot is complete.
  2. init - Triggered after coldboot is complete.
  3. charger - Triggered if ro.bootmode == "charger".
  4. late-init - Triggered if ro.bootmode != "charger", or via healthd triggering a boot from charging mode.

系统关键服务启动简析

作为Android系统的第一个进程,init将通过解析init.rc来陆续启动其他关键的系统服务进程——其中最重要的就是ServiceManager、Zygote和SystemServer

Android中的“DNS”服务器——ServiceManager

Binder机制的“DNS服务器”负责域名(某Binder服务在Service Manager注册时提供的名称)到IP地址(由底层Binder驱动分配的值)的解析。ServiceManager是在Init.rc里描述并由init进程启动的。

//system/core/rootdir/init.rc

on init
    ...

    # Start essential services.
    start servicemanager
    start hwservicemanager
    start vndservicemanager
//frameworks/native/cmds/servicemanager/servicemanager.rc

service servicemanager /system/bin/servicemanager
    class core animation
    user system
    group system readproc
    critical
    onrestart restart apexd
    onrestart restart audioserver
    onrestart restart gatekeeperd
    onrestart class_restart --only-enabled main
    onrestart class_restart --only-enabled hal
    onrestart class_restart --only-enabled early_hal
    task_profiles ServiceCapacityLow
    shutdown critical

可以看到,servicemanager是一个linux程序,他在设备中的存储路径是/system/bin/service-manager。ServiceManager所属class是core,当ServiceManager每次重启时,其他关键进程如apexd、audioserver、gatekeeperd等也会被restart。

孕育新的线程和进程——Zygote

Zygote这个词的字面意思是“受精卵”,因而可以孕育出一个“新生命”,正如其名,Android中大多数应用进程或系统进程都是通过Zygote来生成的。和ServiceManager类似,Zygote也是由init解析rc脚本时启动的。

//system/core/rootdir/init.rc

# It is recommended to put unnecessary data/ initialization from post-fs-data
# to start-zygote in device's init.rc to unblock zygote start.
on zygote-start && property:ro.crypto.state=unencrypted
    wait_for_prop odsign.verification.done 1
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start statsd
    start netd
    start zygote
    start zygote_secondary
//system/core/rootdir/init.zygote64.rc

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    socket usap_pool_primary stream 660 root system
    onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart media.tuner
    onrestart restart netd
    onrestart restart wificond
    task_profiles ProcessCapacityHigh
    critical window=${zygote.critical_window.minute:-off} target=zygote-fatal

从上面的脚本描述中可以看到,启动zygote要执行app_process64,并传入参数-Xzygote /system/bin --zygote --start-system-server,下面分析一下app_process的主函数实现

//frameworks/base/cmds/app_process/app_main.cpp

int main(int argc, char* const argv[])
{
	...
	 // Parse runtime arguments.  Stop at first unrecognized option.
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;

    ++i;  // Skip unused "parent dir" argument.
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
    }
    ...
    if (startSystemServer) {
            args.add(String8("start-system-server"));
    }
    ...
    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    }
}

该函数解析启动app_process时传入的参数,对于启动zygote的情况来说,所有的参数都会作为它主函数的参数使用,如上面代码的args,在我们这个场景中,init.rc制定了–zygote选项,因而app_process接下来启动“ZygoteInit”并传入“start-system-server",之后ZygoteInit会运行于Java虚拟机上。runtime这个变量实际上是一个AndroidRuntime对象,其start函数源码如下:

//frameworks/base/core/jni/AndroidRuntime.cpp

/*
 * Start the Android runtime.  This involves starting the virtual machine
 * and calling the "static void main(String[] args)" method in the class
 * named by "className".
 *
 * Passes the main function two arguments, the class name and the specified
 * options string.
 */
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) {
		...
/* start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
        return;
    }
    
}

VM启动后,会进入ZygoteInit类的main函数中执行

//frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

/**
     * This is the entry point for a Zygote process.  It creates the Zygote server, loads resources,
     * and handles other tasks related to preparing the process for forking into applications.
     *
     * This process is started with a nice value of -20 (highest priority).  All paths that flow
     * into new processes are required to either set the priority to the default value or terminate
     * before executing any non-system code.  The native side of this occurs in SpecializeCommon,
     * while the Java Language priority is changed in ZygoteInit.handleSystemServerProcess,
     * ZygoteConnection.handleChildProc, and Zygote.childMain.
     *
     * @param argv  Command line arguments used to specify the Zygote's configuration.
     */
    @UnsupportedAppUsage
    public static void main(String[] argv) {
        ZygoteServer zygoteServer = null;

        // Mark zygote start. This ensures that thread creation will throw
        // an error.
        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);
        }

        Runnable caller;
        try {
            ...
            boolean startSystemServer = false;
            String zygoteSocketName = "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)) {
                    zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }

            final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);
            if (!isRuntimeRestarted) {
                if (isPrimaryZygote) {
                    FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
                            BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__ZYGOTE_INIT_START,
                            startTime);
                } else if (zygoteSocketName.equals(Zygote.SECONDARY_SOCKET_NAME)) {
                    FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
                            BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SECONDARY_ZYGOTE_INIT_START,
                            startTime);
                }
            }
			...

            zygoteServer = new ZygoteServer(isPrimaryZygote);

            if (startSystemServer) {
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);

                ...
            }

            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 fatal exception", ex);
            throw ex;
        } finally {
            if (zygoteServer != null) {
                zygoteServer.closeServerSocket();
            }
        }

        // We're in the child process and have exited the select loop. Proceed to execute the
        // command.
        if (caller != null) {
            caller.run();
        }
    }

主要完成以下两个工作:

  1. 注册一个Socket:new ZygoteSever()

    Zygote是“孵化器”,一旦有新程序需要运行时,系统会通过这个Socket第一时间通知“总管家”,并由他负责实际的进程孵化过程
    `

  2. 启动systemServer:forkSystemServer

    如果app_process的调用参数中带有“—start-system-server”,那么此时就会通过forkSystemServer来启动SystemServer,

Zygote在前期主要担任启动系统服务的工作,后面有担当“程序孵化”的重任,为了协调好这两个工作的关系,通过forkSystemSever创建新的进程来承载系统服务的运行,而后app_process所在的进程转变为Zygote的“孵化器”守护进程。

/**
     * Prepare the arguments and forks for the system server process.
     *
     * @return A {@code Runnable} that provides an entrypoint into system_server code in the child
     * process; {@code null} in the parent.
     */
    private static Runnable forkSystemServer(String abiList, String socketName, ZygoteServer zygoteServer) {
        /* Hardcoded command line to start the system server */
        String[] args = {
                "--setuid=1000",
                "--setgid=1000",
                "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
                        + "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010,3011,3012",
                "--capabilities=" + capabilities + "," + capabilities,
                "--nice-name=system_server",
                "--runtime-args",
                "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
                "com.android.server.SystemServer",
        };
        ZygoteArguments parsedArgs;

        int pid;

        try {
            ZygoteCommandBuffer commandBuffer = new ZygoteCommandBuffer(args);
            try {
                parsedArgs = ZygoteArguments.getInstance(commandBuffer);
            } catch (EOFException e) {
                throw new AssertionError("Unexpected argument error for forking system server", e);
            }
            commandBuffer.close();
            Zygote.applyDebuggerSystemProperty(parsedArgs);
            Zygote.applyInvokeWithSystemProperty(parsedArgs);

          ...

            /* Request to fork the system server process */
            pid = Zygote.forkSystemServer(
                    parsedArgs.mUid, parsedArgs.mGid,
                    parsedArgs.mGids,
                    parsedArgs.mRuntimeFlags,
                    null,
                    parsedArgs.mPermittedCapabilities,
                    parsedArgs.mEffectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        /* For child process */
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            zygoteServer.closeServerSocket();
            return handleSystemServerProcess(parsedArgs);
        }

        return null;
    }

ZygoteInit.forkSystemServer调用Zygote.forkSystemServer函数,该函数内部利用UNIX的fork机制创建出了一个新进程;而这个“新生儿”(即pid==0分支)会在随后的执行过程中通过handleSystemServerProcess来启动各种支撑系统运行的System Server。在跟踪SystemServer的具体启动过程之前,我们先来为Zygote接下来的工作做一个分析,与我们之前所见得fork处理流程不同的是,startSystemSever中并没有为父进程专门开辟一个代码分支,因而父进程在ZygoteInit.forkSystemServer后会回到ZygoteInit的主函数中(java虚拟机),执行后面的

// The select loop returns early in the child process after a fork and loops forever in the zygote.
caller = zygoteServer.runSelectLoop(abiList);

这是一个死循环——除非Zygote退出或者出现异常才会跳出循环。

/**
     * Runs the zygote process's select loop. Accepts new connections as
     * they happen, and reads commands from connections one spawn-request's
     * worth at a time.
     * @param abiList list of ABIs supported by this zygote.
     */
Runnable runSelectLoop(String abiList) {
    ...

        while (true) {
            fetchUsapPoolPolicyPropsWithMinInterval();
            mUsapPoolRefillAction = UsapPoolRefillAction.NONE;

            int[] usapPipeFDs = null;
            StructPollfd[] pollFDs;

  
            if (mUsapPoolEnabled) {
                usapPipeFDs = Zygote.getUsapPipeFDs();
                pollFDs = new StructPollfd[socketFDs.size() + 1 + usapPipeFDs.length];
            } else {
                pollFDs = new StructPollfd[socketFDs.size()];
            }

            int pollIndex = 0;
            for (FileDescriptor socketFD : socketFDs) {
                pollFDs[pollIndex] = new StructPollfd();
                pollFDs[pollIndex].fd = socketFD;
                pollFDs[pollIndex].events = (short) POLLIN;
                ++pollIndex;
            }

            final int usapPoolEventFDIndex = pollIndex;

            if (mUsapPoolEnabled) {
                pollFDs[pollIndex] = new StructPollfd();
                pollFDs[pollIndex].fd = mUsapPoolEventFD;
                pollFDs[pollIndex].events = (short) POLLIN;
                ++pollIndex;

                // The usapPipeFDs array will always be filled in if the USAP Pool is enabled.
                assert usapPipeFDs != null;
                for (int usapPipeFD : usapPipeFDs) {
                    FileDescriptor managedFd = new FileDescriptor();
                    managedFd.setInt$(usapPipeFD);

                    pollFDs[pollIndex] = new StructPollfd();
                    pollFDs[pollIndex].fd = managedFd;
                    pollFDs[pollIndex].events = (short) POLLIN;
                    ++pollIndex;
                }
            }

            ...

                int pollReturnValue;
            try {
                pollReturnValue = Os.poll(pollFDs, pollTimeoutMs);
            } catch (ErrnoException ex) {
                throw new RuntimeException("poll failed", ex);
            }

            if (pollReturnValue == 0) {
                // The poll returned zero results either when the timeout value has been exceeded
                // or when a non-blocking poll is issued and no FDs are ready.  In either case it
                // is time to refill the pool.  This will result in a duplicate assignment when
                // the non-blocking poll returns zero results, but it avoids an additional
                // conditional in the else branch.
                mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
                mUsapPoolRefillAction = UsapPoolRefillAction.DELAYED;

            } else {
                boolean usapPoolFDRead = false;

                while (--pollIndex >= 0) {
                    if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
                        continue;
                    }

                    if (pollIndex == 0) {
                        // Zygote server socket
                        ZygoteConnection newPeer = acceptCommandPeer(abiList);
                        peers.add(newPeer);
                        socketFDs.add(newPeer.getFileDescriptor());
                    } else if (pollIndex < usapPoolEventFDIndex) {
                        // Session socket accepted from the Zygote server socket

                        try {
                            ZygoteConnection connection = peers.get(pollIndex);
                            boolean multipleForksOK = !isUsapPoolEnabled()
                                && ZygoteHooks.isIndefiniteThreadSuspensionSafe();
                            final Runnable command =
                                connection.processCommand(this, multipleForksOK);

                            // TODO (chriswailes): Is this extra check necessary?
                            if (mIsForkChild) {
                                // We're in the child. We should always have a command to run at
                                // this stage if processCommand hasn't called "exec".
                                if (command == null) {
                                    throw new IllegalStateException("command == null");
                                }

                                return command;
                            } else {
                                // We're in the server - we should never have any commands to run.
                                if (command != null) {
                                    throw new IllegalStateException("command != null");
                                }

                                // We don't know whether the remote side of the socket was closed or
                                // not until we attempt to read from it from processCommand. This
                                // shows up as a regular POLLIN event in our regular processing
                                // loop.
                                if (connection.isClosedByPeer()) {
                                    connection.closeSocket();
                                    peers.remove(pollIndex);
                                    socketFDs.remove(pollIndex);
                                }
                            }
                        } 
                        ...
                    } 
                    ...

                }
            }

从程序中可以看到runSelectLoop的主体就是while死循环,它将作为zygote的守护体存在,重点在于当zygote的socket收到来自客户端的连接时,产生新的connection,然后执行processCommand函数进行处理。

final Runnable command = connection.processCommand(this, multipleForksOK);
    /**
     * Reads a command from the command socket. If a child is successfully forked, a
     * {@code Runnable} that calls the childs main method (or equivalent) is returned in the child
     * process. {@code null} is always returned in the parent process (the zygote).
     * If multipleOK is set, we may keep processing additional fork commands before returning.
     *
     * If the client closes the socket, an {@code EOF} condition is set, which callers can test
     * for by calling {@code ZygoteConnection.isClosedByPeer}.
     */
    Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) {
    ...

        if (parsedArgs.mInvokeWith != null || parsedArgs.mStartChildZygote
            || !multipleOK || peer.getUid() != Process.SYSTEM_UID) {
            // Continue using old code for now. TODO: Handle these cases in the other path.
            pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid,
                                           parsedArgs.mGids, parsedArgs.mRuntimeFlags, rlimits,
                                           parsedArgs.mMountExternal, parsedArgs.mSeInfo, parsedArgs.mNiceName,
                                           fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
                                           parsedArgs.mInstructionSet, parsedArgs.mAppDataDir,
                                           parsedArgs.mIsTopApp, parsedArgs.mPkgDataInfoList,
                                           parsedArgs.mAllowlistedDataInfoList, parsedArgs.mBindMountAppDataDirs,
                                           parsedArgs.mBindMountAppStorageDirs);

            try {
                if (pid == 0) {
                    // in child
                    zygoteServer.setForkChild();

                    zygoteServer.closeServerSocket();
                    IoUtils.closeQuietly(serverPipeFd);
                    serverPipeFd = null;

                    return handleChildProc(parsedArgs, childPipeFd,
                                           parsedArgs.mStartChildZygote);
                } else {
                    // In the parent. A pid < 0 indicates a failure and will be handled in
                    // handleParentProc.
                    IoUtils.closeQuietly(childPipeFd);
                    childPipeFd = null;
                    handleParentProc(pid, serverPipeFd);
                    return null;
                }
            } finally {
                IoUtils.closeQuietly(childPipeFd);
                IoUtils.closeQuietly(serverPipeFd);
            }
...
}

该函数调用forkAndSpecialize来创建承载应用程序的新进程。Specialize的字面意思是专门化,表达了forkAndSpecialize在“孵化”的同时也把它转变为Android应用程序的目标,函数forkAndSpceialize的处理也分为三个阶段,即

 static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
            int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
            int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
            boolean isTopApp, String[] pkgDataInfoList, String[] allowlistedDataInfoList,
            boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) {
        ZygoteHooks.preFork();

        int pid = nativeForkAndSpecialize(
                uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
                fdsToIgnore, startChildZygote, instructionSet, appDataDir, isTopApp,
                pkgDataInfoList, allowlistedDataInfoList, bindMountAppDataDirs,
                bindMountAppStorageDirs);
        if (pid == 0) {
            // Note that this event ends at the end of handleChildProc,
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");

            // If no GIDs were specified, don't make any permissions changes based on groups.
            if (gids != null && gids.length > 0) {
                NetworkUtilsInternal.setAllowNetworkingForProcess(containsInetGid(gids));
            }
        }

        // Set the Java Language thread priority to the default value for new apps.
        Thread.currentThread().setPriority(Thread.NORM_PRIORITY);

        ZygoteHooks.postForkCommon();
        return pid;
    }
  • prefork
  • nativeForkAndSpecialize
  • postForkCommon

我们主要关心nativeForkAndSpecialize,这是个native方法,对应着下面的函数

//frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
        JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, jint runtime_flags,
        jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name,
        jintArray managed_fds_to_close, jintArray managed_fds_to_ignore, jboolean is_child_zygote,
        jstring instruction_set, jstring app_data_dir, jboolean is_top_app,
        jobjectArray pkg_data_info_list, jobjectArray allowlisted_data_info_list,
        jboolean mount_data_dirs, jboolean mount_storage_dirs) {
    jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);


    ...

    pid_t pid = zygote::ForkCommon(env, /* is_system_server= */ false, fds_to_close, fds_to_ignore, true);

    if (pid == 0) {
        SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, capabilities, capabilities,
                         mount_external, se_info, nice_name, false, is_child_zygote == JNI_TRUE,
                         instruction_set, app_data_dir, is_top_app == JNI_TRUE, pkg_data_info_list,
                         allowlisted_data_info_list, mount_data_dirs == JNI_TRUE,
                         mount_storage_dirs == JNI_TRUE);
    }
    return pid;
}

// Utility routine to fork a process from the zygote.
pid_t zygote::ForkCommon(JNIEnv* env, bool is_system_server,
                         const std::vector<int>& fds_to_close,
                         const std::vector<int>& fds_to_ignore,
                         bool is_priority_fork,
                         bool purge) {
 ...

  pid_t pid = fork();

  if (pid == 0) {
    if (is_priority_fork) {
      setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX);
    } else {
      setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MIN);
    }

    ...
  } else {
    ALOGD("Forked child process %d", pid);
  }
}

ForkCommon函数中调用了fork函数,并将子进程的优先级设置为MAX,再回到com_android_internal_os_Zygote_nativeForkAndSpecialize中执行SpecializeCommon,该函数中设置子进程的私有数据,如调度策略、uid等,最后再将自己的优先级恢复正常。之后回到processCommand中,父进程进行一些扫尾工作,包括:将子进程加入进程组;正确关闭文件;调用方法返回结果值等,子进程调用handleChildProc来执行目标进程的入口函数

 private Runnable handleChildProc(ZygoteArguments parsedArgs,
            FileDescriptor pipeFd, boolean isZygote) {
        /*
         * By the time we get here, the native code has closed the two actual Zygote
         * socket connections, and substituted /dev/null in their place.  The LocalSocket
         * objects still need to be closed properly.
         */

        closeSocket();

        Zygote.setAppProcessName(parsedArgs, TAG);

        // End of the postFork event.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        if (parsedArgs.mInvokeWith != null) {
            WrapperInit.execApplication(parsedArgs.mInvokeWith,
                    parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
                    VMRuntime.getCurrentInstructionSet(),
                    pipeFd, parsedArgs.mRemainingArgs);

            // Should not get here.
            throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
        } else {
            if (!isZygote) {
                return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
                        parsedArgs.mDisabledCompatChanges,
                        parsedArgs.mRemainingArgs, null /* classLoader */);
            } else {
                return ZygoteInit.childZygoteInit(
                        parsedArgs.mRemainingArgs  /* classLoader */);
            }
        }
    }

该函数会调用ZygoteInit.zygoteInitzygoteInit调用 RuntimeInit.applicationInit,最后通过

// Remaining arguments are passed to the start class's static main
        return findStaticMain(args.startClass, args.startArgs, classLoader);

执行startClass类的main函数,那么这个startClass具体是什么呢?要回答这个问题并不是件容易的事情,需要大家对应用程序的启动流程有一个全局的认识,我们假设当前的流程已经到了ActivityManagerService,他会想Zygote发起一个创建进程的请求。

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

final ProcessRecord startProcessLocked(String processName,
            ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting,
            boolean isolated) {
        return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
                hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */,
                null /* ABI override */, null /* entryPoint */,
                null /* entryPointArgs */, null /* crashHandler */);
    }

最终层层向下会调用

//frameworks/base/services/core/java/com/android/server/am/ProcessList.java

boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord, int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean disableTestApiChecks, String abiOverride) {
            // 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(hostingRecord, entryPoint, app, uid, gids,
                    runtimeFlags, zygotePolicyFlags, mountExternal, seInfo, requiredAbi,
                    instructionSet, invokeWith, startTime);
}

//最终调用下面的函数
private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint, ProcessRecord app, int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags,
            int mountExternal, String seInfo, String requiredAbi, String instructionSet,
            String invokeWith, long startTime) {
       ...
            final Process.ProcessStartResult startResult;
            boolean regularZygote = false;
            if (hostingRecord.usesWebviewZygote()) {
                startResult = startWebView(entryPoint,
                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, null, app.info.packageName,
                        app.getDisabledCompatChanges(),
                        new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()});
            } else if (hostingRecord.usesAppZygote()) {
                final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app);

                // We can't isolate app data and storage data as parent zygote already did that.
                startResult = appZygote.getProcess().start(entryPoint,
                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, null, app.info.packageName,
                        /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp,
                        app.getDisabledCompatChanges(), pkgDataInfoMap, allowlistedAppDataInfoMap,
                        false, false,
                        new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()});
            } else {
                regularZygote = true;
                startResult = Process.start(entryPoint,
                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags,
                        isTopApp, app.getDisabledCompatChanges(), pkgDataInfoMap,
                        allowlistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs,
                        new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()});
            }
}

可以看到其中有一段代码为final String entryPoint = "android.app.ActivityThread";因此可以认为Zygote中执行的是ActivityThread类的main函数,这同时也是我们熟知的Android应用程序的主线程。

//frameworks/base/core/java/android/app/ActivityThread.java

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

到目前为止我们总结一下,app_process64一开始申请socket,然后fork出子进程执行SystemServer,父进程执行死循环监听socket,如果socket中有来自客户端的消息,则fork出进程,并执行ActivityThread的main函数。

SystemServer

从前面的分析可以知道,ZygoteInit.forkSystemServer调用Zygote.forkSystemServer来创建子进程,然后在pid==0的分支中调用handleSystemServerProcess,

private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
      ...

            /* Request to fork the system server process */
            pid = Zygote.forkSystemServer(
                    parsedArgs.mUid, parsedArgs.mGid,
                    parsedArgs.mGids,
                    parsedArgs.mRuntimeFlags,
                    null,
                    parsedArgs.mPermittedCapabilities,
                    parsedArgs.mEffectiveCapabilities);

        /* For child process */
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            zygoteServer.closeServerSocket();
            return handleSystemServerProcess(parsedArgs);
        }

        return null;
    }

handleSystemServerProcess同样会调用ZygoteInit.zygoteInitzygoteInit调用 RuntimeInit.applicationInit,但和执行普通进程的目标函数不同,此时的systemserver的startClass已经换成了forkSystemServer时args数组中的com.android.server.SystemServer

String[] args = {
                "--setuid=1000",
                "--setgid=1000",
                "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
                        + "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010,3011,3012",
                "--capabilities=" + capabilities + "," + capabilities,
                "--nice-name=system_server",
                "--runtime-args",
                "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
                "com.android.server.SystemServer",
};

因此最终applicationInit将调用SystemServer的main函数。之后SystemServer开始执行,启动各种系统服务,启动过程不再赘述。其中最值得我们关心的时ActivityManagerService,我们放到下次再讲。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

武汉大学计算机学院智能计算系统实验室

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值