The system starts three processes init >zygote > system_server

init

  • Preparing the Android VIRTUAL machine environment: Create and mount the system file directory.

  • Initialize the property service;

  • Set the child’s signal handler (to prevent zombie processes from occurring in init’s child, and to receive and process signals when the child pauses and terminates);

    Zombie process: The parent uses fork to create a child if the child terminates without the parent knowing it has. Although the child has exited, its information is retained (process number). Exit the status. Running time, etc.). In this way, the system process table will be consumed for no reason and if it is exhausted, the system may not be able to create new processes.

  • Start the properties service and allocate memory to store properties: use a key-value pair (registry) to record some usage information of the user \ software (make sure that the system or software can be initialized based on the information in the registry after restart)

  • Parse the init.rc configuration file. Parse the init.zygote script file and start the Zygote process

In general, three things have been done:

  1. Create and mount the file directory required for system startup;
  2. Initialize and start property services;
  3. Parse the init.rc configuration file and start the Zygote process.

zygote

Init starts the Zygote process by calling the start method in the main function of app_main. CPP.DVM, ART, application processes, and SystemServer processes are all created with Zygote. Create a new application process by forking itself (from the Zygote process). Therefore, both the Zygote process and its children run the main function. The main function checks whether the main function is running in a Zygote process or a child process with a tag. If it is in a Zygote process, the start function of AppRuntime is called. In the start function, you create the Java virtual machine and do some other preparatory work. Finally, JNI calls the mian method in Zygoteinit. Java to enter the Java framework layer.

The main method does several things:

  1. Create a Server Socket to wait for AMS requests to create a new application process.
  2. Preloading classes and resources;
  3. Start the SystemServer process.
  4. Wait for AMS request to create a new application process (through an infinite loop while(true) waiting for AMS request).

In general, the Zygote process does the following:

  1. Create AppRuntime and call the start method to start zygote.
  2. Create a Java VIRTUAL machine, register JNI, call Java through JNI, enter the Java framework layer;
  3. Start server Socket and wait for AMS request to create application process;
  4. Start the SystemServer process.

SystemServer (zygote first started process)

SystemServer is mainly used to create system services, such as AMS, WMS are created by him. The Zygote process copies the address space of the Zygote process with the forkSystemServetr method and closes any Socket processes that are not needed by SystemServer. Then through handleSystemServerProcess method to start the process.

//ZygoteInit.java private static Runnable forkSystemServer(String abiList, String socketName, ZygoteServer zygoteServer) { String[] args = { "--setuid=1000", "--setgid=1000", "- setgroups = 1001100 2100 3100 4100 5100 6100 7100 8100 9101 0101 8102 1102 3," + 1024103 2106 5300 1300 2300 3300 6300 7300 9301 0301 1301 2 ", "-" capabilities = "+" capabilities + "," + capabilities, "--nice-name=system_server", "--runtime-args", "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT, "com.android.server.SystemServer", }; ZygoteArguments parsedArgs; 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); } catch (IllegalArgumentException e) { } int pid; try { //... /* 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); } if (pid == 0) { if (hasSecondZygote(abiList)) { waitForSecondaryZygote(socketName); } / / close the Zygote process creation Socket zygoteServer. CloseServerSocket (); return handleSystemServerProcess(parsedArgs); } return null; }Copy the code

Will start in handleSystemServerProcess approach, Binder thread pool, so SystemServer can use Binder and other process communication application process.

//ZygoteInit.java
    private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {
     ///
        if (parsedArgs.mInvokeWith != null) {
            //
        } else {
            return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
                    parsedArgs.mDisabledCompatChanges,
                    parsedArgs.mRemainingArgs, cl);
        }
    }
Copy the code
//ZygoteInit.java public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges, String[] argv, ClassLoader classLoader) { if (RuntimeInit.DEBUG) { Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote"); } Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit"); RuntimeInit.redirectLogStreams(); RuntimeInit.commonInit(); / / start Binder thread pool, through JNI call Native methods ZygoteInit. NativeZygoteInit (); / / into the main method of SystemServer return RuntimeInit. ApplicationInit (targetSdkVersion, disabledCompatChanges, argv, this); }Copy the code

Start the Binder thread pool, will call RuntimeInit. ApplicationInit:

//RuntimeInit.java
  protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {
       
        //
        final Arguments args = new Arguments(argv);
        return findStaticMain(args.startClass, args.startArgs, classLoader);
    }

Copy the code

Then call the findStaticMain method:

////RuntimeInit.java protected static Runnable findStaticMain(String className, String[] argv, ClassLoader classLoader) { Class<? > cl; Try {// Create SystemServer with reflection. cl = Class.forName(className, true, classLoader); } catch (ClassNotFoundException ex) { throw new RuntimeException( "Missing class when invoking static main " + className, ex); } Method m; M = cl.getMethod("main", new Class[] {String[].class}); } catch (NoSuchMethodException ex) { throw new RuntimeException( "Missing static main on " + className, ex); } catch (SecurityException ex) { throw new RuntimeException( "Problem getting static main on " + className, ex); } int modifiers = m.getModifiers(); if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) { throw new RuntimeException( "Main method is not public  and static on " + className); Return new MethodAndArgsCaller(m, argv); }Copy the code

As you can see, Systemserver is created by reflection, where the className is initialized in the variable arg of forkSystemServer in the zygoteinit. Java class. Then call Systemserver’s main method with MethodAndArgsCaller, Zygoteinit. mian is used to catch exceptions (because the SystemServer process does a lot of work before the main method is called, and if we throw an exception, it will clean up all stack frames. Makes SystemServer’s main look like it’s not an entry method to SystemServer), and the MethodAndArgsCaller code is very simple:

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

In ZygoteInit’s main method, there is a try statement that captures the exception.

In SystemServer, the key operations of the main method are as follows:

public static void main(String[] args) { new SystemServer().run(); } private void run() { // try { Looper.prepareMainLooper(); Looper.getMainLooper().setSlowLogThresholdMs( SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS); System.loadLibrary("android_servers"); createSystemContext(); } // // Start services. try { t.traceBegin("StartServices"); startBootstrapServices(t); // Start the boot service startCoreServices(t); // Start the core service startOtherServices(t); } catch (Throwable ex) {throw ex; } finally { t.traceEnd(); // StartServices } Looper.loop(); }Copy the code

SystemServer creates the message Looper, loads the library file, and creates the system Context. Then create and start various system services:

  1. Boot services: Installer, AMS, PMS, etc
  2. Core services: DropBoxManagerService, BatteryService, etc
  3. Other services: CameraService, WMS, etc

For example, start PowerStatsService using SystemServiceManager’s startService method. mSystemServiceManager.startService(PowerStatsService.class);

SystemServiceManager:Manages creating, starting, and other lifecycle events of SystemService system services

   //SystemServiceManager.java
   private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
   
   public <T extends SystemService> T startService(Class<T> serviceClass) {
        try {
            final String name = serviceClass.getName();
            final T service;
            try {
                Constructor<T> constructor = serviceClass.getConstructor(Context.class);
                service = constructor.newInstance(mContext);
            } catch (InvocationTargetException ex) {
                throw new RuntimeException("Failed to create service " + name
                        + ": service constructor threw an exception", ex);
            }

            startService(service);
            return service;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        }
    }

    public void startService(@NonNull final SystemService service) {
        // Register it.
        mServices.add(service);
        // Start it.
        long time = SystemClock.elapsedRealtime();
        try {
            service.onStart();
        } catch (RuntimeException ex) {
            throw new RuntimeException("Failed to start service " + service.getClass().getName()
                    + ": onStart threw an exception", ex);
        }
        warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
    }
Copy the code

Registration is completed by creating the Service and then adding it to an ArrayList. Finally, the start method of the service is called to start it.

The SystemServer process is created to do the following:

  1. Start a Binder thread pool for communicating with other processes.
  2. Create SystemServerManager for creating, starting, and managing system services;
  3. Start various services using SystemServerManager.

Responsible for pulling up more than 80 services such as AMS

     try {
            traceBeginAndSlog("StartServices");
            startBootstrapServices();
            startCoreServices();
            startOtherServices();
            SystemServerInitThreadPool.shutdown();
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        } finally {
            traceEnd();
        }
Copy the code

FinishBooting is responsible for sending the system boot completion broadcast

Fork an application from the Zygote process. If you fork an application from the Zygote process, you need to prepare a VM and preload the class file. If from the system_server App process does not need a large number of services (AMS, WMS, PMS and other more than 80 services)

The Launcher to start

The final step in starting your system is to launch an application, the Launcher, that displays the installed applications in your system. Generally speaking, it is the Android system desktop, which has the following two characteristics:

  1. As the initiator of the Android system, it is used to start applications.
  2. As an Android desktop, it is used to display and manage shortcut ICONS of applications and other desktop components.

During SystemServer startup, Ams (ActivityManagerService.) launched by it launches the Launcher. The Launcher entry is in SystemServer’s startOtherServices method:

//SystemServer.java
// We now tell the activity manager it is okay to run third party
// code. It will call back into us once it has gotten to the state
// where third party code can really run (but before it has actually
// started launching the initial applications), for us to complete our
// initialization.mActivityManagerService.systemReady(() -> { mSystemServiceManager.startBootPhase(t, SystemService.PHASE_ACTIVITY_MANAGER_READY); });Copy the code

According to the official comment, we can see that the system service is ready here, and the system can run the third party’s code. At this point, AMS’s systemReady method is called and AMS starts the Launcher. Below is ActivityManagerService. In Java systemReady method is the key to start the Launcher code:

public ActivityTaskManagerInternal mAtmInternal; public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) { synchronized (this) { mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady"); }}Copy the code

Among them, the mAtmInternal concrete implementation is: ActivityTaskManagerService. LocalService. In ActivityTaskManagerService is an inner class. ActivityTaskManagerService. LocalService. StartHomeOnAllDisplays code is as follows:

@Override public boolean startHomeOnAllDisplays(int userId, String reason) { synchronized (mGlobalLock) { return mRootActivityContainer.startHomeOnAllDisplays(userId, reason); }}Copy the code

RootActivityContainer. StartHomeOnAllDisplays code is as follows:

boolean startHomeOnAllDisplays(int userId, String reason) {
	 boolean homeStarted = false;
	 // 由于Android系统支持多用户和多显示,调用startHomeOnAllDisplays启动每个display上的Home Activity
        for (int i = mActivityDisplays.size() - 1; i >= 0; i--) {
            final int displayId = mActivityDisplays.get(i).mDisplayId;
            homeStarted |= startHomeOnDisplay(userId, reason, displayId);
        }
        return homeStarted;
}
Copy the code

Continue tracing the startHomeOnDisplay method:

boolean startHomeOnDisplay(int userId, String reason, int displayId) { return startHomeOnDisplay(userId, reason, displayId, false /* allowInstrumenting */, false /* fromHomeKey */); } boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean allowInstrumenting, boolean fromHomeKey) { if (displayId == INVALID_DISPLAY) { displayId = getTopDisplayFocusedStack().mDisplayId; } Intent homeIntent = null; ActivityInfo aInfo = null; If (displayId == DEFAULT_DISPLAY) {// First step: Access Intent / / here is mService ActivityTaskManagerService homeIntent = mService. GetHomeIntent (); aInfo = resolveHomeActivity(userId, homeIntent); } else if (shouldPlaceSecondaryHomeOnDisplay(displayId)) { Pair<ActivityInfo, Intent> info = resolveSecondaryHomeActivity(userId, displayId); aInfo = info.first; homeIntent = info.second; } if (aInfo == null || homeIntent == null) { return false; } if (! canStartHomeOnDisplay(aInfo, displayId, allowInstrumenting)) { return false; } homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name)); homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK); if (fromHomeKey) { homeIntent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, true); } final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId( aInfo.applicationInfo.uid) + ":" + displayId; / / the second step: start mService getActivityStartController () startHomeActivity (homeIntent aInfo, myReason, displayId); return true; }Copy the code

Among them, the first step to obtain Intent in ActivityTaskManagerService getHomeIntent method, the code is as follows: the Intent is to add the Intent. CATEGORY_HOME attributes

String mTopAction = Intent.ACTION_MAIN; Intent getHomeIntent() { Intent intent = new Intent(mTopAction, mTopData ! = null ? Uri.parse(mTopData) : null); intent.setComponent(mTopComponent); intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING); if (mFactoryTest ! Factorytest.factory_test_low_level) {// Return an Intent with Category intent.category_HOME intent.addCategory(Intent.CATEGORY_HOME); } return intent; }Copy the code

Next step 2, the startHomeActivity method is in ActivityStartController, and the key code goes as follows:

void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason, int displayId) { final ActivityOptions options = ActivityOptions.makeBasic(); options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN); if (! ActivityRecord.isResolverActivity(aInfo.name)) { options.setLaunchActivityType(ACTIVITY_TYPE_HOME); } options.setLaunchDisplayId(displayId); mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason) .setOutActivity(tmpOutRecord) .setCallingUid(0) .setActivityInfo(aInfo) .setActivityOptions(options.toBundle()) .execute(); / / start}Copy the code

Where the last execute is ultimately executed by ActivityStarter’s execute code:

/** * Starts an activity based on the request parameters provided earlier. * @return The starter result. */ int execute() { try { // TODO(b/64750076): Look into passing request directly to these methods to allow // for transactional diffs and preprocessing. if (mRequest.mayWait) { return startActivityMayWait(mRequest.caller, mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid, mRequest.realCallingUid, mRequest.intent, mRequest.resolvedType, mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo, mRequest.resultWho, mRequest.requestCode, mRequest.startFlags, mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig, mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId, mRequest.inTask, mRequest.reason, mRequest.allowPendingRemoteAnimationRegistryLookup, mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart); } else { return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent, mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo, mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo, mRequest.resultWho, mRequest.requestCode, mRequest.callingPid, mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid, mRequest.realCallingUid, mRequest.startFlags, mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.componentSpecified, mRequest.outActivity, mRequest.inTask, mRequest.reason, mRequest.allowPendingRemoteAnimationRegistryLookup, mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart); } } finally { onExecutionComplete(); }}Copy the code

StartActivity has three overloaded methods that, after repeated calls, end up calling: startActivity(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask, ActivityRecord[] outActivity, Boolean restrictedBgActivity)

private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask, ActivityRecord[] outActivity, boolean restrictedBgActivity) { try { mService.mWindowManager.deferSurfaceLayout(); result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, startFlags, doResume, options, inTask, outActivity, restrictedBgActivity); }}Copy the code

The general flow chart is as follows:

The next step is the creation of the process Launcher and Activity, which is no different from a normal application launch, as documented in the new notes.