1. System startup process overview

The main process of startup:

  1. Boot power and system boot: When the power is pressed, the boot chip code is executed from a predefined place (solidified in ROM). Load the boot program BootLoader into RAM and execute.
  2. Bootloader: Bootloader is a small program before the Android operating system starts to run. Its main purpose is to pull the operating system up and run.
  3. Linux kernel startup:When the kernel starts, the cache is set up, the protected storage is set, the schedule list is set, and the driver is loaded. When the kernel finishes setting up the system, it first looks in the system filesinit.rcFile and start the init process.
  4. Init process start: Initializes and starts the properties service, and starts the Zygote process.
  5. Zygote process startup: Create a Java VM, register the JNI method for the VM, create server-side sockets, and start the SystemServer process.
  6. Start SystemServer process: Start Binder thread pools and SystemServiceManager, and start various system services.
  7. Launcher: AMS started by the SystemServer process starts the Launcher, which displays the shortcut icon of the installed application on the screen.


2. The init process starts

The init process is the first user space process in the Android operating system. The process id is 1 and it is a key step in the Startup process of the Android operating system. The following three things have been done:

  • Create and mount the file directories required for startup.
  • Initialize and start the properties service.
  • parsinginit.rcConfigure the file and start the Zygote process.

2.1. Entry function of init process

In the Linux kernel after completion of loading, it first in system file for init. Rc file (/ system/core/rootdir/init. Rc), and start the init process, Then look at the init process entry main function to read the configuration in init.rc to start other related processes and other operations.

Android 9 and in the past, the main function in/system/core/init/init. CPP file, the source based on the Android 9.0.0:

int main(int argc, char** argv) {
    / *... * /

    bool is_first_stage = (getenv("INIT_SECOND_STAGE") = =nullptr);

    if (is_first_stage) {
        boot_clock::time_point start_time = boot_clock::now(a);/ / clean the umask.
        umask(0);

        clearenv(a);setenv("PATH", _PATH_DEFPATH, 1);
        // Create and mount the file directories required for startup
        mount("tmpfs"."/dev"."tmpfs", MS_NOSUID, "mode=0755");
        mkdir("/dev/pts".0755);
        mkdir("/dev/socket".0755);
        mount("devpts"."/dev/pts"."devpts".0.NULL);
        #define MAKE_STR(x) __STRING(x)
        mount("proc"."/proc"."proc".0."hidepid=2,gid=" MAKE_STR(AID_READPROC));
        // Don't expose the raw commandline to unprivileged processes.
        chmod("/proc/cmdline".0440);
        gid_t groups[] = { AID_READPROC };
        setgroups(arraysize(groups), groups);
        mount("sysfs"."/sys"."sysfs".0.NULL);
        mount("selinuxfs"."/sys/fs/selinux"."selinuxfs".0.NULL);

        mknod("/dev/kmsg", S_IFCHR | 0600.makedev(1.11));

        if constexpr (WORLD_WRITABLE_KMSG) {
            mknod("/dev/kmsg_debug", S_IFCHR | 0622.makedev(1.11));
        }

        mknod("/dev/random", S_IFCHR | 0666.makedev(1.8));
        mknod("/dev/urandom", S_IFCHR | 0666.makedev(1.9));

        mount("tmpfs"."/mnt"."tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
              "mode=0755,uid=0,gid=1000");

        mkdir("/mnt/vendor".0755);

        // Initialize the Kernel Log, so that the Kernel Log can be obtained from the outside
        InitKernelLogging(argv);
        / *... * /
    }
    / *... * /
	// Initialize the properties service
    property_init(a);/ *... * /
	// Create an epoll handle
    epoll_fd = epoll_create1(EPOLL_CLOEXEC);
    / *... * /
	If the Zygote (Zygote) process exits unexpectedly, init will call the signal handler set in this function to handle it
    sigchld_handler_init(a);/ *... * /
	// Import the default environment variables
    property_load_boot_defaults(a);export_oem_lock_status(a);// Start the properties service
    start_property_service(a);set_usb_controller(a);const BuiltinFunctionMap function_map;
    Action::set_function_map(&function_map);

    subcontexts = InitializeSubcontexts(a); ActionManager& am = ActionManager::GetInstance(a); ServiceList& sm = ServiceList::GetInstance(a);// Load the startup script. For details, see 👇
    LoadBootScripts(am, sm);
    
	if (false) DumpState(a);/ *... * /
    while (true) {
        / *... * /
        if(! (waiting_for_prop || Service::is_exec_service_running())) {
            // Internal traversal executes the execution function corresponding to the command carried in each action
            am.ExecuteOneCommand(a); }if(! (waiting_for_prop || Service::is_exec_service_running())) {
            if(! shutting_down) {// Restart the dead process
                auto next_process_restart_time = RestartProcesses(a);/ *... * /
            }
			/ *... * /
        }
		/ *... * /
    }
    
    return 0;
}

static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
    Parser parser = CreateParser(action_manager, service_list);

    std::string bootscript = GetProperty("ro.boot.init_rc"."");
    if (bootscript.empty()) {
        // Parse the init.rc configuration file
        parser.ParseConfig("/system/etc/init/hw/init.rc");
        if(! parser.ParseConfig("/system/etc/init")) {
            late_import_paths.emplace_back("/system/etc/init");
        }
        parser.ParseConfig("/system_ext/etc/init");
        if(! parser.ParseConfig("/vendor/etc/init")) {
            late_import_paths.emplace_back("/vendor/etc/init");
        }
        if(! parser.ParseConfig("/odm/etc/init")) {
            late_import_paths.emplace_back("/odm/etc/init");
        }
        if(! parser.ParseConfig("/product/etc/init")) {
            late_import_paths.emplace_back("/product/etc/init"); }}else {
        parser.ParseConfig(bootscript); }}Copy the code

Android 10 and so on, the main function in/system/core/init/main CPP file, the following source based on the Android 10.0.0:

// argc indicates how many arguments are in argv
The argv argument can have four different cases, entering different entrances
int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
    __asan_set_error_report_callback(AsanReportCallback);
#endif
	Ueventd is responsible for creating device nodes, setting permissions, etc
    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }

    if (argc > 1) {
        // The subContext argument goes to InitLogging and SubcontextMain to initialize the logging system
        if (!strcmp(argv[1]."subcontext")) {
            android::base::InitLogging(argv, &android::base::KernelLogger);
            const BuiltinFunctionMap function_map;

            return SubcontextMain(argc, argv, &function_map);
        }
		SetupSelinux starts the Selinux security policy
        if (!strcmp(argv[1]."selinux_setup")) {
            return SetupSelinux(argv);
        }
		SecondStageMain, init process phase 2
        if (!strcmp(argv[1]."second_stage")) {
            return SecondStageMain(argc, argv); }}The first stage / / start the init process (function defined in the/system/core/init/init. CPP)
    return FirstStageMain(argc, argv);
}
Copy the code

To sum up, main does the following key steps:

  • Create and mount the file directories required for startup:mounttmpfs,devpts,proc,sysfsselinuxfsFive file systems, all of which are system runtime directories.
  • Property_init () : Initializes the property.
  • Signal_handler_init () : Sets the child signal handler function to prevent the init process’s child (Zygote) from becoming a zombie process.
  • Start_property_service () : starts the property service.
  • Parser. ParseConfig (“/system/etc/init/hw/init. Rc “) :parsinginit.rcFile.
  • Restart_processes () : Restarts dead processes.

[Zombie Progression]

The parent process uses fork to create a child process. If the child process terminates, the parent process does not know about it and retains its information (process number, exit status, running time…) in the system process table. , the terminated child process is the zombie process.

If the system process table is exhausted by zombie processes, the system may not be able to create new processes.

Signal_handler_init () will find the Zygote process well, remove all information, and restart the Zygote service with the onrestart option in the Zygote startup script. Call restart_processes() to restart the Zygote process.

2.2. Parsing init.rc file

/ system/core/rootdir/init. Rc is initialized by the Android Language (Android init Language) to write configuration files, mainly contains five types of statements: Action, Command, Service, Option and Import.

/ *... * /
// This action is triggered when you press and hold the system power button
on property:sys.boot_from_charger_mode=1
    class_stop charger
    trigger late-init
/ *... * /
// Mount the file system and start the core system service.
on late-init
    / *.. * /
    // The zygote process is started on the device based on file encryption
    trigger zygote-start
	/ *.. * /
Copy the code

An important step is to start the Zygote process.

/ system/core/rootdir/init. ZygoteXX. Rc file is Zygote startup scripts.

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 netd
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks
Copy the code

Service is used to tell the init process to create a process named zygote. The execution path is /system/bin/app_process64, followed by the parameters to be passed to app_process64. And Zygote’s classname is main. If the audioServer, Cameraserver, and Media processes are terminated, you need to restart them.



3. The Zygote process is started

The Zygote process is called the incubator. It creates the DVM and ART, and the APP process and the system SystemServer process are created by its FOCk (Replication process), so it can get an instance copy of the DVM or ART internally.

The name of the Zygote process is not “Zygote” but “app_process”, which is defined in Android.mk. After the Zygote process starts, the Linux PCTRL system calls app_process and changes its name to Zygote.

Different versions, the code is slightly different, the overall process is not very different, the following code based on Android 8.0 source code

3.1. Startup process

3.1.1. App_main. CPP

frameworks/base/cmds/app_process/app_main.cpp

The important flow of the main function of app_main. CPP

int main(int argc, char* const argv[])
{
    / *... * /
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    / *... * /
    ++i;	// Skip the first argument (parent directory)
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") = =0) {
            // Set Zygote to true if main is running in a Zygote process
            zygote = true;
            // Set the process name
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") = =0) {
            // Set startSystemServer to true if main is running in the SystemServer process
            startSystemServer = true;
        } 
        / *... * /
    }
    / *... * /
    if (zygote) {
        // If running in a Zygote process, the start function of AppRuntime is called
        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(a);LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); }}Copy the code

Important process summary:

  • Determine the currentmainWhether the function is run in Zygote or SystemServer.
    • The Zygote process creates child processes through Fock itself, so both the Zygote process and its children can enterapp_main.cppmainDelta function, somainThe function must distinguish which process is currently running in.
  • If running in a Zygote process, AppRuntime’sstartFunction to start the Java virtual machine.

3.1.2. AndroidRuntime. CPP

frameworks/base/core/jni/AndroidRuntime.cpp

Androidruntime.cpp is an important process for the start function

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    / *... * /
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    // Create a Java VM
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) ! =0) {
        return;
    }
    // Initialize the VIRTUAL machine
    onVmCreated(env);

    // Register the JNI method for the Java virtual machine
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }

    / *... * /
    / / from the main function of app_main passed the className for com. Android. Internal. OS. ZygoteInit
    classNameStr = env->NewStringUTF(className);
    assert(classNameStr ! =NULL);
    env->SetObjectArrayElement(strArray, 0, classNameStr);

    for (size_t i = 0; i < options.size(a); ++i) { jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
        assert(optionsStr ! =NULL);
        env->SetObjectArrayElement(strArray, i + 1, optionsStr);
    }

    // When the VM is started, the thread becomes the main thread of the VM and does not return until the VM exits.
    // Put classNarne's ". Replace with "/"
    char* slashClassName = toSlashClassName(className ! =NULL ? className : "");
    // Find the Java class ZygoteInit
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
    } else {
        // Find ZygoteInit's main method
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main"."([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            // Call ZygoteInit's main method from JNI
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
            / *... * /}}/ *... * /
}
Copy the code

Important process summary:

  • callstartVmFunction to create a Java virtual machine.
  • callstartRegThe JNI function registers JNI methods for the Java virtual machine.
  • The argument that will be passedclassNameThe value of thecom.android.internal.os.ZygoteInitIn the.Replace with/, i.e.,com/android/internal/os/ZygoteInitAnd assign a value toslashClassName
  • According to theslashClassNameTo findZygotelnitClass.
  • If found, it is called through JNIZygoteInitmainMethods.

⭐️ has been running in the Native layer until now, and no code has entered the Java framework layer, i.e. Zygote has enabled the Java framework layer to run.

3.1.3. ZygoteInit. Java

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

Important flow of zygoteinit. Java’s main method and startSystemServer method

The code varies slightly from version to version:

Here is the ZygoteInit class for Android 8.0.

public static void main(String argv[]) {
    // Create ZygoteServer object
    ZygoteServer zygoteServer = new ZygoteServer();
    / *... * /
    try {
        / *... * /
        String socketName = "zygote";
        / *... * /
        // Create a Server Socket and pass in the socketName
        zygoteServer.registerServerSocket(socketName);
        if(! enableLazyPreload) { bootTimingsTraceLog.traceBegin("ZygotePreload");
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis());
            // Preload classes and resources
            preload(bootTimingsTraceLog);
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis());
            bootTimingsTraceLog.traceEnd();
        } else {
            Zygote.resetNicePriority();
        }
		/ *... * /
        if (startSystemServer) {
            Start the SystemServer process
            startSystemServer(abiList, socketName, zygoteServer);
        }
        Log.i(TAG, "Accepting command socket connections");
        // Wait for AMS to create a new application process
        zygoteServer.runSelectLoop(abiList);
        zygoteServer.closeServerSocket();
    } catch (Zygote.MethodAndArgsCaller caller) {
        caller.run();
    } catch (Throwable ex) {
        Log.e(TAG, "System zygote died with exception", ex);
        zygoteServer.closeServerSocket();
        throwex; }}private static boolean startSystemServer(String abiList, String socketName, ZygoteServer zygoteServer)
        throws Zygote.MethodAndArgsCaller, RuntimeException {
    / *... * /
    // Create an args array to hold the startup parameters for starting SystemServer
    String args[] = {
        "--setuid=1000"./ / user id
        "--setgid=1000".// User group ID
        // Permissions that the process has
        "- setgroups = 1001100 2100 3100 4100 5100 6100 7100 8100 9101 0101 8102 1102 3103 2300 1300 2300 3300 6300 7300 9301 0"."--capabilities=" + capabilities + "," + capabilities,
        "--nice-name=system_server"./ / process name
        "--runtime-args".// The name of the class to start
        "com.android.server.SystemServer"}; ZygoteConnection.Arguments parsedArgs =null;

    int pid;

    try {
        // Wrap the args array into Arguments objects
        parsedArgs = new ZygoteConnection.Arguments(args);
        ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
        ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

        // Create a child, the SystemServer process
        pid = Zygote.forkSystemServer(
                parsedArgs.uid, parsedArgs.gid,
                parsedArgs.gids,
                parsedArgs.debugFlags,
                null,
                parsedArgs.permittedCapabilities,
                parsedArgs.effectiveCapabilities);
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException(ex);
    }

    // The current code logic is running in a child process
    if (pid == 0) {
        if (hasSecondZygote(abiList)) {
            waitForSecondaryZygote(socketName);
        }
		// Close the Socket created by Zygote
        zygoteServer.closeServerSocket();
        // Process the SystemServer process
        handleSystemServerProcess(parsedArgs);
    }

    return true;
}
Copy the code

Important process summary:

  • throughregisterServerSocketMethod to create a Server namezygoteThe Socket object of.
  • Preload common classes and common resources, which can be shared with all its children by fork, and the load is divided into several parts:
    • preloadClasses(); Preload Classes.
    • preloadResources();Preload Resources.
    • preloadOpenGL();Preload openGL.
    • preloadSharedLibraries();Preload the shared class library.
    • preloadTextResources();Preloads text resources.
    • WebViewFactory.prepareWebViewInZygote();Initialize the WebView to implement memory sharing between child processes.
  • If the SystemServer process is started, system services are also started by the SystemServer process.
  • callZygoteServerrunSelectLoopMethods forActivityManagerServiceRequest to create a new application process.

3.1.4. ZygoteServer. Java

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

The important flow of zygoteserver.java registerServerSocket method and runSelectLoop method

Here is the ZygoteServer class for Android 8.0.

private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
// Server-side Socket object
private LocalServerSocket mServerSocket;

void registerServerSocket(String socketName) {
    if (mServerSocket == null) {
        int fileDesc;
        // Concatenate the complete Socket name. SocketName is zygote
        final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
        try {
            // Get environment variables
            String env = System.getenv(fullSocketName);
            // Convert the value of the environment variable to the parameter of the file descriptor
            fileDesc = Integer.parseInt(env);
        } catch (RuntimeException ex) {
            throw new RuntimeException(fullSocketName + " unset or invalid", ex);
        }

        try {
            FileDescriptor fd = new FileDescriptor();
            // Set the file descriptor
            fd.setInt$(fileDesc);
            // Create a server-side Socket object based on the file descriptor
            mServerSocket = new LocalServerSocket(fd);
        } catch (IOException ex) {
            throw new RuntimeException("Error binding to local socket '" + fileDesc + "'", ex); }}}void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
    // List of file descriptors
    ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
    // List of Socket connections
    ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
	// Get the file descriptor word for the Socket and add it to the FDS
    fds.add(mServerSocket.getFileDescriptor());
    peers.add(null);
	// Wait indefinitely for AMS request
    while (true) {
        // Move the FDS stored information to the pollFds array
        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) {
                // The server Socket is connected to the client, that is, the current Zygote process is connected to AMS
                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                // Add to peers and FDS to receive requests from AMS.
                peers.add(newPeer);
                fds.add(newPeer.getFileDesciptor());
            } else {
                // AMS sends a request to Zygote to create an application process
                // Create a new application process
                boolean done = peers.get(i).runOnce(this);
                if (done) {
                    // The connection was created successfully and cleared from peers and FDS.
                    peers.remove(i);
                    fds.remove(i);
                }
            }
        }
    }
}
Copy the code

Important process summary:

  • registerServerSocketMethod: Create a server-side Socket that waits for AMS to request the Zygote process to create a new application process.
  • runSelectLoopMethod: wait indefinitely for AMS request, once there is a request, callZygoteConnectionrunOnceFunction to create a new application process.

3.2. Launch summary

  • The Init process passesinit.zygoteXX.rcFile that creates AppRuntime and calls itstartFunction to start the Zygote process.
  • AppRuntime Creates a Java virtual machine and registers JNI methods for the Java virtual machine.
  • AppRuntime calls Zygotelnit through JNImainMethod into the Java framework layer of Zygote.
  • Zygotelnit via ZygoteServerregisterZygoteSocketMethod to create a server-side Socket.
  • Zygotelnit preloads public classes and public resources.
  • Zygotelnit Starts the SystemServer process.
  • Zygotelnit via ZygoteServerrunSelectLoopMethod waits for AMS ‘request to create a new application process.


4. SystemServer processing

The SystemServer process is primarily used to create system services, such as AMS, WMS, and PMS.

Different versions, the code is slightly different, the overall process is not very different, the following code based on Android 8.0 source code

4.1. Start the SystemServer process

Zygotelnit. Java calls its startSystemServer method to start the SystemServer process.

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

private static boolean startSystemServer(String abiList, String socketName, ZygoteServer zygoteServer)
        throws Zygote.MethodAndArgsCaller, RuntimeException {
    / *... * /
    // The current code logic is running in a child process
    if (pid == 0) {
        if (hasSecondZygote(abiList)) {
            waitForSecondaryZygote(socketName);
        }
		// Close the Zygote process to fork the Socket, the Scoket is not useful to the SystemServer process
        zygoteServer.closeServerSocket();
        Start the SystemServer process
        handleSystemServerProcess(parsedArgs);
    }
    return true;
}
Copy the code

Call handleSystemServerProcess method to start the SystemServer process.

private static void handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs)
        throws Zygote.MethodAndArgsCaller {
	/ *... * /
    if(parsedArgs.invokeWith ! =null) {
        / *... * /
    } else {
        ClassLoader cl = null;
        if(systemServerClasspath ! =null) {
            // Create a PathClassLoader
            cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);
			// Set PathClassLoader to ContextClassLoader for the current thread
            Thread.currentThread().setContextClassLoader(cl);
        }
        // Pass the remaining parameters to SystemServer.ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl); }}public static final void zygoteInit(int targetSdkVersion, String[] argv,
        ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
    / *... * /
    RuntimeInit.commonInit();
    // Start the Binder thread pool with Native code so that SystemServer processes can communicate with other processes using Binder
    ZygoteInit.nativeZygoteInit();
    // Go to the SystemServer main method
    RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
Copy the code

4.1.1. Start Binder thread pools

NativeZygoteInit () corresponds to com_android_internal_os_ZygoteInit_nativeZygoteInit in androidRuntime.cpp:

frameworks/base/core/jni/AndroidRuntime.cpp

static AndroidRuntime* gCurRuntime = NULL;
static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
    // gCurRuntime points to AppRuntime, a subclass of AndroidRuntime
    gCurRuntime->onZygoteInit(a); }Copy the code

The AppRuntime class is defined in app_main.cpp.

frameworks/base/cmds/app_process/app_main.cpp

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

4.1.2. main method to start

RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader); The applicationInit static method of the RuntimeInit class is called to start the SystemServer process.

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

protected static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
        throws Zygote.MethodAndArgsCaller {
    / *... * /
    invokeStaticMain(args.startClass, args.startArgs, classLoader);
}

private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
        throws Zygote.MethodAndArgsCaller {
    / *... * /
        / / SystemServer class is obtained by reflection, the value of the className for com. Android. Server SystemServer
        cl = Class.forName(className, true, classLoader);
    / *... * /
        // Find the SystemServer main method
        m = cl.getMethod("main".new Class[] { String[].class });
    / *... * /
    Throw MethodAndArgsCaller and pass out the main method and parameters
    throw new Zygote.MethodAndArgsCaller(m, argv);
}
Copy the code

The code that catches the MethodAndArgsCaller exception is in the main method of Zygotelnit.java. The SystemServer main method is then called.

There are two reasons to throw an exception instead of calling main directly:

  • This throws an exception and clears all stack frames required by the setup process.
  • Let SystemServermainMethod looks like the entry method for the SystemServer process.
    • After Zygote started the SystemServer process, the SystemServer process has done a lot of preparatory work, and this work is in the SystemServermainBefore the method call.
    • This makes SystemServer’smainMethod does not look like an entry method for the SystemServer process.
    • This exception is thrown by zygotelnit.javamainMethod, will make SystemServermainMethod looks like the entry method for the SystemServer process.

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

public static void main(String argv[]) {
    ZygoteServer zygoteServer = new ZygoteServer();
	/ *... * /
    try {
        / *... * /
        if (startSystemServer) {
            / / start SystemServer process and capture the Zygote. MethodAndArgsCaller anomalies
            startSystemServer(abiList, socketName, zygoteServer);
        }
        Log.i(TAG, "Accepting command socket connections");
        zygoteServer.runSelectLoop(abiList);
        zygoteServer.closeServerSocket();
    } catch (Zygote.MethodAndArgsCaller caller) {
        // The SystemServer process completes initialization and calls the run method
        caller.run();
    } catch (Throwable ex) {
        Log.e(TAG, "System zygote died with exception", ex);
        zygoteServer.closeServerSocket();
        throwex; }}Copy the code

Zygote. MethodAndArgsCaller exception class is Zygote class of the static inner class.

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

public static class MethodAndArgsCaller extends Exception implements Runnable {
    private final Method mMethod;
    private final String[] mArgs;

    public MethodAndArgsCaller(Method method, String[] args) {
        mMethod = method;	// Method is the main method passed in
        mArgs = args;
    }

    public void run(a) {
        try {
            // Execute the SystemServer main method
            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 newRuntimeException(ex); }}}Copy the code

At this point SystemServer really starts executing the main method.

4.2. Parse the SystemServer process

To enter the SystemServer main method, just call the run method.

frameworks/base/services/java/com/android/server/SystemServer.java

public static void main(String[] args) {
    // Create the SystemServer object and execute the run method
    new SystemServer().run();
}

private void run(a) {
    / *... * /
    try {
        / *... * /
        // Set the time zone
        String timezoneProperty = SystemProperties.get("persist.sys.timezone");
        if(! isValidTimeZoneId(timezoneProperty)) {/ *... * /
            SystemProperties.set("persist.sys.timezone"."GMT");
        }

        // Set the language
        if(! SystemProperties.get("persist.sys.language").isEmpty()) {
            final String languageTag = Locale.getDefault().toLanguageTag();
            SystemProperties.set("persist.sys.locale", languageTag);
            SystemProperties.set("persist.sys.language"."");
            SystemProperties.set("persist.sys.country"."");
            SystemProperties.set("persist.sys.localevar"."");
        }

        / *... * /

        // Set the path to the virtual library file
        SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());

        // Clear the upper limit of memory growth
        VMRuntime.getRuntime().clearGrowthLimit();

        // Some devices rely on run-time fingerprint generation, so make sure it is defined before further booting.
        Build.ensureFingerprintProperty();

        // Set the environment variable access user condition
        Environment.setUserRequired(true);
        BaseBundle.setShouldDefuse(true);

        Parcel.setStackTraceParceling(true);

        // Set binder services to always run in the foreground
        BinderInternal.disableBackgroundScheduling(true);

        // Set the maximum number of binder thread pools
        BinderInternal.setMaxThreads(sMaxBinderThreads);

        / *... * /
        // Create message Looper
        Looper.prepareMainLooper();
        Looper.getMainLooper().setSlowLogThresholdMs(
                SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);

        SystemServiceRegistry.sEnableServiceNotFoundWtf = true;

        // Load the dynamic library libandroid_servers.so
        System.loadLibrary("android_servers");
        
        / *... * /

        // Start the system context
        createSystemContext();

        / *... * /

        // Create the SystemServiceManager object
        mSystemServiceManager = new SystemServiceManager(mSystemContext);
        mSystemServiceManager.setStartInfo(mRuntimeRestart, mRuntimeStartElapsedTime, mRuntimeStartUptime);
        LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
        SystemServerInitThreadPool.start();
        / *... * /
    } finally {
        / *... * /
    }

    / *... * /

    // Start various services
    try {
        t.traceBegin("StartServices");
        // Start the boot service
        startBootstrapServices(t);
        // Start the core service
        startCoreServices(t);
        // Start other services
        startOtherServices(t);
    } catch (Throwable ex) {
        Slog.e("System"."* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *");
        Slog.e("System"."************ Failure starting system services", ex);
        throw ex;
    } finally {
        t.traceEnd();
    }
	/ *... * /
    // Enter the Loop to process the message Loop
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}
Copy the code

The run method does the following:

  • Set the time, time zone, and language.
  • Set the path to the vm library filepersist.sys.dalvik.vm.lib.2.
  • setbinderMaximum number of threads in a thread pool.
  • Create a messageLooper.
  • loadinglibandroid_servers.soLibrary.
  • Start the context.
  • createSystemServiceManagerObject that is responsible for starting system services.
  • Boot services, core services, other services, they are allSystemServiceA subclass of class.
    • Bootstrap service:ActivityManagerService,PowerManagerService,PackageManagerServiceAnd so on.
    • Core Services:DropBoxManagerService,BatteryService,UsageStatsServiceWebViewUpdateService
    • Other Services:CameraService,AlarmManagerService,VrManagerServiceAnd so on.
  • openLooperMessage loop.

4.3. Launch summary

After the SystemServer process is created, its main tasks are as follows:

  • Start a Binder thread pool so that you can communicate with other processes.
  • Create SystemServiceManager, which creates, starts, and manages the life cycle of system services.
  • Start various system services.