[[374543]] This article is reprinted from the WeChat public account "Ma Shang Ji Mu", which can be followed through the following QR code. To reprint this article, please contact the WeChat public account "Ma Shang Ji Mu". Preface In the previous article, we talked about the startup process of the Android system. The first process forked by the Zygote process is the SystemServer process. This process is responsible for starting and managing the JavaFramework layer, that is, it provides many services of the framework layer, such as the well-known AMS, PMS, WMS, as well as DisplayManagerService, CameraService, etc. In other words, it holds the lifeline of the Android system and is the steward of the Android system. Let’s take a look together~ (The source code of this article is based on Android 9.0) Birth Previously, during the startup process of the Android system, it was mentioned that the SystemServer process was forked from the Zygote process. The fork() function creates a process that is almost identical to the original process through a system call. It can be understood as copying a process, and the new process is its child process. As for the birth of SystemServer, we have to start with the forkSystemServer method of ZygoteInit... (only keep the main code) - private static Runnable forkSystemServer(String abiList, String socketName,
- ZygoteServer zygoteServer) {
- //...
-
- // 1
- int pid;
- pid = Zygote.forkSystemServer(
- parsedArgs.uid, parsedArgs.gid,
- parsedArgs.gids,
- parsedArgs.runtimeFlags,
- null ,
- parsedArgs.permittedCapabilities,
- parsedArgs.effectiveCapabilities);
-
- /* For child process */
- if (pid == 0) {
- //2
- zygoteServer.closeServerSocket();
- //3
- return handleSystemServerProcess(parsedArgs);
- }
-
- return true ;
- }
-
- /**
- * Finish remaining work for the newly forked system server process.
- */
- private static Runnable handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {
-
- //...
-
- /*
- * Pass the remaining arguments to SystemServer.
- */
- ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
- }
-
-
- public static final Runnable zygoteInit( int targetSdkVersion, String[] argv, ClassLoader classLoader) {
- //...
-
- //4
- RuntimeInit.commonInit();
- //5
- ZygoteInit.nativeZygoteInit();
- //6
- return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
- }
In the startSystemServer method: - 1. Call the forkSystemServer method to create a child process - the SystemServer process.
- 2. After fork, it is determined whether the return value pid of fork is equal to 0. If it is equal to 0, it means that the fork is successful and it is in the SystemServer process. Then the Socket object brought from the Zygote process fork is closed.
- 3. Then the handleSystemServerProcess method is called, and finally it goes to zygoteInit to do some initialization work for the new process.
In the zygoteInit method: - 4. The commonInit method performs some common initialization work for the process, such as setting the time zone and resetting the log configuration.
- 5. The nativeZygoteInit method goes to the native layer through JNI. Its main task is to create a new Binder thread pool so that SystemServer can communicate with major app processes.
- 6. The applicationInit method will eventually go to the findStaticMain method, which calls the main method of the SystemServer class through reflection. Here is a simple code:
- protected static Runnable findStaticMain(String className, String[] argv,
- ClassLoader classLoader) {
- Class<?> cl;
-
- try {
- cl = Class.forName(className, true , classLoader);
- }
- //...
-
- Method m;
- try {
- m = cl.getMethod( "main" , new Class[] { String[].class });
- }
- //...
-
- return new MethodAndArgsCaller(m, argv);
- }
Work The SystemServer process is created and some initialization work is done. Next, we come to the main method. As the name suggests, we must start the main work. - public static void main(String[] args) {
- new SystemServer().run();
- }
-
-
- private void run() {
- try {
- //...
-
- // 1
- android.os.Process.setThreadPriority(
- android.os.Process.THREAD_PRIORITY_FOREGROUND);
- android.os.Process.setCanSelfBackground( false );
-
- Looper.prepareMainLooper();
- Looper.getMainLooper().setSlowLogThresholdMs(
- SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
-
- // 2
- System.loadLibrary( "android_servers" );
-
- // 3
- performPendingShutdown();
-
- // 4
- createSystemContext();
-
- // 5
- mSystemServiceManager = new SystemServiceManager(mSystemContext);
- mSystemServiceManager.setStartInfo(mRuntimeRestart,
- mRuntimeStartElapsedTime, mRuntimeStartUptime);
- LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
- // Prepare the thread pool for init tasks that can be parallelized
- SystemServerInitThreadPool.get();
- finally
- traceEnd();
- }
-
- //...
-
- // Start services.
- try {
- //6
- startBootstrapServices();
- //7
- startCoreServices();
- //8
- startOtherServices();
- SystemServerInitThreadPool.shutdown();
- }
-
- //...
-
- // Loop forever.
- Looper.loop();
- throw new RuntimeException( "Main thread loop unexpectedly exited" );
- }
- 1. Prepare the main thread, Looper.
- 2. Load the dynamic library.
- 3. Check whether the last shutdown process failed.
- 4. Initialize the system context.
- private void createSystemContext() {
- ActivityThread activityThread = ActivityThread.systemMain();
- mSystemContext = activityThread.getSystemContext();
- mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);
-
- final Context systemUiContext = activityThread.getSystemUiContext();
- systemUiContext.setTheme(DEFAULT_SYSTEM_THEME);
- }
In this method, the ActivityThread class is created, the context is obtained, and some system themes are set. - 5. Create SystemServiceManager for subsequent system service management creation and other tasks.
The last task of the run method is to start three types of services, which are also our focus, namely boot service, core service, and other services. There are more than 100 of these services, which are related to the entire Android application ecosystem. Let’s talk about them in detail below. - 6. Start the boot service
- private void startBootstrapServices() {
-
- //Install APK service
- traceBeginAndSlog( "StartInstaller" );
- Installer installer = mSystemServiceManager.startService(Installer.class);
- traceEnd();
-
- //AMS, responsible for the startup and scheduling of the four major components
- mActivityManagerService = mSystemServiceManager.startService(
- ActivityManagerService.Lifecycle.class).getService();
- mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
- mActivityManagerService.setInstaller(installer);
- traceEnd();
-
-
- // Management and display backlight LED and other services
- traceBeginAndSlog( "StartLightsService" );
- mSystemServiceManager.startService(LightsService.class);
- traceEnd();
-
- //PMS, responsible for APK installation, parsing and uninstallation, etc.
- traceBeginAndSlog( "StartPackageManagerService" );
- mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
- mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
- mFirstBoot = mPackageManagerService.isFirstBoot();
- mPackageManager = mSystemContext.getPackageManager();
- traceEnd();
-
- //...
-
- }
Among the guidance services, there are several that we are familiar with, such as AMS and PMS. - private void startCoreServices() {
- traceBeginAndSlog( "StartBatteryService" );
- // Manage battery related services
- mSystemServiceManager.startService(BatteryService.class);
- traceEnd();
-
- // Collect user usage time service
- traceBeginAndSlog( "StartUsageService" );
- mSystemServiceManager.startService(UsageStatsService.class);
- mActivityManagerService.setUsageStatsManager(
- LocalServices.getService(UsageStatsManagerInternal.class));
- traceEnd();
-
- // Webview update service
- if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
- traceBeginAndSlog( "StartWebViewUpdateService" );
- mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
- traceEnd();
- }
-
- //...
- }
- private void startOtherServices() {
- //...
-
- //Telephone management service
- traceBeginAndSlog( "StartTelephonyRegistry" );
- telephonyRegistry = new TelephonyRegistry(context);
- ServiceManager.addService( "telephony.registry" , telephonyRegistry);
- traceEnd();
-
-
- //WMS, window management service, is also a common
- traceBeginAndSlog( "StartWindowManagerService" );
- ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
- mSensorServiceStart = null ;
- wm = WindowManagerService.main(context, inputManager,
- mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
- !mFirstBoot, mOnlyCore, new PhoneWindowManager());
- ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false ,
- DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
- ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
- /* allowIsolated= */ false , DUMP_FLAG_PRIORITY_CRITICAL);
- traceEnd();
-
-
- // Input event management service
- traceBeginAndSlog( "StartInputManager" );
- inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
- inputManager.start();
- traceEnd();
-
- //...
- }
With so many services started, let's take a look at how the services are started: - public <T extends SystemService> T startService(Class<T> serviceClass) {
- try {
- final String name = serviceClass.getName();
-
- // Create the service.
- final T service;
- try {
- Constructor<T> constructor = serviceClass.getConstructor(Context.class);
- service = constructor.newInstance(mContext);
- } //...
- startService(service);
- return service;
- finally
- Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
- }
- }
-
- // A collection of all system services
- private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
-
- 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" );
- }
As you can see, the corresponding Service class is first created through reflection, and then the corresponding Service is added to the mServices collection to complete the registration. Then the onStart method is called to start the corresponding Service to complete the initialization work. At this point, the startup of SystemServer is complete. Let's review what happened in this process. - First, Zygote forks the SystemServer child process, then closes the original socket and creates a new Binder thread pool.
- Secondly, some initialization work was done, the Context object was created, and the SystemServiceManager class was created to manage all system services.
- Finally, three types of system services are started, namely boot services, core services and other services.
System knowledge extension Socket and Binder We noticed that after SystemServer was forked, it closed Sokcet and started the Binder thread pool for inter-process communication. The question is, why does the Zygote process use Socket communication, while the SystemServer process uses Binder for communication? Actually, these are two questions. The first question is why Android uses Binder process communication to obtain system services? This involves the knowledge of Binder. Binder was designed because it has two major advantages over other IPC methods: - High performance and high efficiency: Traditional IPC (sockets, pipes, message queues) requires copying memory twice, Binder only needs to copy memory once, and shared memory does not need to copy memory.
- Good security: The receiver can obtain the process ID and user ID of the sender from the data packet, which is convenient for verifying the identity of the sender. Other IPCs can only be actively stored if they want to experiment, but this may be modified during the sending process.
The second question is, why does the Zygote process use Socket communication instead of Binder? This is also a problem in wanAndroid: Daily Question | In the Activity startup process, most of the communication is done through Binder. Why do we need to use socket when communicating with Zygote? (https://www.wanandroid.com/wenda/show/10482) The comments section mainly has the following views: - ServiceManager cannot guarantee that it has been initialized when zygote starts, so Binder cannot be used.
- The owner of the socket is root, and only users with system permissions can read and write it, which provides additional security.
- Binder relies on multithreading to work, but multithreading is not allowed during forking. Process forking in multithreading is prone to deadlock, so Binder is not needed.
Binder thread pool What exactly is the Binder thread pool? Some readers have asked similar questions before. The Binder thread pool is located on the server side. Its main function is to forward the Binder requests of each business module to the remote Server for execution, thus avoiding the repeated creation of the Service. That is, there is only one server side, but it can handle Binder requests from multiple different clients. AMS, PMS, WMS During the startup of the SystemServer process, many system services are also started, including three services that interact more with applications: - AMS, ActivityManagerService, is responsible for the startup, switching, and scheduling of the four major components.
- PMS, PackageManagerService, is responsible for the installation, parsing, and uninstallation of APK.
- WMS, WindowManagerService, is responsible for window startup, adding, and deleting.
refer to 《Android Advanced Decryption》 https://www.wanandroid.com/wenda/show/10482 https://blog.csdn.net/yiranfeng/article/details/103550262 |