Application process startup process
This article is based on Android 11. It mainly analyzes the application startup process and will directly locate the function start, because the content before the function is mainly in the Activity startup process, and can be read through this part of the article.
To see the source code process, you need to be cautious and have a good attitude. It is recommended to use the source code first, and read it on a whim after late at night.
By analyzing the startup process of the application process, you can obtain:
- In the Framework layer, there are not only AMS responsible for requesting the Zygote process to create a new process, but also ATMS, ActivityStarter, ActivityTaskManger, and ActivityTaskS are assisting in sharing some parameters and logic checks.
- Each process comes through the fork Zygote process and obtains a Java virtual machine. In other words, each application process has its own virtual machine.
- The application process requests the Zygote process fork itself through Soket.
- Each process has its own Binder thread pool for IPC.
- The main thread of each application process is in ActivityThread, and its main function will create a message loop mechanism.
1、
ATMS has a mProcessNames of type ProcessMap<WindowProcessController>, which is used to store WindowProcessController instances that encapsulate the startup process information ProcessRecord and window information Windows. WindowProcessController is used to coordinate the relationship between ActivityManger management ProcessReocrd and WindowManger management WIndow and Activity.
void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) { // Is this activity's application already running? final WindowProcessController wpc = (, ); boolean knownToBeDead = false; if (wpc != null && ()) { realStartActivityLocked(r, wpc, andResume, checkConfig); return; ... knownToBeDead = true; } (); final boolean isTop = andResume && (); (r, knownToBeDead, isTop, isTop ? "top-activity" : "activity"); }
The mService here is an instance of ActivityTaskManagerService. The current wpc object is obtained through the getProcessController function, and it is determined whether the current startup application process starts wpc != null && (). If the condition is true, start an unstarted activity and use realStartActivityLocked; if the condition does not hold, call mService's startProcessAsync to start the process where the current activity is located. That is, the startSpecificActivity function is a dividing point between starting the process and starting the Activity.
2、
The function is the calling method of Lambda, which means calling the startProcess function of ActivityManagerInternal, and then its parameters. And return a Message object and send it to the mH of type Handler.
void startProcessAsync(ActivityRecord activity, boolean knownToBeDead, boolean isTop, String hostingType) { final Message m = (ActivityManagerInternal::startProcess, mAmInternal, , , knownToBeDead, isTop, hostingType, ()); (m); }
The inheritance class of the abstract class ActivityManagerInternal is defined in the internal class LocalService of the ActivityManagerService.
public final class LocalService extends ActivityManagerInternal
3、
@Override public void startProcess(String processName, ApplicationInfo info, boolean knownToBeDead, boolean isTop, String hostingType, ComponentName hostingName) { startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */, new HostingRecord(hostingType, hostingName, isTop), ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE, false /* allowWhileBooting */, false /* isolated */, true /* keepIfLarge */); }
4. startProcessLocked function
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting, boolean isolated, boolean keepIfLarge) { return (processName, info, knownToBeDead, intentFlags, hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge, null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */, null /* crashHandler */); }
5、
The startProcessLocked function of the ProcessList class has several overloaded functions, the first one is called.
exist ! isolated, determine whether the startup IntentFlag is running in the background. If yes, reject it directly. Otherwise, clean up the process (current application) that has occurred in AMS.
Analysis 1: Description of creating the current application process ProcessRecord.
To determine whether the current system has been started or not, cache the process information to the mProcessesOnHold of AMS.
Analysis 2: Another overloaded function was called.
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge, String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) { long startTime = (); ProcessRecord app; //isolated is passed in false. if (!isolated) { //Fetch from mProcessNames cache, since it is the first time it is created, null app = getProcessRecordLocked(processName, , keepIfLarge); checkSlow(startTime, "startProcess: after getProcessRecord"); //Judge whether the process to be started is running in the background, and directly return null if ((intentFlags &amp; Intent.FLAG_FROM_BACKGROUND) != 0) { if ((info)) { return null; } } else { //Reset the crash state of the process to make it in a normal state (info); if ((info)) { (info); if (app != null) { = false; } } } } else { app = null; } ProcessRecord precedence = null; if (app != null &amp;&amp; &gt; 0) { if ((!knownToBeDead &amp;&amp; !) || == null) { (, , ); return app; } (, ); precedence = app; app = null; } if (app == null) { // Analysis 1. Create a new application process description ProcessRocrd //Internally, it will add itself to mProcessNames app = newProcessRecordLocked(info, processName, isolated, isolatedUid, hostingRecord); if (app == null) { return null; } //At this time, all three are null = crashHandler; = entryPoint; = entryPointArgs; if (precedence != null) { = precedence; = app; } } else { (, , ); } // If the system is not ready yet, then hold off on starting this // process until it is. if (! &amp;&amp; !(info) &amp;&amp; !allowWhileBooting) { if (!(app)) { (app); } if (DEBUG_PROCESSES) (TAG_PROCESSES, "System not ready, putting on hold: " + app); checkSlow(startTime, "startProcess: returning with proc on hold"); return app; } Analysis 2: final boolean success = startProcessLocked(app, hostingRecord, zygotePolicyFlags, abiOverride); checkSlow(startTime, "startProcess: done starting proc!"); return success ? app : null; }
6. Reload
Call another overloaded function again.
final boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord, int zygotePolicyFlags, String abiOverride) { return startProcessLocked(app, hostingRecord, zygotePolicyFlags, false /* disableHiddenApiChecks */, false /* disableTestApiChecks */, false /* mountExtStorageFull */, abiOverride); }
Overload function. This overload function has a long processing logic and mainly sets various properties for the ProcessRecord type app created earlier. For example, external storage mount mode, application process operation mode, abi architecture, etc. The most important point is to analyze 1 and determine the class name to start the process:. Analysis 2, continue to call the overloaded function.
boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord, int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean disableTestApiChecks, boolean mountExtStorageFull, String abiOverride) { ... = gids; (requiredAbi); = instructionSet; final String seInfo = + (() ? "" : ); //Analysis 1: Determine the class name to start the application final String entryPoint = ""; //Analysis 2: Call another overloaded function return startProcessLocked(hostingRecord, entryPoint, app, uid, gids, runtimeFlags, zygotePolicyFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith, startTime); } catch (RuntimeException e) { ... } }
Overloading function: also set some properties and then call the startProcess function.
boolean startProcessLocked(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 startResult = startProcess(hostingRecord, entryPoint, app, uid, gids, runtimeFlags, zygotePolicyFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith, startTime); handleProcessStartedLocked(app, , , startSeq, false); ... } }
7、
The startProcess function of the ProcessList class will judge the different creation branches based on the hostingRecord property mHostingZygote. The previous creation uses the default value, so the else branch is gone. Create a new application process through functions.
Calling all the way:
=>=>=>
8、
The startViaZygote function mainly splices the passed in parameters into strings and collects them. where processClass is
private startViaZygote(...) throws ZygoteStartFailedEx { //According to the passed parameters, splice into strings and collect ArrayList<String> type argsForZygote // Will be used as the parameter of the main function of the new application return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), zygotePolicyFlags, argsForZygote); }
9、
The first parameter of zygoteSendArgsAndGetResult calls the openZygoteSocketIfNeeded function. Try to establish a connection to the Socket (if not established before). We know that during the creation process of Zygote process, it will call the runSelectLoop function to create the Socket on the Server side, and wait for the Socket creation process request from the AMS Client side.
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx { try { // Establish a Socket connection with Zygote attemptConnectionToPrimaryZygote(); //Match abi's architecture. The creation of Zygote corresponds to four modes: 32, 32_64 and 64, 64_32 //32,64 if ((abi)) { return primaryZygoteState; } //The main architectural pattern does not match, match the second type 32_64,64_32 if (mZygoteSecondarySocketAddress != null) { // The primary zygote didn't match. Try the secondary. attemptConnectionToSecondaryZygote(); if ((abi)) { return secondaryZygoteState; } } } catch (IOException ioe) { throw new ZygoteStartFailedEx("Error connecting to zygote", ioe); } throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi); }
attemptConnectionToPrimaryZygote function mainly creates Socket connections with Zygote process through the underlying LocalSocket, and obtains the input stream zygoteInputStream and the output stream zygoteOutputWriter.
private void attemptConnectionToPrimaryZygote() throws IOException { if (primaryZygoteState == null || ()) { primaryZygoteState = (mZygoteSocketAddress, mUsapPoolSocketAddress); maybeSetApiBlacklistExemptions(primaryZygoteState, false); maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState); } }
After establishing a connection with the server Socket of the Zygote process, it starts writing data to the Socket.
10、attemptZygoteSendArgsAndGetResult
Go back to step 8 and call the zygoteSendArgsAndGetResult function, and call the attemptZygoteSendArgsAndGetResult function.
zygoteSendArgsAndGetResult=>attemptZygoteSendArgsAndGetResult
11、attemptZygoteSendArgsAndGetResult
At this point, the parameters spliced before are written to the Zygote process through Socket. After Zygote receives data, it will perform the creation action. Returning >=0 means the creation is successful and run in a new process.
private attemptZygoteSendArgsAndGetResult( ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx { try { final BufferedWriter zygoteWriter = ; final DataInputStream zygoteInputStream = ; (msgStr); (); result = new (); = (); = (); if ( < 0) { throw new ZygoteStartFailedEx("fork() failed"); } return result; } catch (IOException ex) { (); (LOG_TAG, "IO Exception while communicating with Zygote - " + ()); throw new ZygoteStartFailedEx(ex); } }
12、
In the Zygote startup process, the main function of ZygoteInit is called. Because Zygote creates other processes through fork itself, it is necessary to determine what type of process it is started based on the passed parameters, such as its own isPrimaryZygote=true, or SystemServer process. Then, through the function, wait for other processes to request to create a new process.
public static void main(String argv[]) { ZygoteServer zygoteServer = null; Runnable caller; try { ... boolean startSystemServer = false; String zygoteSocketName = "zygote"; String abiList = null; boolean enableLazyPreload = false; for (int i = 1; i &lt; ; i++) { if ("start-system-server".equals(argv[i])) { startSystemServer = true; //Judge whether the SystemServer process } 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)) { //SCOKET_NAME_ARG="--socket-name=", obtain SocketName according to the parameters zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length()); } else { throw new RuntimeException("Unknown command line argument: " + argv[i]); } } //PRIMARY_SOCKET_NAME=zygote final boolean isPrimaryZygote = (Zygote.PRIMARY_SOCKET_NAME); gcAndFinalize(); (isPrimaryZygote); (); zygoteServer = new ZygoteServer(isPrimaryZygote); if (startSystemServer) { //Start the SystemServer process Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer); if (r != null) { (); return; } } //Longly wait for the AMS to request to create a new process caller = (abiList); } catch (Throwable ex) { (TAG, "System zygote died with exception", ex); throw ex; } finally { if (zygoteServer != null) { (); } } //Calling the new process main function if (caller != null) { (); } }
13、
Here we only focus on functions and accept Socket client data.
/** * 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. */ Runnable runSelectLoop(String abiList) { while (true) { ... ZygoteConnection connection = (pollIndex); final Runnable command = (this); ... if (mIsForkChild) { return command; } .... } }
14、
runSelctLoop mainly detects whether there is a connection establishment from the loop. After establishment, the processOneCommand function of ZygoteConnection is executed and a command object of Runable type is returned.
Runnable processOneCommand(ZygoteServer zygoteServer) { ... args = (mSocketReader); //Document other types of processing based on the parameter content ... //Create a process, call the underlying nativeForkAndSpecialize method, and create a child thread by fork the current process. pid = (, , , , rlimits, , , , fdsToClose, fdsToIgnore, , , , , , , , ); ... if (pid == 0) { //Set mIsForkChild=true (); //Close Socket connection (); (serverPipeFd); serverPipeFd = null; //Execute child process content return handleChildProc(parsedArgs, childPipeFd, ); } ... }
15、handleChildProc
handleChildProc function.
private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor pipeFd, boolean isZygote) { ... if (!isZygote) { return (, , , null /* classLoader */); } else { return (, , null /* classLoader */); } }
16、
public static final Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges, String[] argv, ClassLoader classLoader) { (); ();//Create a Binder thread pool for a new process return (targetSdkVersion, disabledCompatChanges, argv, classLoader); }
I used to think that each process shared a Binder thread pool, but now I know that each process has its own Binder thread pool for IPC.
17、
protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges, String[] argv, ClassLoader classLoader) { final Arguments args = new Arguments(argv); return findStaticMain(, , classLoader); }
Here is what is passed on by the Socket client.
18、
Functions mainly create an instance of the ActivityThread class through reflection, reflect the main function main, and then encapsulate it into the MethodAndArgsCaller instance to return.
protected static Runnable findStaticMain(String className, String[] argv, ClassLoader classLoader) { ... Class<?> cl = (className, true, classLoader); Method m = ("main", new Class[] { String[].class }); ... return new MethodAndArgsCaller(m, argv); }
The MethodAndArgsCaller class inherits from Runable and calls the main function method in its run function.
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() { ... (null, new Object[] { mArgs }); ... } }
As the findStaticMain function method stack returns all the way to the runSelectLoop function, since mIsForkChild is true, the MethodAndArgsCaller object returns to the main function of ZygoteInit and is assigned to the caller variable. The main function finally calls the caller's run function. That is, the main function main of ActivityThread is executed.
I had a doubt that after the fork child process and the caller run function has exited the runSelectLoop loop waiting of the Zygote process. How to continue to receive new AMS requests. So that's it. After fork the child process, the subsequent code is run in the child process. Here, return is actually the child process.
After a process calls the fork() function, the system first allocates resources to the new process, such as space to store data and code. Then copy all the values of the original process into the new process, and only a few values are different from the values of the original process. It's equivalent to cloning oneself.
19. Process.
public static void main(String[] args) { (); ActivityThread thread = new ActivityThread(); (false, startSeq); if (sMainThreadHandler == null) { sMainThreadHandler = (); } (); }
The main function of ActivityThread creates the ActivityThread process and starts the message loop queue, which means that the main thread of the current process has been started.
Knowledge points
- fork function.
- Create a new process through Socket.
- Binder mechanism and timing of application creation.
- ActivityThread's main thread of the process.
Points of doubt
- The child processes that come from the Zygote process fork will obtain the Java virtual machine created by Zygote, that is, each application process has its own Java virtual machine.
- Each application process has its own Binder thread pool and message loop mechanism.
- The reason fork Zygote process rather than init process is to avoid repeated initialization of environmental resources and creation of virtual machines.
- The Socket mechanism is selected for the creation of the process, because the Binder mechanism will cause deadlocks. I am afraid that the parent binder thread will have a lock, and the main thread of the child process will be waiting for the resources of its child thread (the child process copied from the parent process), but in fact, the child process of the parent process is not copied, causing deadlocks.Fork does not allow multi-threading。
The above is a detailed explanation of the Android application startup process example. For more information about the Android program startup process, please follow my other related articles!