主頁 > 移動端開發 > Zygote家的大兒子 —— SystemServer

Zygote家的大兒子 —— SystemServer

2020-09-16 08:50:16 移動端開發

本文基于 Android 9.0 , 代碼倉庫地址 : android_9.0.0_r45

文中原始碼鏈接:

SystemServer.java

SystemServiceManager.java

SystemService.java

首先來回顧一下上篇文章 Java 世界的盤古和女媧 —— Zygote ,主要介紹了 Android 世界中的第一個 Java 行程 Zygote,它的主要作業流程如下:

  1. registerServerSocketFromEnv(), 注冊服務端 socket,用于和客戶端行程通信
  2. preload(),預加載一系列資源,提高應用啟動速度
  3. forkSystemServer(),創建 system_server 行程
  4. 功成身退,呼叫 runSelectLoop() 等待回應客戶端請求,創建應用行程

本篇文章的主角 system_server 行程是 Zygote 行程 fork 出的第一個行程,它負責管理和啟動整個 Framework 層,

再來看看 Gityuan 的這張圖片,找一下 System Server 的位置,它承載了各類系統服務的創建和啟動,關于 system_server 行程的創建流程,上篇文章中已經做了詳細介紹,這里再簡單看一下流程圖:

最侄訓呼叫到 SystemServer.main() 方法,下面就以此為起點,來具體分析 SystemServer 都做了些什么,

SystemServer 啟動流程

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

接著看 run() 方法,

private void run() {
    try {
        ......
        // 如果設備時間早于 1970 年,很多 API 處理負數時會 crash,所以直接設定為 1970 年 1 月 1 日
        if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
            Slog.w(TAG, "System clock is before 1970; setting to 1970.");
            SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
        }

        // 未設定時區的話默認設為 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 (!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 should never make non-oneway calls
        Binder.setWarnOnBlocking(true);
        // The system server should always load safe labels
        PackageItemInfo.setForceSafeLabels(true);

        // Default to FULL within the system server.
        SQLiteGlobal.sDefaultSyncMode = SQLiteGlobal.SYNC_MODE_FULL;

        // Deactivate SQLiteCompatibilityWalFlags until settings provider is initialized
        SQLiteCompatibilityWalFlags.init(null);

        // Here we go!
        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);
        }

        // 設定虛擬機運行庫路徑
        SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());

        // Mmmmmm... more memory!
        // 清除虛擬機記憶體增長限制,允許應用申請更多記憶體
        VMRuntime.getRuntime().clearGrowthLimit();

        // 設定堆記憶體的有效利用率為 0.8,(可能被忽略)
        VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);

        // 確保指紋資訊已經定義
        Build.ensureFingerprintProperty();

        // Within the system server, it is an error to access Environment paths without
        // explicitly specifying a user.
        Environment.setUserRequired(true);

        // Within the system server, any incoming Bundles should be defused
        // to avoid throwing BadParcelableException.
        BaseBundle.setShouldDefuse(true);

        // Within the system server, when parceling exceptions, include the stack trace
        Parcel.setStackTraceParceling(true);

        // 確保系統的 Binder 呼叫總是運行在前臺優先級
        BinderInternal.disableBackgroundScheduling(true);

        // Increase the number of binder threads in system_server
        BinderInternal.setMaxThreads(sMaxBinderThreads);

        // Prepare the main looper thread (this thread).
        android.os.Process.setThreadPriority(
            android.os.Process.THREAD_PRIORITY_FOREGROUND);
            android.os.Process.setCanSelfBackground(false);
        // 1. 創建主執行緒 Looper
        Looper.prepareMainLooper();
        Looper.getMainLooper().setSlowLogThresholdMs(
                SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);

        // 初始化 native 服務,加載 libandroid_servers.so
        System.loadLibrary("android_servers");

        // 檢查上次關機是否失敗,可能不會有回傳值
        performPendingShutdown();

        // 2. 初始化系統背景關系
        createSystemContext();

        // 3. 創建系統服務管理 SystemServiceManager
        // 并將 mSystemServiceManager 注冊到 sLocalServiceObjects 中
        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();  // InitBeforeStartServices
    }

    // Start services.
    try {
        traceBeginAndSlog("StartServices");
        startBootstrapServices(); // 4. 啟動系統引導服務
        startCoreServices();      // 5. 啟動系統核心服務
        startOtherServices();     // 6. 啟動其他服務
        SystemServerInitThreadPool.shutdown();
    } catch (Throwable ex) {
        Slog.e("System", "******************************************");
        Slog.e("System", "************ Failure starting system services", ex);
        throw ex;
    } finally {
        traceEnd();
    }

    StrictMode.initVmDefaults(null);

    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);
        }
    }

    // 7. Loop forever.
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

代碼雖然比較長,但是邏輯很清晰,我在注釋里標記了比較重要的 7 個步驟,逐一分析,

Looper.prepareMainLooper()

初始化 Looper,關于 Handler 訊息機制,可以閱讀我的另一篇文章 深入理解 Handler 訊息機制 ,最后會呼叫 Looper.loop() 開啟訊息回圈,開始處理訊息,

createSystemContext()

private void createSystemContext() {
    // 創建 system_server 背景關系資訊
    ActivityThread activityThread = ActivityThread.systemMain();
    mSystemContext = activityThread.getSystemContext();
    mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);

    final Context systemUiContext = activityThread.getSystemUiContext();
    // 設定主題,用于系統 dialog 等
    systemUiContext.setTheme(DEFAULT_SYSTEM_THEME);
}

創建系統背景關系,首先呼叫 ActivityThread.systemMain() 方法獲取 ActivityThread 物件,然后再獲取背景關系,

public static ActivityThread systemMain() {
    // 判斷是否是大記憶體設備,在低記憶體設備上不啟用硬體加速
    if (!ActivityManager.isHighEndGfx()) {
        ThreadedRenderer.disable(true);
    } else {
        ThreadedRenderer.enableForegroundTrimming();
    }
    ActivityThread thread = new ActivityThread();
    thread.attach(true, 0);
    return thread;
}

關于 ActivityThread.attach() 方法這里不做具體分析了,后面文章說到應用啟動時再來詳細決議,

創建完系統背景關系,接下來就是啟動各種系統服務了,原始碼中把服務大致分為了三類,再來回顧一下:

startBootstrapServices(); // 4. 啟動系統引導服務
startCoreServices();      // 5. 啟動系統核心服務
startOtherServices();     // 6. 啟動其他服務

逐一進行分析,

startBootstrapServices()

private void startBootstrapServices() {
    final String TAG_SYSTEM_CONFIG = "ReadingSystemConfig";
    SystemServerInitThreadPool.get().submit(SystemConfig::getInstance, TAG_SYSTEM_CONFIG);

    // 阻塞等待與 installd 建立 socket 通道
    Installer installer = mSystemServiceManager.startService(Installer.class);

    // 啟動 DeviceIdentifiersPolicyService,在 ActivityManagerService 之前
    mSystemServiceManager.startService(DeviceIdentifiersPolicyService.class);

    // 啟動服務 ActivityManagerService
    mActivityManagerService = mSystemServiceManager.startService(
            ActivityManagerService.Lifecycle.class).getService();
    mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
    mActivityManagerService.setInstaller(installer);

    // 啟動服務 PowerManagerService
    mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);

    // Now that the power manager has been started, let the activity manager
    // initialize power management features.
    mActivityManagerService.initPowerManagement();

    // 啟動服務 RecoverySystemService
    mSystemServiceManager.startService(RecoverySystemService.class);

    // Now that we have the bare essentials of the OS up and running, take
    // note that we just booted, which might send out a rescue party if
    // we're stuck in a runtime restart loop.
    RescueParty.noteBoot(mSystemContext);

    // 啟動服務 LightsService
    mSystemServiceManager.startService(LightsService.class);

    // 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);
    }

    // 啟動 DisplayManagerService,在 PackageManagerService 之前
    mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);

    // We need the default display before we can initialize the package manager.
    mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);

    // 正在加密設備時只運行核心 app
    String cryptState = SystemProperties.get("vold.decrypt");
    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());
    }
    mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
            mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
    mFirstBoot = mPackageManagerService.isFirstBoot();
    mPackageManager = mSystemContext.getPackageManager();
    if (!mRuntimeRestart && !isFirstBootOrUpgrade()) {
        MetricsLogger.histogram(null, "boot_package_manager_init_ready",
                (int) SystemClock.elapsedRealtime());
    }
    if (!mOnlyCore) {
        boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
                false);
        if (!disableOtaDexopt) {
            traceBeginAndSlog("StartOtaDexOptService");
            try {
                OtaDexoptService.main(mSystemContext, mPackageManagerService);
            } catch (Throwable e) {
                reportWtf("starting OtaDexOptService", e);
            } finally {
                traceEnd();
            }
        }
    }

    // 啟動服務 UserManagerService
    mSystemServiceManager.startService(UserManagerService.LifeCycle.class);

    // 初始化屬性 cache 以快取包資源
    AttributeCache.init(mSystemContext);

    // 設定 AMS
    mActivityManagerService.setSystemProcess();

    // DisplayManagerService needs to setup android.display scheduling related policies
    // since setSystemProcess() would have overridden policies due to setProcessGroup
    mDisplayManagerService.setupSchedulerPolicies();

    // 啟動服務 OverlayManagerService
    OverlayManagerService overlayManagerService = new OverlayManagerService(
            mSystemContext, installer);
    mSystemServiceManager.startService(overlayManagerService);

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

    // 在單獨的執行緒中啟動 SensorService
    mSensorServiceStart = SystemServerInitThreadPool.get().submit(() -> {
        TimingsTraceLog traceLog = new TimingsTraceLog(
                SYSTEM_SERVER_TIMING_ASYNC_TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
        startSensorService();
    }, START_SENSOR_SERVICE);
}

startBootstrapServices() 方法中的都是系統啟動程序中的關鍵服務,且相互依賴,主要下列服務 :

Installer DeviceIdentifiersPolicyService ActivityManagerService PowerManagerService RecoverySystemService LightsService StartSidekickService DisplayManagerService

SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY (100)

PackageManagerService UserManagerService OverlayManagerService SensorService

一共啟動了十二個核心服務,注意中間的 SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY,它并不是代表什么系統服務,而是一個 int 值 100,類似的 int 值還有一些,定義在 SystemService 類中,它的作用是給服務啟動程序劃分階段,每個階段都有特定的含義,可以做不同的事情,這里先混個臉熟,等介紹完所有的服務,再回過頭來總結一下有哪些階段,

startCoreServices()

private void startCoreServices() {
    // 啟動服務 BatteryService,需要 LightService
    mSystemServiceManager.startService(BatteryService.class);

    // 啟動服務 UsageStatsService,統計應用使用情況
    mSystemServiceManager.startService(UsageStatsService.class);
    mActivityManagerService.setUsageStatsManager(
            LocalServices.getService(UsageStatsManagerInternal.class));

    // 檢查是否存在可更新的 WebView,存在就啟動服務 WebViewUpdateService
    if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
        mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
    }

    // 啟動服務 BinderCallsStatsService,跟蹤 Binder 呼叫的 cpu 時間消耗
    BinderCallsStatsService.start();
}

啟動了四個服務,BatteryService UsageStatsService WebViewUpdateServiceBinderCallsStatsService

startOtherServices()

startOtherServices() 原始碼有一千多行,就像一個雜貨鋪,啟動了一系列的服務,下面盡量精簡一下代碼:

KeyAttestationApplicationIdProviderService/KeyChainSystemService
SchedulingPolicyService/TelecomLoaderService/TelephonyRegistry

mContentResolver = context.getContentResolver();

AccountManagerService/ContentService

mActivityManagerService.installSystemProviders();
  
DropBoxManagerService/VibratorService/ConsumerIrService/AlarmManagerService

final Watchdog watchdog = Watchdog.getInstance();
watchdog.init(context, mActivityManagerService);

InputManagerService/WindowManagerService/VrManagerService/BluetoothService
IpConnectivityMetrics/NetworkWatchlistService/PinnerService
InputMethodManagerService/AccessibilityManagerService/StorageManagerService
StorageStatsService/UiModeManagerService/LockSettingsService
PersistentDataBlockService/OemLockService/DeviceIdleController
DevicePolicyManagerService/StatusBarManagerService/ClipboardService
NetworkManagementService/IpSecService/TextServicesManagerService
TextClassificationManagerService/NetworkScoreService/NetworkStatsService
NetworkPolicyManagerService/WifiScanningService/RttService
WifiAware/WifiP2P/Lowpan/Ethernet/ConnectivityService/NsdService
SystemUpdateManagerService/UpdateLockService/NotificationManagerService
DeviceStorageMonitorService/LocationManagerService/CountryDetectorService
SearchManagerService/WallpaperManagerService/AudioService/BroadcastRadioService
DockObserver/ThermalObserver/WiredAccessoryManager/MidiManager/UsbService
SerialService/HardwarePropertiesManagerService/TwilightService
ColorDisplayService/JobSchedulerService/SoundTriggerService/TrustManagerService
BackupManager/AppWidgerService/VoiceRecognitionManager/GestureLauncherService
SensorNotificationService/ContextHubSystemService/DiskStatsService
TimeZoneRulesManagerService/NetworkTimeUpdateService/CommonTimeManagementService
CertBlacklister/EmergencyAffordanceService/DreamManagerService/GraphicsStatsService
CoverageService/PrintManager/CompanionDeviceManager/RestrictionsManagerService
MediaSessionService/MediaUpdateService/HdmiControlService/TvInputManagerService
MediaResourceMonitorService/TvRemoteService/MediaRouterService/FingerprintService
BackgroundDexOptService/PruneInstantAppsJobService/ShortcutService
LauncherAppsService/CrossProfileAppsService/MediaProjectionManagerService
WearConfigService/WearConnectivityService/WearTimeService/WearLeftyService
WearGlobalActionsService/SliceManagerService/CameraServiceProxy/IoTSystemService
MmsServiceBroker/AutoFillService

// It is now time to start up the app processes...
vibrator.systemReady();
lockSettings.systemReady();

// 480
mSystemServiceManager.startBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY); 
// 500
mSystemServiceManager.startBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY); 

wm.systemReady();
mPowerManagerService.systemReady(mActivityManagerService.getAppOpsService());
mPackageManagerService.systemReady();
mDisplayManagerService.systemReady(safeMode, mOnlyCore);

// Start device specific services
final String[] classes = mSystemContext.getResources().getStringArray(
        R.array.config_deviceSpecificSystemServices);
for (final String className : classes) {
    try {
        mSystemServiceManager.startService(className);
    } catch (Throwable e) {
        reportWtf("starting " + className, e);
    }
}

// 520
mSystemServiceManager.startBootPhase(SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY);

mActivityManagerService.systemReady(() -> {
    // 550
    mSystemServiceManager.startBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY);
    
    startSystemUi(context, windowManagerF);
    
    networkManagementF.systemReady();
    ipSecServiceF.systemReady();
    networkStatsF.systemReady();
    connectivityF.systemReady();
    
    Watchdog.getInstance().start
    mPackageManagerService.waitForAppDataPrepared();

    // 600
    mSystemServiceManager.startBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
    
    locationF.systemRunning();
    countryDetectorF.systemRunning();
    networkTimeUpdaterF.systemRunning();
    commonTimeMgmtServiceF.systemRunning();
    inputManagerF.systemRunning();
    telephonyRegistryF.systemRunning();
    mediaRouterF.systemRunning();
    mmsServiceF.systemRunning();
    incident.systemRunning();
}

通過上面的代碼可以看到啟動了相當多的系統服務,startOtherServices() 方法共經歷了五個啟動階段,如下所示:

SystemService.PHASE_LOCK_SETTINGS_READY             // 480
SystemService.PHASE_SYSTEM_SERVICES_READY           // 500
SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY  // 520
SystemService.PHASE_ACTIVITY_MANAGER_READY          // 550
SystemService.PHASE_THIRD_PARTY_APPS_CAN_START      // 600

最后呼叫的 mActivityManagerService.systemReady() 方法,該方法中會呼叫 startHomeActivityLocked 來啟動桌面 Activity,這樣桌面應用就啟動了,

Looper.loop()

至此,system_server 行程的主要作業就算完成了,進入 Looper.loop() 狀態,等待其他執行緒通過 Handler 發送訊息到主執行緒并處理,

SystemServer 啟動階段分類

回過頭再來看看前面提到的啟動階段分類,定義在 com.android.server.SystemService 類中:

/*
 * Boot Phases
 * 
 * 啟動階段
 */
public static final int PHASE_WAIT_FOR_DEFAULT_DISPLAY = 100; // maybe should be a dependency?

/**
 * After receiving this boot phase, services can obtain lock settings data.
 */
public static final int PHASE_LOCK_SETTINGS_READY = 480;

/**
 * After receiving this boot phase, services can safely call into core system services
 * such as the PowerManager or PackageManager.
 * 
 * 在這個階段之后,可以安全的呼叫系統核心服務,如 PowerManager 和 PackageManager
 */
public static final int PHASE_SYSTEM_SERVICES_READY = 500;

/**
 * After receiving this boot phase, services can safely call into device specific services.
 * 
 * 在這個階段之后,可以安全呼叫設備特定的服務
 */
public static final int PHASE_DEVICE_SPECIFIC_SERVICES_READY = 520;

/**
 * After receiving this boot phase, services can broadcast Intents.
 * 
 * 在這個階段之后,服務可以廣播
 */
public static final int PHASE_ACTIVITY_MANAGER_READY = 550;

/**
 * After receiving this boot phase, services can start/bind to third party apps.
 * Apps will be able to make Binder calls into services at this point.
 * 
 * 在這個階段之后,服務可以啟動/系結第三方應用
 * 應用此時可以進行 Binder 呼叫
 */
public static final int PHASE_THIRD_PARTY_APPS_CAN_START = 600;

/**
 * After receiving this boot phase, services can allow user interaction with the device.
 * This phase occurs when boot has completed and the home application has started.
 * System services may prefer to listen to this phase rather than registering a
 * broadcast receiver for ACTION_BOOT_COMPLETED to reduce overall latency.
 * 
 * 在這個階段之后,允許用戶和設備互動,
 * 這個階段發生在啟動完成,home 應用已經開始,
 * 系統服務更傾向于監聽這個階段,而不是監聽啟動廣播 ACTION_BOOT_COMPLETED,以降低延遲
 */
public static final int PHASE_BOOT_COMPLETED = 1000;

system_server 啟動程序中各個階段的位置大致如下:

private void startBootstrapServices() {
    ...
    // 100
    mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
    ...
}

private void startOtherServices() {
    ...
    // 480
    mSystemServiceManager.startBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY);
    // 500
    mSystemServiceManager.startBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);

    ...
    // 520
    mSystemServiceManager.startBootPhase(SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY);

    mActivityManagerService.systemReady(() -> {
        mSystemServiceManager.startBootPhase(
                    SystemService.PHASE_ACTIVITY_MANAGER_READY); // 550
                    
        ...
        mSystemServiceManager.startBootPhase(
                    SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); // 600
    }
}

最后的 SystemService.PHASE_BOOT_COMPLETED(1000) 在 AMS 的 finishBooting() 方法中呼叫,另外注意 480500 兩個階段是連在一起的,中間沒有發生任何事情,

那么,劃分階段的具體作用是什么呢?答案就在 startBootPhase() 方法中:

public void startBootPhase(final int phase) {
    if (phase <= mCurrentPhase) {
        throw new IllegalArgumentException("Next phase must be larger than previous");
    }
    mCurrentPhase = phase;

    try {
        final int serviceLen = mServices.size();
        for (int i = 0; i < serviceLen; i++) {
            final SystemService service = mServices.get(i);
            long time = SystemClock.elapsedRealtime();
            try {
                // 回呼系統服務的 onBootPhase() 方法
                service.onBootPhase(mCurrentPhase);
            } catch (Exception ex) {
                throw new RuntimeException("Failed to boot service "
                        + service.getClass().getName()
                        + ": onBootPhase threw an exception during phase "
                        + mCurrentPhase, ex);
            }
            warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onBootPhase");
        }
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
    }
}

核心就在于 service.onBootPhase(mCurrentPhase);,所有系統服務都是繼承于 SystemService 的,startBootPhase() 方法會回呼當前階段已經加入 mServices 的所有系統服務的 onBootPhase() 方法,在合適的階段做一些合適的事情,以 AMS 為例:

@Override
public void onBootPhase(int phase) {
    mService.mBootPhase = phase;
    if (phase == PHASE_SYSTEM_SERVICES_READY) {
        mService.mBatteryStatsService.systemServicesReady();
        mService.mServices.systemServicesReady();
    }
}

SystemServer 是如何啟動服務的 ?

看完 SystemServer 的原始碼,它最重要的作業就是創建和啟動各種系統服務,那么服務一般是如何創建的呢?下面以 startBootstrapServices() 中創建的第一個服務 Installer 為例來看一下:

Installer installer = mSystemServiceManager.startService(Installer.class);

進入 SystemServiceManagerstartService() 方法:

public <T extends SystemService> T startService(Class<T> serviceClass) {
    try {
        // 獲取服務名稱
        final String name = serviceClass.getName();

        // Create the service.
        if (!SystemService.class.isAssignableFrom(serviceClass)) {
            throw new RuntimeException("Failed to create " + name
                    + ": service must extend " + SystemService.class.getName());
        }
        final T service;
        try {
            // 獲取服務類的構造器
            Constructor<T> constructor = serviceClass.getConstructor(Context.class);
            // 反射創建 service
            service = constructor.newInstance(mContext);
        } catch (InstantiationException ex) {
            throw new RuntimeException("Failed to create service " + name
                    + ": service could not be instantiated", ex);
        } catch (IllegalAccessException ex) {
            throw new RuntimeException("Failed to create service " + name
                    + ": service must have a public constructor with a Context argument", ex);
        } catch (NoSuchMethodException ex) {
            throw new RuntimeException("Failed to create service " + name
                    + ": service must have a public constructor with a Context argument", ex);
        } 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);
    }
}

創建并啟動一個系統服務,這個系統服務必須是 com.android.server.SystemService 的子類,根據引數傳入的 Class 物件反射創建其實體,再呼叫多載方法 startService()

public void startService(@NonNull final SystemService service) {
    // Register it.
    mServices.add(service);
    // Start it.
    long time = SystemClock.elapsedRealtime();
    try {
        // 回呼系統服務的 onStart() 方法
        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");
}

就兩步,第一步,注冊服務,mServices 是一個 ArrayList<SystemService> 物件,用來保存已經創建的系統服務,第二步,回呼服務的 onStart() 方法,還是以 Installer 為例:

@Override
public void onStart() {
    if (mIsolated) {
        mInstalld = null;
    } else {
        connect();
    }
}

這樣一個服務就啟動完成了,這是一種比較普遍的啟動方式,當然還有一些系統服務具有不一樣的啟動方式,這里就不一一分析了,后面有機會決議具體服務的時候再來分析,

總結

SystemServer 的啟動流程比較耿直,沒有那么多彎彎繞,下面簡單總結一下:

  1. 語言、時區、地區等設定
  2. 虛擬機記憶體設定
  3. 指紋資訊,Binder 呼叫設定
  4. Looper.prepareMainLooper() ,創建主執行緒 Looper
  5. 初始化 native 服務,加載 libandroid_servers.so
  6. createSystemContext(),初始化系統背景關系
  7. 創建系統服務管理 SystemServiceManager
  8. startBootstrapServices,啟動系統引導服務
  9. startCoreServices,啟動系統核心服務
  10. startOtherServices,啟動其他服務
  11. Looper.loop(),開啟訊息回圈

另外,在 startOtherServices 的最后會呼叫 AMS 的 onSystemReady() 方法啟動桌面 Activity,

預告

還記得 Zygote 行程的 runSelectLoop() 方法嗎?Zygote 在創建完 system_server 行程之后,就開始默默的等待客戶端請求創建應用行程,下一篇,我們將從原始碼角度來捋一遍客戶端是如何發送請求,Zygote 是如何處理請求,應用行程是如何創建的,敬請期待!

文章首發微信公眾號: 秉心說 , 專注 Java 、 Android 原創知識分享,LeetCode 題解,

更多最新原創文章,掃碼關注我吧!

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/55648.html

標籤:Android

上一篇:Android開發——實作子執行緒更新UI

下一篇:Android之實作apk插件方式換膚

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more