“This is the fourth day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

When an Android phone starts up, it loads the boot program from ROM into RAM, initializes resources such as hardware parameters, and then loads the Linux kernel into RAM. The Kernel then starts the init ancestor process, in which configuration files such as init.rc are parsed, and zygote is started.

Because of the limited level, skip the Init process parsing init.rc. Look directly at the main() function in app_main.cpp called by the init process

Here is the main function for cpp_main.cpp. Check out the source code for app_main.cpp

Source code based on Android API31 


int main(int argc, char* const argv[])
{
    / /... Omit some code

    // You can see the following variables are controls to start zygote,systemServer flags
    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++];
        // Compare the process name with "--zygote"
        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; }}/ /... Part of the code is omitted
  
    // Main process.
    if (zygote) {
        Androidruntime.start () androidRuntime.start () androidRuntime.start ()
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
    / / start RuntimeInit
        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

** You can see that the main function ends up calling the Start method of androidRuntime. Let’s look at the androidRuntime start method

/* * 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)
{
  / /... Part of the code is omitted

    /* Start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) ! =0) {
        return;
    }
    onVmCreated(env);

    /* * Register android functions. */
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    } 
    

    /* * Call main on 'className' (RuntimeInit and ZygoteInit are called according to main in app_main. CPP) * Start VM. This thread becomes the  main thread of the VM, and will * not return until the VM exits. */
    char* slashClassName = toSlashClassName(className ! =NULL ? className : "");
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        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 {
            env->CallStaticVoidMethod(startClass, startMeth, strArray);

#if 0
            if (env->ExceptionCheck())
                threadExitUncaughtException(env);
#endif}}}Copy the code

Let’s go to the main method of ZygoteInit in our Java class

public static void main(String argv[]) {
        ZygoteServer zygoteServer = new ZygoteServer();
        / /...
        try {
            / /...
            if (startSystemServer) {
                Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
               / /...
            }
			/ /...
        } catch (Throwable ex) {
           / /...
        } finally {
           / /...
        }
		/ /...}}}Copy the code

As you can see, forkSystemServer is forked by the forkSystemServer method:

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

    int pid;

    try {
        ZygoteCommandBuffer commandBuffer = new ZygoteCommandBuffer(args);
        try {
      / /...
        pid = Zygote.forkSystemServer(
                parsedArgs.mUid, parsedArgs.mGid,
                parsedArgs.mGids,
                parsedArgs.mRuntimeFlags,
                null,
                parsedArgs.mPermittedCapabilities,
                parsedArgs.mEffectiveCapabilities);
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException(ex);
    }
/ /...

if (pid == 0) {
    if (hasSecondZygote(abiList)) {
        waitForSecondaryZygote(socketName);
    }

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

    return null; } Here are the forkSystemServer static methods in the Zygote classstatic int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
        int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
    ZygoteHooks.preFork();
    // As you can see, Zygote forked out the SystemServer process by calling the JNI native method
    int pid = nativeForkSystemServer(
            uid, gid, gids, runtimeFlags, rlimits,
            permittedCapabilities, effectiveCapabilities);
    / /...
    return pid;
}

Copy the code

In forkSystem the last line of code that can be found in the fork out after the child, the if (pid = = 0) is executed handleSystemServerProcess (parsedArgs)

private static Runnable handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {
        / /...
        if(parsedArgs.invokeWith ! =null) {
            / /...
        } else {
           / /...
            returnZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl); }}Copy the code

ZygoteInit is immediately followed by a call to ZygoteInit:

public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
        / /...
        return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }
// Then call findStaticMain
protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
        String[] argv, ClassLoader classLoader) {
  / /...
    returnfindStaticMain(args.startClass, args.startArgs, classLoader); } * *// The current className is SystemServer, so call SystemServer's Main method via JNI reflection:
**protected static Runnable findStaticMain(String className, String[] argv, ClassLoader classLoader) { Class<? > cl;//....

    return new MethodAndArgsCaller(m, argv);
}
Copy the code

Now look at the SystemServer main method

    public static void main(String[] args) {
        new SystemServer().run();
    }

	public SystemServer(a) {
        // Check factory test mode.
        mFactoryTestMode = FactoryTest.getMode();
        // Remember if it's runtime restart(when sys.boot_completed is already set) or reboot
        // Remember whether it is a runtime reboot (when sys.boot_completed is set) or a reboot
        mRuntimeRestart = "1".equals(SystemProperties.get("sys.boot_completed"));

        mRuntimeStartElapsedTime = SystemClock.elapsedRealtime();
        mRuntimeStartUptime = SystemClock.uptimeMillis();
    }
    
    
	private void run(a) {
        try {
         
            
            // If the device clock is before 1970, the value is reassigned to 1970
            if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
                SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
            }

            // If the time zone is not set, the default is Greenwich Mean Time (GMT).
            String timezoneProperty =  SystemProperties.get("persist.sys.timezone");
            if (timezoneProperty == null || timezoneProperty.isEmpty()) {
                SystemProperties.set("persist.sys.timezone"."GMT");
            }
            
            // Check the locale Settings
            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"."");
            }

            // The system server should not make non-one-way calls
            Binder.setWarnOnBlocking(true);
            // The system server should always load security labels
            PackageItemInfo.setForceSafeLabels(true);
            / / disable SQLiteCompatibilityWalFlags until initialization Settings provider
            SQLiteCompatibilityWalFlags.init(null);

            //---------- Enter the Android service -----------
            int uptimeMillis = (int) SystemClock.elapsedRealtime();
            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, uptimeMillis);
            if(! mRuntimeRestart) { MetricsLogger.histogram(null."boot_system_server_init", uptimeMillis);
            }

            // If the runtime has been switched since the last boot (e.g. when the old runtime was removed in the OTA), set the system properties to synchronize it
            SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());

            // More memory
            VMRuntime.getRuntime().clearGrowthLimit();

            // The system server must always be running, so memory needs to be used as efficiently as possible.
            VMRuntime.getRuntime().setTargetHeapUtilization(0.8 f);

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

            // In the system server, it is an error to access the environment path without explicitly specifying the user.
            Environment.setUserRequired(true);

            // In the system server, any incoming packages should be unlocked to avoid throwing BadParcelableException.
            BaseBundle.setShouldDefuse(true);

            // In the system server, stack traces are included when packaging exceptions occur
            Parcel.setStackTraceParceling(true);

            // Ensure that bound calls to the system always run at the foreground priority.
            BinderInternal.disableBackgroundScheduling(true);

            // Increase the number of binder threads in system_server
            BinderInternal.setMaxThreads(sMaxBinderThreads);

            // Prepare to create the main thread (the current thread).
            android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_FOREGROUND);
            android.os.Process.setCanSelfBackground(false);
            
            Looper.prepareMainLooper(); // Create main thread
            Looper.getMainLooper().setSlowLogThresholdMs(
                    SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);

            // Load the libandroid_Servers. so library
            System.loadLibrary("android_servers");

            // Check if we failed the last time we tried to close it
            performPendingShutdown();

            // Initialize the system context
            createSystemContext();

            / / create SystemServiceManager
            mSystemServiceManager = new SystemServiceManager(mSystemContext);
            mSystemServiceManager.setStartInfo(mRuntimeRestart, mRuntimeStartElapsedTime, mRuntimeStartUptime);
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);

            // Prepare thread pools for init tasks that can be parallelized
            SystemServerInitThreadPool.get();
        } finally {
            traceEnd();
        }

        // Start system services
        try {
            startBootstrapServices();
            startCoreServices();
            startOtherServices();
            SystemServerInitThreadPool.shutdown();
        } catch (Throwable ex) {
            throw ex;
        } finally {
            traceEnd();
        }

        / /...
        
        // Open the main thread, enter an infinite loop, processing various event messages
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
    
	Note slightly here that the global context is created with ActivityThread
	private void createSystemContext(a) {
        ActivityThread activityThread = ActivityThread.systemMain();
        mSystemContext = activityThread.getSystemContext();
        mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);

        final Context systemUiContext = activityThread.getSystemUiContext();
        systemUiContext.setTheme(DEFAULT_SYSTEM_THEME);
    }

Copy the code

The above run method can be roughly divided into the following steps:

PrepareMainLooper () is called to create the main thread, known as the UI thread, and then loads the android_Servers library. Initializing the system context object is followed by initializing various system services, such as: SystemServiceManager, ActivityServiceManager, WifiService, etc. finally call looper.loop () to start an infinite loop, To handle all kinds of event messages above is zygote process to SystemServer process.