Next: Android system startup process (2) — the startup process of Zygote process

Starting SystemServer process is a very important step in the Android system startup process. We are familiar with SystemServiceManager, AMS, WMS and other services are responsible for starting the SystemServer process. Therefore, it is necessary to understand the startup process of SystemServer.

1. Create the SystemServer process

The SystemServer process is started by the Zygote process by executing the main method of zygoteinit. Java:

Source path: \frameworks\base\core\ Java \com\android\internal\ OS \ zygoteinit.java

    public static void main(String argv[]) {...try{...boolean startSystemServer = false;
            String socketName = "zygote";
            String abiList = null;
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true;//1. If the parameter contains start-system-server, start SystemServer
                } else if ("--enable-lazy-preload".equals(argv[i])) {
                    enableLazyPreload = true;
                } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                    socketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: "+ argv[i]); }}...if (startSystemServer) {
                startSystemServer(abiList, socketName, zygoteServer);/ / 2. Start the SystemServer}... }catch (Zygote.MethodAndArgsCaller caller) {
            caller.run();
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            zygoteServer.closeServerSocket();
            throwex; }}Copy the code

If args contains the “start-system-server” field in comment 1, then SystemServer is started by calling the startSystemServer method in comment 2. Let’s look at the source code for the startSystemServer method:

    private static boolean startSystemServer(String abiList, String socketName, ZygoteServer zygoteServer)
            throws Zygote.MethodAndArgsCaller, RuntimeException {...int pid;

        try{...//1. Call the forkSystemServer method of Zygote to create 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);
        }

        /* If pid is 0, it is currently in SystemServer process */
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            zygoteServer.closeServerSocket();// Close the Socket copied from the Zygote process
            handleSystemServerProcess(parsedArgs);/ / 2. Call handleSystemServerProcess to initialize the SystemServer process
        }

        return true;
    }
Copy the code

The startSystemServer method is simple. In note 1, we create the SystemServer process by calling Zygote’s forkSystemServer. Then 2 out by calling handleSystemServerProcess to further SystemServer process for some of the initialization. Let’s look at the forkSystemServer source code first:

public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,
            int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
        VM_HOOKS.preFork();
        // Resets nice priority for zygote process.
        resetNicePriority();
        int pid = nativeForkSystemServer(
                uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);
        // Enable tracing as soon as we enter the system_server.
        if (pid == 0) {
            Trace.setTracingEnabled(true);
        }
        VM_HOOKS.postForkCommon();
        return pid;
    }

    native private static int nativeForkSystemServer(int uid, int gid, int[] gids, int debugFlags,
            int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
Copy the code

As you can see, the Native forkSystemServer method nativeForkSystemServer method is called in the forkSystemServer method to create the SystemServer process, The bottom layer of nativeForkSystemServer directly calls the fork method to create a new thread.

Look at the handleSystemServerProcess method, the source code is as follows:

    private static void handleSystemServerProcess( ZygoteConnection.Arguments parsedArgs)
            throws Zygote.MethodAndArgsCaller {...if(parsedArgs.invokeWith ! =null) {... }else {
            ClassLoader cl = null;
            if(systemServerClasspath ! =null) {
                / / 1. Create a PathClassLoader
                cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);

                Thread.currentThread().setContextClassLoader(cl);
            }

           //2. Call zygoteinit. ZygoteInit to initialize SystemServerZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl); }}Copy the code

Create a PathClassLoader in comment 1, then call ZygoteInit method in comment 2 to initialize SystemServer. ZygoteInit source code as follows:

Source path: \frameworks\base\core\ Java \com\android\internal\ OS \ zygoteinit.java

    public static final void zygoteInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
        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();/ / call nativeZygoteInit
        RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }

    private static final native void nativeZygoteInit(a);
Copy the code

In the zygoteInit method, the nativeZygoteInit method is called, and the nativeZygoteInit function is mainly used to start the Binder thread pool.

2. Enable the Binder thread pool

The corresponding C++ code for the nativeZygoteInit method is as follows:

Source location: \frameworks\base\core\jni\AndroidRuntime.cpp

static AndroidRuntime* gCurRuntime = NULL;

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

This method directly calls onZygoteInit on the gCurRuntime object, which is implemented by a subclass of AndroidRuntime called AppRuntime in the app_main. CPP file. Let’s look at AppRuntime’s onZygoteInit method:

Source path: \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");
        proc->startThreadPool(a); }Copy the code

The startThreadPool of ProcessState is also called in the onZygoteInit method. The source code for this method is as follows:

Source path: \frameworks\native\libs\binder\ processstate.cpp

void ProcessState::startThreadPool(a)
{
    AutoMutex _l(mLock);
    if(! mThreadPoolStarted) {//1. Check whether the thread pool is enabled
        mThreadPoolStarted = true;
        spawnPooledThread(true);//2. Call the spawnPooledThread method}}void ProcessState::spawnPooledThread(bool isMain)
{
    if (mThreadPoolStarted) {
        String8 name = makeBinderThreadName(a);//3. Create a Binder thread pool name
        ALOGV("Spawning new pooled thread, name=%s\n", name.string());
        sp<Thread> t = new PoolThread(isMain);//4. Create a thread pool object
        t->run(name.string());Run the thread pool}}String8 ProcessState::makeBinderThreadName(a) {
    int32_t s = android_atomic_add(1, &mThreadPoolSeq);/ / no. + 1
    pid_t pid = getpid(a);/ / get the pid
    String8 name;
    name.appendFormat("Binder:%d_%X", pid, s);//6. Splicing Binder thread pool names
    return name;
}
Copy the code

The method spawnPooledThread is called in comment 2 to create a thread with the parameter true.

The makeBinderThreadName method is used to create the name of the thread in comment 3. The code in comment 6 shows that all Binder threads in Android have names of “Binder:” + thread ID + “_” + thread number.

The first thread in the pool is created at comment 4, which is a PoolThread object. IsMain is true to indicate that this thread is the main thread of the pool, and the run method is called at comment 5 to run the thread.

Let’s look at the source code for PoolThread:

Source path: \frameworks\native\libs\binder\ processstate.cpp

class PoolThread : public Thread
{
public:
    explicit PoolThread(bool isMain)
        : mIsMain(isMain)
    {
    }
    
protected:
    virtual bool threadLoop(a)
    {
        IPCThreadState::self() - >joinThreadPool(mIsMain);
        return false;
    }
    
    const bool mIsMain;
};
Copy the code

As you can see from the above code, PoolThread inherits from the Thread class. When the run method of the PoolThread object is run, the threadLoop method of the PoolThread object is called, and the joinThreadPool method of the IPCThreadState object is called from the threadLoop method to add the thread to the Binder pool. At this point, SystemServer processes can communicate with other processes through Binder.

3. Create SystemServiceManager and various system services

Back to ZygoteInit. Java ZygoteInit method, after the call nativeZygoteInit to start a thread pool, again call RuntimeInit. ApplicationInit method, the method of code is as follows:

Source path: \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);//1. Invoke the invokeStaticMain method
    }

    private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
            throws Zygote.MethodAndArgsCaller { Class<? > cl;try {
            cl = Class.forName(className, true, classLoader);//2. Obtain the Java class corresponding to SystemServer
        } 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 });//3. Find the main method
        } 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);
        }

        /* * 4. Throw an exception that will eventually be caught in zygoteinit. main * use the method of throwing an exception to directly clean up all stack frames */
        throw new Zygote.MethodAndArgsCaller(m, argv);
    }
Copy the code

As you can see from note 1, the invokeStaticMain method is called within the applicationInit method, which, as we can guess from the name of the invokeStaticMain method, uses reflection primarily to call the SystemServer main method. In comment 2, the Java class corresponding to SystemServer is obtained by reflection, and in comment 3, the main method is found by reflection. But did not directly in the invokeStaticMain method to carry out the main method, but in April to throw an exception object Zygote. MethodAndArgsCaller, and will be the main method and relevant parameters are encapsulated in the exception object, This exception is eventually caught in the main method of zygoteinit. Java, as follows:

public static void main(String argv[]) {...try{...if(startSystemServer) { startSystemServer(abiList, socketName, zygoteServer); }... }catch (Zygote.MethodAndArgsCaller caller) {/ / 1. Capture Zygote. MethodAndArgsCaller anomalies
            caller.run();  //2. Call the run method of the exception object
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            zygoteServer.closeServerSocket();
            throwex; }}Copy the code

In note 1 out of capture to throw Zygote MethodAndArgsCaller anomaly, and then in 2 place calls the run method of the object, MethodAndArgsCaller source code is as follows:

Source path: \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;
            mArgs = args;
        }

        public void run(a) {
            try {
                mMethod.invoke(null.new Object[] { mArgs });// Execute the main method
            } 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

We can see that the run method of MethodAndArgsCaller is executed directly from mmethod. invoke, that is, the main method of SystemServer.

Source path: \frameworks\base\services\ Java \com\android\server\ systemserver.java

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

    private void run(a) {
        try{... Looper.prepareMainLooper();//1. Prepare a Looper for the main thread

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

            performPendingShutdown();

            createSystemContext();//2. Create the system context

            mSystemServiceManager = new SystemServiceManager(mSystemContext);/ / 3. Create SystemServiceManager
            mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart);
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
            SystemServerInitThreadPool.get();
        } finally {
            traceEnd();
        }

        // Start various services
        try {
            traceBeginAndSlog("StartServices");
            startBootstrapServices();//4. Start various boot services
            startCoreServices();//5. Start core services
            startOtherServices();//6. Enable other services
            SystemServerInitThreadPool.shutdown();
        } catch (Throwable ex) {
            Slog.e("System"."* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *");
            Slog.e("System"."************ Failure starting system services", ex);
            throw ex;
        } finally{ traceEnd(); }... Looper.loop();//7. Start the Loop
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
Copy the code

A SystemServer object is created in the main method and its run method is called directly.

Prepare Looper for the main thread by calling prepareMainLooper in note 1, create system context in note 2, and create SystemServiceManager object in note 3. This object is used to manage various services in the Android system.

Note 4, 5, 6 are starting various system services, system services in Android can be roughly divided into three categories:

  1. Bootloader services: ActivityManagerService(for managing the four components), PowerManagerService(for handling logic related to the phone’s power), PackageManagerService(for managing applications installed on the phone), etc
  2. Core services, such as BatteryService
  3. Other services: InputManagerService(for handling various input events), WindowManagerService(for managing Windows), etc

To see how these services are started using ActivityManagerService as an example, look at the startBootstrapServices source:

Source path: \frameworks\base\services\ Java \com\android\server\ systemserver.java

private void startBootstrapServices(a) {...// Activity manager runs the show.
        traceBeginAndSlog("StartActivityManager");

        // Create an ActivityManagerService by calling the startService method on the SystemServiceManager objectmActivityManagerService = mSystemServiceManager.startService( ActivityManagerService.Lifecycle.class).getService(); mActivityManagerService.setSystemServiceManager(mSystemServiceManager); mActivityManagerService.setInstaller(installer); traceEnd(); . }Copy the code

As you can see from the above code, ActivityManagerService is started by the startService method of the SystemServiceManager object. The startService method code looks like this:

    @SuppressWarnings("unchecked")
    public <T extends SystemService> T startService(Class<T> serviceClass) {
        try{...final T service;
            try {
                Constructor<T> constructor = serviceClass.getConstructor(Context.class);//1. Get the constructor of the service class to start
                service = constructor.newInstance(mContext);//2. Create service instances}... startService(service);//3. Call another overloaded method
            return service;
        } finally{ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); }}public void startService(@NonNull final SystemService service) {
        mServices.add(service);//4. Add the created service to the mServices list
        long time = System.currentTimeMillis();
        try {
            service.onStart();//5. Call the onStart method to start the service
        } catch (RuntimeException ex) {
            throw new RuntimeException("Failed to start service " + service.getClass().getName()
                    + ": onStart threw an exception", ex);
        }
        warnIfTooLong(System.currentTimeMillis() - time, service, "onStart");
    }
Copy the code

In comment 1, the constructor of the service to be started is obtained by reflection, and then a new instance is created in comment 2. Another overloaded method of startService is called at comment 3, and the created service is added to the list of mServices at comment 4. The service is started by calling the service’s onStart method in comment 5.

At this point, the startup process of SystemServer is almost complete.