Android source code analysis directory

(Note: The following code analysis is based on Android-10.0.0_R30)

An overview of

Zygote starts SystemServer Zygote starts SystemServer Zygote starts SystemServer Zygote starts SystemServer Zygote starts SystemServer Zygote

Source directory

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
frameworks/base/services/java/com/android/server/SystemServer.java
Copy the code

Start the SystemServer

ForkSystemServer is a method that has been explained in the Zygote startup tutorial. Here we will focus on two methods

  1. forkSystemServer
  2. handleSystemServerProcess

[ZygoteInit.java]

private static Runnable forkSystemServer(String abiList, String socketName, ZygoteServer zygoteServer) { ... Try {// method 1 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); } zygoteServer.closeServerSocket(); / / method 2 return handleSystemServerProcess (parsedArgs); } return null; }Copy the code

The first is method 1: this is a native method that ends up calling the Native layer, ForkCommon, and binding SystemServer’s life and death to Zygote.

Then there is method 2: this method handles something after the SystemServer process has been created

2.1 handleSystemServerProcess

[ZygoteInit.java]

Private static Runnable handleSystemServerProcess (ZygoteArguments parsedArgs) {/ / set the permissions Os. The umask (S_IRWXG | S_IRWXO); . // Find SystemServer ClassPath final String systemServerClasspath = os.getenv (" systemServerClasspath "); if (systemServerClasspath ! = null) { ... } if (parsedArgs.mInvokeWith ! = null) { ... } else {/ / build cl createSystemServerClassLoader (); ClassLoader cl = sCachedSystemServerClassLoader; if (cl ! = null) { Thread.currentThread().setContextClassLoader(cl); } / / transfer cl in return ZygoteInit. ZygoteInit (parsedArgs. MTargetSdkVersion, parsedArgs mRemainingArgs, cl); }}Copy the code

About handleSystemServerProcess, main is to build SystemServer parameters, and pass to ZygoteInit. ZygoteInit, about ZygoteInit this method, the main can do three things, Then the main method of the argument class is finally called (see how Zygote works), because the argument here is SystemServer, so the main method of SystemServer is called

Three SystemServer. Java

3.1 the main

[SystemServer.java]

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

3.2 the run

SystemServer’s run method does a lot of things, but because they are more important, so here is not omitted, try to add every line of code to the effect of the comment, for this method to do the following

  1. Do some information saving
  2. Do some property Settings
  3. Do some virtual machine Settings
  4. Do some binder related Settings
  5. Load the so library for Android_Servers
  6. Create SystemServiceManager and register binder
  7. Start services in batches
  8. Enter the loop

[SystemServer.java]

private void run() { try { traceBeginAndSlog("InitBeforeStartServices"); Systemproperties.set (SYSPROP_START_COUNT, string.valueof (mStartCount)); SystemProperties.set(SYSPROP_START_ELAPSED, String.valueOf(mRuntimeStartElapsedTime)); SystemProperties.set(SYSPROP_START_UPTIME, String.valueOf(mRuntimeStartUptime)); EventLog.writeEvent(EventLogTags.SYSTEM_SERVER_START, mStartCount, mRuntimeStartUptime, mRuntimeStartElapsedTime); // If the system clock is before 1970 (the timestamp is less than 0), If (system.currentTimemillis () < written _supported_time) {log.w(TAG, "System clock is before 1970; setting to 1970."); SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME); } // if there is no timezone, set a default timezone GMT String timezoneProperty = SystemProperties. Get ("persist.sys.timezone"); if (timezoneProperty == null || timezoneProperty.isEmpty()) { Slog.w(TAG, "Timezone not set; setting to GMT."); SystemProperties.set("persist.sys.timezone", "GMT"); } // If the system set persist. Sys. language, replace it with persist. Sys. locale if (! SystemProperties.get("persist.sys.language").isEmpty()) { final String languageTag = Locale.getDefault().toLanguageTag(); SystemProperties.set("persist.sys.locale", languageTag); SystemProperties.set("persist.sys.language", ""); SystemProperties.set("persist.sys.country", ""); SystemProperties.set("persist.sys.localevar", ""); } // The system server must not make a non-one-way call to binder.setwarnonblocking (true); / / system server should always be loaded security label PackageItemInfo. ForceSafeLabels (); / / set the default SQLiteGlobal sDefaultSyncMode = SQLiteGlobal. SYNC_MODE_FULL; / / disable SQLiteCompatibilityWalFlags. Wait until the program initialization SQLiteCompatibilityWalFlags init (null); Slog. I (TAG, "Entered the Android System Server! ); int uptimeMillis = (int) SystemClock.elapsedRealtime(); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, uptimeMillis); if (! mRuntimeRestart) { MetricsLogger.histogram(null, "boot_system_server_init", uptimeMillis); } / / switch virtual libraries SystemProperties. Set (". Persist. Sys. Dalvik vm. Lib. 2 ", VMRuntime. GetRuntime (). VmLibrary ()); // Clear the memory limit vmruntime.getruntime ().clearGrowthLimit(); / / set the memory usage efficiency VMRuntime. GetRuntime (). SetTargetHeapUtilization (0.8 f); // Some devices rely on run-time fingerprint generation, so define it before further booting. Build.ensureFingerprintProperty(); / / system services, access to Environment variables need to explicitly specify the user Environment. SetUserRequired (true); / / system server, all incoming bundles need to be lifted, avoid BadParcelableException BaseBundle. SetShouldDefuse (true); In abnormal/server/system, packaging needs to contain stack information Parcel. SetStackTraceParceling (true); / / make sure binder calls at the front desk BinderInternal priority. DisableBackgroundScheduling (true); / / set the biggest binder threads, value is 31 BinderInternal setMaxThreads (sMaxBinderThreads); / / to the main thread which. Android. OS) Process. The 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); // Load the so library system. loadLibrary(" android_Servers "); / / debug the if (Build IS_DEBUGGABLE) {initZygoteChildHeapProfiling (); } // Check if the last shutdown failed performPendingShutdown(); // Initialize the system context createSystemContext(); // Create SystemServiceManager mSystemServiceManager = new SystemServiceManager(mSystemContext); mSystemServiceManager.setStartInfo(mRuntimeRestart, mRuntimeStartElapsedTime, mRuntimeStartUptime); / / registered SystemServiceManager LocalServices. The addService (SystemServiceManager. Class, mSystemServiceManager); / / preparation task thread pool SystemServerInitThreadPool. The get (); } finally { traceEnd(); // InitBeforeStartServices} // Start services. try {traceBeginAndSlog("StartServices"); // InitBeforeStartServices} // Start services. try {traceBeginAndSlog("StartServices"); / / boot service startBootstrapServices (); // startCoreServices(); // Other services startOtherServices(); / / get the thread pool SystemServerInitThreadPool. Shutdown (); } catch (Throwable ex) { Slog.e("System", "******************************************"); Slog.e("System", "************ Failure starting system services", ex); throw ex; } finally { traceEnd(); } / / rigid model (we can also use this thing) StrictMode. InitVmDefaults (null); // If the service is not started, print some logs if (! mRuntimeRestart && ! isFirstBootOrUpgrade()) { int uptimeMillis = (int) SystemClock.elapsedRealtime(); MetricsLogger.histogram(null, "boot_system_server_ready", uptimeMillis); final int MAX_UPTIME_MILLIS = 60 * 1000; if (uptimeMillis > MAX_UPTIME_MILLIS) { Slog.wtf(SYSTEM_SERVER_TIMING_TAG, "SystemServer init took too long. uptimeMillis=" + uptimeMillis); }} // Ensure that the system is normal if (! VMRuntime.hasBootImageSpaces()) { Slog.wtf(TAG, "Runtime is not running with a boot image!" ); } // start loop looper.loop (); throw new RuntimeException("Main thread loop unexpectedly exited"); }Copy the code

Batch startup of services

4.1 startBootstrapServices

[SystemServer.java]

private void startBootstrapServices() {
    //Watchdog 性能检测
    final Watchdog watchdog = Watchdog.getInstance();
    watchdog.start();
    traceEnd();

    //SystemConfig
    final String TAG_SYSTEM_CONFIG = "ReadingSystemConfig";
    traceBeginAndSlog(TAG_SYSTEM_CONFIG);
    SystemServerInitThreadPool.get().submit(SystemConfig::getInstance, TAG_SYSTEM_CONFIG);
    traceEnd();

    // Installer
    traceBeginAndSlog("StartInstaller");
    Installer installer = mSystemServiceManager.startService(Installer.class);
    traceEnd();

    // DeviceIdentifiersPolicyService
    traceBeginAndSlog("DeviceIdentifiersPolicyService");
    mSystemServiceManager.startService(DeviceIdentifiersPolicyService.class);
    traceEnd();

    // UriGrantsManagerService
    traceBeginAndSlog("UriGrantsManagerService");
    mSystemServiceManager.startService(UriGrantsManagerService.Lifecycle.class);
    traceEnd();

    // ActivityTaskManagerService
    // ActivityManagerService
    traceBeginAndSlog("StartActivityManager");
    // TODO: Might need to move after migration to WM.
    ActivityTaskManagerService atm = mSystemServiceManager.startService(
            ActivityTaskManagerService.Lifecycle.class).getService();
    mActivityManagerService = ActivityManagerService.Lifecycle.startService(
            mSystemServiceManager, atm);
    mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
    mActivityManagerService.setInstaller(installer);
    mWindowManagerGlobalLock = atm.getGlobalLock();
    traceEnd();

    // PowerManagerService
    traceBeginAndSlog("StartPowerManager");
    mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
    traceEnd();

    //ThermalManagerService
    traceBeginAndSlog("StartThermalManager");
    mSystemServiceManager.startService(ThermalManagerService.class);
    traceEnd();

    // 初始化 PowerManager
    traceBeginAndSlog("InitPowerManagement");
    mActivityManagerService.initPowerManagement();
    traceEnd();

    // RecoverySystemService
    traceBeginAndSlog("StartRecoverySystemService");
    mSystemServiceManager.startService(RecoverySystemService.class);
    traceEnd();

    // 
    RescueParty.noteBoot(mSystemContext);

    // LightsService
    traceBeginAndSlog("StartLightsService");
    mSystemServiceManager.startService(LightsService.class);
    traceEnd();

    //SidekickService
    traceBeginAndSlog("StartSidekickService");
    // Package manager isn't started yet; need to use SysProp not hardware feature
    if (SystemProperties.getBoolean("config.enable_sidekick_graphics", false)) {
        mSystemServiceManager.startService(WEAR_SIDEKICK_SERVICE_CLASS);
    }
    traceEnd();

    // DisplayManagerService
    traceBeginAndSlog("StartDisplayManager");
    mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
    traceEnd();

    //使用默认显示
    traceBeginAndSlog("WaitForDisplay");
    mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
    traceEnd();

    // 当设备正在加密时,仅运行核心app
    String cryptState = VoldProperties.decrypt().orElse("");
    if (ENCRYPTING_STATE.equals(cryptState)) {
        Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
        mOnlyCore = true;
    } else if (ENCRYPTED_STATE.equals(cryptState)) {
        Slog.w(TAG, "Device encrypted - only parsing core apps");
        mOnlyCore = true;
    }

    // PackageManagerService
    if (!mRuntimeRestart) {
        MetricsLogger.histogram(null, "boot_package_manager_init_start",
                (int) SystemClock.elapsedRealtime());
    }
    traceBeginAndSlog("StartPackageManagerService");
    try {
        Watchdog.getInstance().pauseWatchingCurrentThread("packagemanagermain");
        mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
    } finally {
        Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain");
    }
    mFirstBoot = mPackageManagerService.isFirstBoot();
    mPackageManager = mSystemContext.getPackageManager();
    traceEnd();

    if (!mRuntimeRestart && !isFirstBootOrUpgrade()) {
        MetricsLogger.histogram(null, "boot_package_manager_init_ready",
                (int) SystemClock.elapsedRealtime());
    }
    // Manages A/B OTA dexopting. This is a bootstrap service as we need it to rename
    // A/B artifacts after boot, before anything else might touch/need them.
    // Note: this isn't needed during decryption (we don't have /data anyways).
    if (!mOnlyCore) {
        boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
                false);
        if (!disableOtaDexopt) {
            traceBeginAndSlog("StartOtaDexOptService");
            try {
                Watchdog.getInstance().pauseWatchingCurrentThread("moveab");
                OtaDexoptService.main(mSystemContext, mPackageManagerService);
            } catch (Throwable e) {
                reportWtf("starting OtaDexOptService", e);
            } finally {
                Watchdog.getInstance().resumeWatchingCurrentThread("moveab");
                traceEnd();
            }
        }
    }

    // UserManagerService
    traceBeginAndSlog("StartUserManagerService");
    mSystemServiceManager.startService(UserManagerService.LifeCycle.class);
    traceEnd();

    // 初始化 AttributeCache
    traceBeginAndSlog("InitAttributerCache");
    AttributeCache.init(mSystemContext);
    traceEnd();

    // 为系统进程设置Application实例
    traceBeginAndSlog("SetSystemProcess");
    mActivityManagerService.setSystemProcess();
    traceEnd();

    // watchdog 性能监控
    traceBeginAndSlog("InitWatchdog");
    watchdog.init(mSystemContext, mActivityManagerService);
    traceEnd();

    // DisplayManagerService需要设置调度相关政策
    mDisplayManagerService.setupSchedulerPolicies();

    // OverlayManagerService
    traceBeginAndSlog("StartOverlayManagerService");
    mSystemServiceManager.startService(new OverlayManagerService(mSystemContext, installer));
    traceEnd();

    //SensorPrivacyService
    traceBeginAndSlog("StartSensorPrivacyService");
    mSystemServiceManager.startService(new SensorPrivacyService(mSystemContext));
    traceEnd();

    if (SystemProperties.getInt("persist.sys.displayinset.top", 0) > 0) {
        // DisplayManager needs the overlay immediately.
        mActivityManagerService.updateSystemUiContext();
        LocalServices.getService(DisplayManagerInternal.class).onOverlayChanged();
    }

    // 因为传感器服务依赖一些其他的服务,所以之后再启动它
    mSensorServiceStart = SystemServerInitThreadPool.get().submit(() -> {
        TimingsTraceLog traceLog = new TimingsTraceLog(
                SYSTEM_SERVER_TIMING_ASYNC_TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
        traceLog.traceBegin(START_SENSOR_SERVICE);
        //启动传感器服务
        startSensorService();
        traceLog.traceEnd();
    }, START_SENSOR_SERVICE);
}
Copy the code

4.2 startCoreServices

[SystemServer.java]

private void startCoreServices() { // BatteryService traceBeginAndSlog("StartBatteryService"); mSystemServiceManager.startService(BatteryService.class); traceEnd(); // UsageStatsService traceBeginAndSlog("StartUsageService"); mSystemServiceManager.startService(UsageStatsService.class); mActivityManagerService.setUsageStatsManager( LocalServices.getService(UsageStatsManagerInternal.class)); traceEnd(); // WebViewUpdateService if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) { traceBeginAndSlog("StartWebViewUpdateService"); mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class); traceEnd(); } / / CachedDeviceStateService disk cache state traceBeginAndSlog (" StartCachedDeviceStateService "); mSystemServiceManager.startService(CachedDeviceStateService.class); traceEnd(); // BinderCallsStatsService traceBeginAndSlog("StartBinderCallsStatsService"); mSystemServiceManager.startService(BinderCallsStatsService.LifeCycle.class); traceEnd(); // LooperStatsService traceBeginAndSlog("StartLooperStatsService"); mSystemServiceManager.startService(LooperStatsService.Lifecycle.class); traceEnd(); // RollbackManagerService traceBeginAndSlog("StartRollbackManagerService"); mSystemServiceManager.startService(RollbackManagerService.class); traceEnd(); / / this is bugreport BugreportManagerService, normally we get log is used traceBeginAndSlog (" StartBugreportManagerService "); mSystemServiceManager.startService(BugreportManagerService.class); traceEnd(); // GpuService traceBeginAndSlog("GpuService"); mSystemServiceManager.startService(GpuService.class); traceEnd(); }Copy the code

4.3 The first part of Startup Services

The total code for startOtherServices is quite long, so I won’t list all of them here. It does two main things. The first thing it does is start various system services

[SystemServer.java]

Private void startOtherServices() {public void startOtherServices() {public void startOtherServices() {public void startOtherServices(); try { ... / / key string service traceBeginAndSlog (" StartKeyChainSystemService "); mSystemServiceManager.startService(KeyChainSystemService.class); traceEnd(); . / / AccountManager traceBeginAndSlog account management (" StartAccountManagerService "); mSystemServiceManager.startService(ACCOUNT_SERVICE_CLASS); traceEnd(); // AlarmManagerService Clock management traceBeginAndSlog("StartAlarmManagerService"); mSystemServiceManager.startService(new AlarmManagerService(context)); traceEnd(); / / InputManagerService input traceBeginAndSlog (" StartInputManagerService "); inputManager = new InputManagerService(context); traceEnd(); One of the most important service / / WMS traceBeginAndSlog (" StartWindowManagerService "); wm = WindowManagerService.main(context, inputManager, ! mFirstBoot, mOnlyCore, new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager); 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(); . if (mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL) { Slog.i(TAG, "No Bluetooth Service (factory test)"); } else if (! context.getPackageManager().hasSystemFeature (PackageManager.FEATURE_BLUETOOTH)) { Slog.i(TAG, "No Bluetooth Service (Bluetooth Hardware Not Present)"); } else {//BluetoothService traceBeginAndSlog("StartBluetoothService"); mSystemServiceManager.startService(BluetoothService.class); traceEnd(); }... }Copy the code

4.4 startOtherServices

The second part is to call AMS ‘systemReady, and the desktop startup is also related to this AMS’ systemReady, because the desktop startup is a longer process, so I will explain it later

[SystemServer.java]

Private void startOtherServices() {public void startOtherServices() {public void startOtherServices() {public void startOtherServices(); / / all service start, to start the desktop mActivityManagerService. SystemReady (() - > {Slog i. (TAG, "Making services ready"); traceBeginAndSlog("StartActivityManagerReadyPhase"); mSystemServiceManager.startBootPhase( SystemService.PHASE_ACTIVITY_MANAGER_READY); traceEnd(); / / monitor native crash traceBeginAndSlog (" StartObservingNativeCrashes "); try { mActivityManagerService.startObservingNativeCrashes(); } catch (Throwable e) { reportWtf("observing native crashes", e); } traceEnd(); / / start the webview final String WEBVIEW_PREPARATION = "WebViewFactoryPreparation"; Future<? > webviewPrep = null; if (! mOnlyCore && mWebViewUpdateService ! = null) { webviewPrep = SystemServerInitThreadPool.get().submit(() -> { Slog.i(TAG, WEBVIEW_PREPARATION); TimingsTraceLog traceLog = new TimingsTraceLog( SYSTEM_SERVER_TIMING_ASYNC_TAG, Trace.TRACE_TAG_SYSTEM_SERVER); traceLog.traceBegin(WEBVIEW_PREPARATION); ConcurrentUtils.waitForFutureNoInterrupt(mZygotePreload, "Zygote preload"); mZygotePreload = null; mWebViewUpdateService.prepareWebViewInSystemServer(); traceLog.traceEnd(); }, WEBVIEW_PREPARATION); } if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { traceBeginAndSlog("StartCarServiceHelperService"); mSystemServiceManager.startService(CAR_SERVICE_HELPER_SERVICE_CLASS); traceEnd(); } // StartSystemUI traceBeginAndSlog("StartSystemUI"); try { startSystemUi(context, windowManagerF); } catch (Throwable e) { reportWtf("starting System UI", e); } traceEnd(); / / execution networkManagementF. SystemReady () traceBeginAndSlog (" MakeNetworkManagementServiceReady "); try { if (networkManagementF ! = null) { networkManagementF.systemReady(); } } catch (Throwable e) { reportWtf("making Network Managment Service ready", e); } CountDownLatch networkPolicyInitReadySignal = null; if (networkPolicyF ! = null) { networkPolicyInitReadySignal = networkPolicyF .networkScoreAndNetworkManagementServiceReady(); } traceEnd(); / / execution ipSecServiceF. SystemReady () traceBeginAndSlog (" MakeIpSecServiceReady "); try { if (ipSecServiceF ! = null) { ipSecServiceF.systemReady(); } } catch (Throwable e) { reportWtf("making IpSec Service ready", e); } traceEnd(); // There is also a series of systemReady... / / wait for all ready appdata mPackageManagerService. WaitForAppDataPrepared (); / / let the system service launched three sides traceBeginAndSlog tripartite code (" PhaseThirdPartyAppsCanStart "); // confirm webview completion before starting 3rd party if (webviewPrep ! = null) { ConcurrentUtils.waitForFutureNoInterrupt(webviewPrep, WEBVIEW_PREPARATION); } mSystemServiceManager.startBootPhase( SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); traceEnd(); . SystemRunning traceBeginAndSlog("MakeLocationServiceReady"); try { if (locationF ! = null) { locationF.systemRunning(); } } catch (Throwable e) { reportWtf("Notifying Location Service running", e); } traceEnd(); traceBeginAndSlog("MakeCountryDetectionServiceReady"); try { if (countryDetectorF ! = null) { countryDetectorF.systemRunning(); } } catch (Throwable e) { reportWtf("Notifying CountryDetectorService running", e); } traceEnd(); . //systemRunning end}, BOOT_TIMINGS_TRACE_LOG); }}Copy the code

Five summarizes

  • SystemServer as Zygote startup process, one of the most important processes, even life and death are bound to Zygote, so it is very important to see its role.
  • When SystemServer starts, the main method calls the run method, and does a series of initialization operations in the run method, including information saving, properties, virtual machine Settings, binder Settings, so library loading, registration of SystemServiceManager, and batch start services
  • The SystemServer batch Boot service is divided into three phases, Boot (Boot service), Core (Core service), Other (Other service), mainly to solve the dependency problem during the service startup process
  • After starting the service, a loop is entered

Note that not all services are started by SystemServer. Services started by SystemServer belong to the SystemServer process, and some services have their own independent processes. Those services are started by configuration in the RC file. If we want to develop a system-level service, we can either start it as a separate process in a rc file by configuration, or start it with SystemServer in the same process as SystemServer. Of course, there are many differences between the two services, which will be explained later. The SystemServer Launch is now complete, and the desktop Launch is now complete