After the Android system is started, the first Android application Launcher will be started. Then start other applications under user operation. The two processes are roughly the same. This paper mainly analyzes the startup process of launching Launcher.
Android system source code version: 9.0 0_ r3
The overall flow chart is as follows:
Zygote startup process
After the Android Kernel is started, start the first process init, which will resolve init. * RC file starts the process zygote.
/system/core/rootdir/init.zygote32_64.rc
1 service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote 2 class main 3 priority -20 4 user root 5 group root readproc reserved_disk 6 socket zygote stream 660 root system 7 onrestart write /sys/android_power/request_state wake 8 onrestart write /sys/power/state on 9 onrestart restart audioserver 10 onrestart restart cameraserver 11 onrestart restart media 12 onrestart restart netd 13 onrestart restart wificond 14 writepid /dev/cpuset/foreground/tasks 15 16 service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary 17 class main 18 priority -20 19 user root 20 group root readproc reserved_disk 21 socket zygote_secondary stream 660 root system 22 onrestart restart zygote 23 writepid /dev/cpuset/foreground/tasks
init started app_process32 or app_ The process64 and -- zygote parameters indicate that the zygote process is started. App here_ process32,app_process64 represents a 32-bit zygote process and a 64 bit zygote process. It is used for compatible application startup with a 32-bit so library. In fact, we can use app in Android environment_ Success * runs a java bytecode file in Dalvik format, just like running bytecode in java on a desktop.
After zygote is started, it will complete the creation of ART virtual machine and run com android. internal. os. ZygoteInit. The key contents are as follows
/frameworks/base/cmds/app_process/app_main.cpp
349 if (zygote) { 350 runtime.start("com.android.internal.os.ZygoteInit", args, zygote); 351 } else if (className) { 352 runtime.start("com.android.internal.os.RuntimeInit", args, zygote); 353 } else { 354 fprintf(stderr, "Error: no class name or --zygote supplied.\n"); 355 app_usage(); 356 LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); 357 }
On COM android. internal. os. Zygoteinit will complete the loading of key Java class files of the Framework in the Android environment. Create a local socket, manage it with ZygoteServer, and create a sub process system through fork call_ Server process. Turn on the listening function of the local socket ZygoteServer, that is, run the runSelectLoop method to listen for new sockets or read-write events.
/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
750 public static void main(String argv[]) { 751 ZygoteServer zygoteServer = new ZygoteServer(); 752 //..... Delete irrelevant codes 832 if (startSystemServer) { 833 Runnable r = forkSystemServer(abiList, socketName, zygoteServer); 834 835 // {@code r == null} in the parent (zygote) process, and {@code r != null} in the 836 // child (system_server) process. 837 if (r != null) { 838 r.run(); 839 return; 840 } 841 } 842 843 Log.i(TAG, "Accepting command socket connections"); 844 845 // The select loop returns early in the child process after a fork and 846 // loops forever in the zygote. 847 caller = zygoteServer.runSelectLoop(abiList); 848 } catch (Throwable ex) { 849 Log.e(TAG, "System zygote died with exception", ex); 850 throw ex; 851 } finally { 852 zygoteServer.closeServerSocket(); 853 } 854 855 // We're in the child process and have exited the select loop. Proceed to execute the 856 // command. 857 if (caller != null) { 858 caller.run(); 859 } 860 }
Here, the local socket, namely UDS(Unix Domain Socket), is actually a way of inter process communication. For example, in Nginx and MySQL, UDS is used for inter process communication. Android has more interprocess communication than Linux, and Binder has more interprocess communication. This article will not explain Binder in detail. Just know that Binder is actually used for communication between two different processes. It is not fundamentally different from pipeline, semaphore and UDS.
system_server process startup process
system_ The server process will call com android. server. Systemserver and systemnserver will start various important services. The code is as follows
/frameworks/base/services/java/com/android/server/SystemServer.java
// Start services. 427 try { 428 traceBeginAndSlog("StartServices"); 429 startBootstrapServices(); 430 startCoreServices(); 431 startOtherServices(); 432 SystemServerInitThreadPool.shutdown(); 433 } catch (Throwable ex) { 434 Slog.e("System", "******************************************"); 435 Slog.e("System", "************ Failure starting system services", ex); 436 throw ex; 437 } finally { 438 traceEnd(); 439 }
The services started include ActivityManagerService, WindowManagerService, PackageManagerService, InputManagerService, Bluetooth managerservice and other service classes.
PackageManagerService will resolve the installed applications on the mobile phone, such as Apk installation location, Manifest information, resource file, class file path, etc.
system_ After server is launched, it calls the systemReady method of AMS, sends the Intent that starts Launcher, PMS will find the installation path of Launcher, and call startProcess of AMS. After a series of calls, startprocess finally uses UDS to communicate with zygote process and send corresponding commands to let zygote create child processes. AMS puts the returned child process pid and the associated app information into the mPidsSelfLocked member variable. The code is as follows
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
4530 private boolean handleProcessStartedLocked(ProcessRecord app, int pid, boolean usingWrapper, 4531 long expectedStartSeq, boolean procAttached) { 4532 //Omit a lot of code 4598 synchronized (mPidsSelfLocked) { 4599 this.mPidsSelfLocked.put(pid, app); 4600 if (!procAttached) { 4601 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG); 4602 msg.obj = app; 4603 mHandler.sendMessageDelayed(msg, usingWrapper 4604 ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT); 4605 } 4606 } 4607 checkTime(app.startTime, "startProcess: done updating pids map"); 4608 return true; 4609 }
Application process startup process
Here, when the local socket of ZygoteServer listens to a message, it will fork a new sub process, which inherits the resources of zygote process, such as the created ART virtual machine, which can speed up the creation and startup of applications.
The key codes are as follows
/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
123 Runnable processOneCommand(ZygoteServer zygoteServer) { 124 String args[]; 125 Arguments parsedArgs = null; 126 FileDescriptor[] descriptors; 127 128 try { 129 args = readArgumentList(); 130 descriptors = mSocket.getAncillaryFileDescriptors(); 131 } catch (IOException ex) { 132 throw new IllegalStateException("IOException on command socket", ex); 133 } 134 //Delete irrelevant code 146 parsedArgs = new Arguments(args); 147 148 231 232 fd = null; 233 234 pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, 235 parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, 236 parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote, 237 parsedArgs.instructionSet, parsedArgs.appDataDir); //Delete irrelevant code 238 240 if (pid == 0) { 241 // in child 242 zygoteServer.setForkChild(); 243 244 zygoteServer.closeServerSocket(); 245 IoUtils.closeQuietly(serverPipeFd); 246 serverPipeFd = null; 247 248 return handleChildProc(parsedArgs, descriptors, childPipeFd, 249 parsedArgs.startChildZygote); 250 } else { 251 // In the parent. A pid < 0 indicates a failure and will be handled in 252 // handleParentProc. 253 IoUtils.closeQuietly(childPipeFd); 254 childPipeFd = null; 255 handleParentProc(pid, descriptors, serverPipeFd); 256 return null; 257 } 258 262 }
Other processes will be resolved in the child process The parameter sent by (system_server) runs the specified class. Usually, this class is ActivityThread, and this sub process is our newly started application process. At present, this process does not know where to load the byte code and resource file corresponding to the application. After the ActivityThread is started, it will carry out inter process communication (Binder) with system_server and call AMS related functions. The code is as follows:
6478 private void attach(boolean system, long startSeq) { 6479 sCurrentActivityThread = this; 6480 mSystemThread = system; 6481 if (!system) { 6482 ViewRootImpl.addFirstDrawHandler(new Runnable() { 6483 @Override 6484 public void run() { 6485 ensureJitEnabled(); 6486 } 6487 }); 6488 android.ddm.DdmHandleAppName.setAppName("<pre-initialized>", 6489 UserHandle.myUserId()); 6490 RuntimeInit.setApplicationObject(mAppThread.asBinder()); 6491 final IActivityManager mgr = ActivityManager.getService(); 6492 try { 6493 mgr.attachApplication(mAppThread, startSeq); 6494 } catch (RemoteException ex) { 6495 throw ex.rethrowFromSystemServer(); 6496 }
At line 6493, the ActivityThread calls Mgr attachApplication, because Binder mechanism will call attachApplication method of AMS.
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@Override 7932 public final void attachApplication(IApplicationThread thread, long startSeq) { 7933 synchronized (this) { 7934 int callingPid = Binder.getCallingPid(); 7935 final int callingUid = Binder.getCallingUid(); 7936 final long origId = Binder.clearCallingIdentity(); 7937 attachApplicationLocked(thread, callingPid, callingUid, startSeq); 7938 Binder.restoreCallingIdentity(origId); 7939 } 7940 }
The attachApplication method will obtain the pid of the starting process, find the information of the program to be started in mPidsSelfLocked through pid, send the information of the program to be started to the application process through Binder inter process communication (i.e. iaapplicationthread related methods), and the application process will load the corresponding classes.
After the application process is loaded, inform AMS that AMS will control the application process to start the Activity. Then AMS issues a command, the application process executes, and inform AMS after execution. The application process is restricted by AMS like a string puppet. (the current plug-in technology is to Hook off the corresponding interface and deceive AMS to complete the loading of the four components in the plug-in, that is, it is often said to deceive the top and deceive the bottom)
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
private final boolean attachApplicationLocked(IApplicationThread thread, 7573 int pid, int callingUid, long startSeq) { 7574 7575 // Find the application record that is being attached... either via 7576 // the pid if we are running in multiple processes, or just pull the 7577 // next app record if we are emulating process with anonymous threads. 7578 ProcessRecord app; 7579 long startTime = SystemClock.uptimeMillis(); 7580 if (pid != MY_PID && pid >= 0) { 7581 synchronized (mPidsSelfLocked) { 7582 app = mPidsSelfLocked.get(pid); 7583 } 7584 } else { 7585 app = null; 7586 } 7587 7588 // It's possible that process called attachApplication before we got a chance to 7589 // update the internal state. 7590 if (app == null && startSeq > 0) { 7591 final ProcessRecord pending = mPendingStarts.get(startSeq); 7592 if (pending != null && pending.startUid == callingUid 7593 && handleProcessStartedLocked(pending, pid, pending.usingWrapper, 7594 startSeq, true)) { 7595 app = pending; 7596 } 7597 } 7598 7599 if (app == null) { 7600 Slog.w(TAG, "No pending application record for pid " + pid 7601 + " (IApplicationThread " + thread + "); dropping process"); 7602 EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid); 7603 if (pid > 0 && pid != MY_PID) { 7604 killProcessQuiet(pid); 7605 //TODO: killProcessGroup(app.info.uid, pid); 7606 } else { 7607 try { 7608 thread.scheduleExit(); 7609 } catch (Exception e) { 7610 // Ignore exceptions. 7611 } 7612 } 7613 return false; 7614 }