ActivityManagerService的啓動過程

AMS對象隨系統進程啓動而構建,隨着系統進程退出而消亡,能夠說,AMS與系統進程共存亡。java

先上一張總的啓動時序圖:android

上圖分爲三個步驟:git

  1. 初始化系統進程的運行環境;
  2. 初始化AMS對象;
  3. AMS對象啓動的配套工做。

1.初始化系統進程的運行環境

SystemServer是咱們理解Android系統進程的入口,它的初始化是從Native層開始的:Zygote從Native層調用SystemServer的main()函數,便開始了SystemServer的初始化。初始化很重要的一個步驟就是建立系統進程的運行環境,即建立一個SystemContext,調用關係以下所示:github



SystemServer.main() // Zygote會從Native層調用該方法,進入SystemServer的執行代碼 └── SystemServer.run() // SystemServer一旦運行起來,就一直循環處理消息隊列中的消息 └── SystemServer.createSystemContext() // 建立SystemContext

SystemContext究竟是什麼呢?說到底,它仍是一個Context類型的對象,須要藉助於ActivityThread才能獲取到:shell

// SystemServer.createSystemContext() private void createSystemContext() { ActivityThread activityThread = ActivityThread.systemMain(); mSystemContext = activityThread.getSystemContext(); mSystemContext.setTheme(android.R.style.Theme_DeviceDefault_Light_DarkActionBar); }

ActivityThread.systemMain()函數用於建立系統進程的主線程,方法主體很簡單,建立了一個新的ActivityThread對象,並調用了attach()方法,輸入參數是true,表示須要將其綁定到系統進程。數據庫

應用進程建立ActivityThread對象是經過ActivityThread.main()函數完成的。因爲系統進程的特殊性,專闢了一個systemMain()函數給系統進程。編程

public static ActivityThread systemMain() { ... // 省略硬件渲染相關配置的代碼 ActivityThread thread = new ActivityThread(); thread.attach(true); return thread; }

接下來,咱們來着重分析一下ActivityThread.attach()函數:數據結構

private void attach(boolean system) { sCurrentActivityThread = this; mSystemThread = system; if (!system) { ... // 綁定應用進程,本例僅討論綁定系統進程,故省略之 } else { // 設置進程名爲system_process android.ddm.DdmHandleAppName.setAppName("system_process", UserHandle.myUserId()); try { mInstrumentation = new Instrumentation(); ContextImpl context = ContextImpl.createAppContext( this, getSystemContext().mPackageInfo); mInitialApplication = context.mPackageInfo.makeApplication(true, null); mInitialApplication.onCreate(); } catch (Exception e) { ... // 省略拋出異常的代碼 } } // 設置與輸出日誌相關的Dropbox DropBox.setReporter(new DropBoxReporter()); ViewRootImpl.addConfigCallback( ... // ); }

在上面的函數實現中,會建立幾個很重要的對象:多線程

  • mInstrumentation: 工具類,主要用於測試,與AndroidManifest.xml中<instrumentation>對應;app

  • context: Application的運行環境,建立它的目的是爲了建立下面的Application對象。建立這個context須要傳入一個LoadedApk類型的對象,經過ActivityThread.getSystemContext()函數即可獲取:

public ContextImpl getSystemContext() { synchronized (this) { if (mSystemContext == null) { mSystemContext = ContextImpl.createSystemContext(this); } return mSystemContext; } }

這裏是第一次調用getSystemContext()函數,因此mSystemContext爲null,進而會經過ContextImpl.createSystemContext()函數建立一個新的對象:

// ContextImpl.createSystemContext() static ContextImpl createSystemContext(ActivityThread mainThread) { LoadedApk packageInfo = new LoadedApk(mainThread); ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, false, null, null, Display.INVALID_DISPLAY); context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(), context.mResourcesManager.getDisplayMetricsLocked()); return context; }

上述函數首先會建立一個LoadedApk的對象,LoadedApk表示一個裝載到內存的Apk,對於SystemContext,這個Apk就是framework-res.apk; 而後,建立一個ContextImpl的對象,進一步初始化資源相關的配置; 最終,返回的context就是SystemContext。

  • mInitialApplication: Application對象,因爲是經過framework-res.apk這個APK的Context建立而來,因此這個Application對象就對應到了framework-res.apk,這是系統中第一個運行的APK,因此叫作InitialApplication,它是運行在系統進程中。

兜兜轉轉弄了一圈,終於把SystemContext給建立好了,系統進程好好運行就行了,爲何要大費周張的搞一個運行環境Context出來呢? 操做系統運行基本單位是進程,咱們寫的任何Android代碼最終都要落到一個實際的進程中去執行。然而,Android有意弱化了進程的概念,咱們在寫Android應用程序的時候,基礎的概念都是運行環境(Context),而不是去考慮進程中有什麼可使用。 Android對待系統進程,也像對待普通的應用進程同樣,都須要構建一個運行環境,就是Context。在構建AMS對象時,會將SystemContext傳入,經過這個特殊的Context,AMS就能獲取運行時所須要各類信息。

咱們經過一張類圖來總結一下,與系統進程運行環境初始化相關的各個類之間的關係:

 

 

  總結初始化環境的三個步驟:

  1. Android要爲應用進程創造一個運行環境,一樣也須要爲系統進程創造一個運行環境,在系統進程啓動伊始,這個運行環境就須要建立完畢,這個環境就是咱們所說的SystemContext;

  2. SystemServer會建立一個ActivityThread對象,表明系統進程的主線程,系統進程的入口爲SysMain(),在ActivityThread對象構建的過程當中,又會建立Instrumentation對象和framework-res.apk的LoadedApk對象,再經過LoadedApk建立Application對象;

  3. 在ActivityThread對象構建完畢後,SystemServer即可獲取到系統進程的運行環境了,即SystemContext,這是ActivityThread經過ContextImpl建立而成的。

 

2.初始化ActivityManagerService對象

在Android起機的過程當中,系統服務是相互影響的,因此有啓動順序的前後之分,譬如BatteryService,WindowManagerService就須要在ActivityManagerService建立以後才能建立。還有一些系統事件,譬如BOOT_COMPLETED廣播,須要在系統徹底啓動以後才能發出。 Android爲系統服務封裝了SystemService類,設計了系統服務的生命週期:

public abstract class SystemService { // 階段 1: 等待顯示設備準備完畢 // 這個階段,Installer, AMS, PowerManagerService, DisplayManagerService已經構建完畢 public static final int PHASE_WAIT_FOR_DEFAULT_DISPLAY = 100; // 階段 2: 鎖屏服務已經準備完畢 // 這個階段,大部分系統服務已經構建完畢。其餘服務能夠獲取鎖屏相關的數據了,譬如鎖屏密碼等 public static final int PHASE_LOCK_SETTINGS_READY = 480; // 階段 3: 系統服務已經準備完畢 // 這個階段,大部分系統服務已經構建完畢,PackageManagerService,PowerManagerService已經可以提供服務 public static final int PHASE_SYSTEM_SERVICES_READY = 500; // 階段 4: ActivityManagerService已經可以提供服務了 // 這個階段,獲取ContentProvider、發送廣播等AMS相關的功能已經能夠用了 public static final int PHASE_ACTIVITY_MANAGER_READY = 550; // 階段 5: 已經能夠啓動應用程序了 // 這個階段,用戶界面已經啓動,數據鏈接、音頻等服務都已可用 public static final int PHASE_THIRD_PARTY_APPS_CAN_START = 600; // 階段 6: 系統起機完成 public static final int PHASE_BOOT_COMPLETED = 1000; public abstract void onStart(); public void onBootPhase(int phase) {} // ... 省略其餘函數 }

部分系統服務的初始化依賴於當前系統已經起機到什麼階段,當系統服務啓動時,onStart()函數會被調用; 系統啓動到必定的階段,onBootPhase()函數會被調用。全部系統服務的建立和生命週期的管理都是由SystemServiceManager這個類完成的。

本文中要分析的AMS,它並無直接繼承SystemService,而是經過內部類Lifecycle來繼承實現的, AMS.Lifecycle很是簡單,就是調用了AMS的構造函數和start()函數,是一個間接初始化AMS的過程。



咱們經過類圖來總結一下SystemServiceManager, SystemService以及AMS三者之間的關係:public static final class Lifecycle extends SystemService { private final ActivityManagerService mService; // 構造函數會被SystemServiceManager反射調用 public Lifecycle(Context context) { super(context); mService = new ActivityManagerService(context); } // 在Lifecycle對象構造完成後,這個函數會被回調 @Override public void onStart() { mService.start(); } public ActivityManagerService getService() { return mService; } }

 

  1. SystemService是系統服務的抽象類,封裝了onStart()和onBootPhase()等生命週期函數供SystemServiceManager回掉;

  2. AMS並非直接繼承SystemService,而是經過內部類Lifecycle間接完成了系統服務啓動的生命週期;

  3. SystemServiceManager管理了多個SystemService。

SystemServer在完成一些簡單的初始化後,就須要啓動系統服務了,最重要的一系列服務是在SystemServer.startBootstrapServices() 這個函數中啓動的,BootstrapServices的命名也很貼切,表示要啓動一些」引導服務」,這些服務直接影響到其餘服務的啓動。

  1. 啓動AMS以前,須要先鏈接installd進程。在系統進程(system_process)中,對應的服務就Installer, 經過Installer這個服務,就能完成一些重要目錄的建立,譬如/data/user。

  2. 啓動AMS。因而可知AMS的重要性,Android第二個啓動的系統服務就是AMS。 實際上,這裏經過SystemServcieManager來啓動的是AMS.Lifecycle,AMS的真正初始化工做是由AMS.Lifecyle間接完成的。

  3. 啓動PowerManagerService,這也是很是重要的一個系統服務。AMS也須要使用PowerManagerService的服務, 譬如,在啓動Activity時,要避免系統進入休眠狀態,就須要獲取WakeLock。

  4. 這一步啓動Lights、 DisplayManager、 PackageManager這些系統服務。

  5. 調用AMS.setSystemProcess()將當前進程設置爲系統進程。爲何在SystemServer中須要調用AMS的方法來設置當前進程的信息呢? 由於AMS的職責之一就是維護全部進程的狀態,不論是應用進程仍是系統進程,都是AMS的管轄範圍。

   上面第2條AMS對象構建時,要初始化的內容很是多,大體能夠分紅兩類:

  • 監測統計: Watchdog,CPU、內存、電量的使用統計
  • 組件管理: broadcastQueues, services, providers, statckSupervisor,recentTasks, Android四大組件的相關信息都由AMS統一維護

   在第5步中, 經過AMS對象調用了setSystemProcess()函數,目的是爲了將當前進程(system_process)設置爲系統進程:

  1. 經過ServiceManager向系統註冊一些重要的服務。諸如meminfo、gfxinfo、dbinfo等信息都是由系統進程維護的, 能夠經過adb shell dumpsys命令輸出。

  2. ApplicationInfo包含了一個應用程序的信息,這些信息從AndroidManifest.xml的<application>標籤中解析出來,譬如進程名、版本號、使用的主題等,那麼,經過android這個包名,獲取的ApplicationInfo天然就是Android系統這個應用程序的信息。

    每個普通的應用程序都會有一個AndroidManifest.xml文件,這個應用程序運行的環境,就是咱們所說的」應用進程」; 有一個特殊的應用程序,具有更多的特權,這個應用程序的運行環境就是」系統進程」。 android就是這個特殊應用程序的包名,其所對應的<application>標籤訂義在frameworks/base/core/res/AndroidManifest.xml中,最終會編譯在framework-res.apk中。

    不管是應用進程仍是系統進程,都有主線程,ActivityThread就是Android定義的主線程類。 AMS中的mSystemThread對象就是ActivityThread的實例,表示這是系統進程的主線程。 經過mSystemThread.installSystemApplicationInfo()這個函數調用,ApplicationInfo和ClassLoader就被設置到了 LoadedApk中,ApplicationInfo與LoadedApk的關係咱們後文再描述。

  3. ProcessRecord這個類用於描述一個運行的進程,AMS管理着全部ProcessRecord的狀態,包括系統進程的ProcessRecord。 系統進程的ProcessRecord幾個重要的屬性值:

    • persistent=true: 系統進程的ProcessRecord是常駐內存的
    • maxAdj=SYSTEM_ADJ(-16): 在內存不足時,這個值越小,存活的概率就越大。SYSTEM_ADJ已是倒數第二小了,可見系統進程在內存不足時被殺的可能性極小。
    • active: 在上文中,咱們介紹過ProcessRecord有Active和InActive兩種狀態,所謂」激活」,就是將應用程序的信息(IApplicationThread)綁定到進程,這樣就可以經過ProcessRecord間接完成對進程的調度。

    AMS經過mPidSelfLocked這個映射表來記錄全部的ProcessRecord,(鍵 => 值)關係是(PID => ProcessRecord)。 在建立一個ProcessRecord以後,就須要集中對進程的信息進行調整了,AMS中管理進程的函數就兩類:updateLruProcessLocked()用於更新最近使用進程列表,updateOomAdjLocked()用戶更新進程的OOM ADJ。

3.AMS啓動的配套工做

在引導服務(BootstrapServices)啓動完畢後,SystemServer就開始啓動核心服務(CoreServices),包括電池服務(BatteryService),用戶行爲統計服務(UsageStatsService)等; 最後,就是啓動其餘服務了,很是之多,再也不此列舉。部分服務在啓動時,仍須要與AMS關聯,譬如: AMS須要與WindowManagerService關聯。AMS在這個過程之中有兩個關鍵的步驟:

  1. AMS.installSystemProviders(): 表示要裝載SettingsProvider, 不少系統服務都須要從這個數據庫中讀取配置信息;
  2. AMS.systemReady(): 表示當前SystemServer已經啓動完畢, AMS仍須要作一些準備就緒工做。

3.1 對於installSystemProviders的分析

關鍵函數 generateApplicationProvidersLocked()

該函數基於AndroidManifest.xml文件的定義, 生成一個應用程序的Provider信息, 以方便AMS對Provider進行管理,

AMS對Provider的管理方式:

  • AMS中使用ContentProviderRecord來管理一個ContentProvider。ProviderInfo, ApplicationInfo, 運行ContentProvider的ProcessRecord等信息都保存在ContentProviderRecord中。

  • AMS維護了一個ProviderMap, 支持從Authority或CompnentName到ContentProviderRecord的映射; AMS也維護了各類各樣的ProcessRecord, 譬如: 前臺進程, 內存常駐進程, 最近使用的進程等。 當一個ContentProvider綁定到具體的進程時, 就會添加到ProcessRecord中維護的mPubProviders的映射表中。因此, ProcessRecord.mPubProviders就表示進程所擁有的ContentProvider。

      如今,咱們再來看這塊函數的邏輯:

  • 首先, 須要確保ProcessRecord可以容納必定數量的Provider, 前面經過PackageManager找到的ProviderInfo可能會關聯到ProcessRecord中,因此, 在mPubProvider上已有容量的基礎上, 再擴容的大小爲找到的ProviderInfo的數量。

  • 而後, 對找到的ProviderInfo列表進行遍歷, 若有須要, 則新建一個ContentProviderRecord對象, 將其添加到mProviderMap中以方便AMS管理;同時, 也須要將其添加到PrcoessRecord.mPubProviders中。

  • 最後, 因爲可能新增其餘APK中的ProviderInfo, 因此須要確保對APK進行dex優化。

關鍵函數: ActivityThread.installSystemProviders()

將一個ProviderInfo綁定到ProcessRecord後, AMS中就有了Provider的信息了, 但這時Provider還不能工做, 由於真正的ContentProvider還未建立, 該函數的就是將上面找到的ProviderInfo裝載到系統進程之中

全部ContentProvider的建立都須要通過installContentProvider()函數, 它接收兩個參數, 一個是進程的運行環境Context, 一個是 ProviderInfo列表; 對系統進程而言, 運行環境就是mInitialApplication。該函數中使用了ContentProviderHodler這個類,它實現了Parcelable接口, 一般表示這類數據結構須要跨進程傳遞, 應用進程中生成的ContentProvider須要向系統進程註冊後才能使用, 因此, 須要將ContentProvider的信息從應用進程傳遞到系統進程, 這就用到了ContentProviderHolder進行數據封裝。

基於ProviderInfo生成的ContentProviderHolder的函數實現是installProvider():

3.2對於systemReady的分析

  1. mSystemReady表示系統進程是否準備完畢, 因爲systemReady()函數會被屢次調用到,並且多線程並行,因此一旦mSystemReady爲true,表示再也不須要執行下面的邏輯了,直接回調函數入參goingCallback,這個回調函數咱們放到後面分析;

  2. 進入這一步,表示mSystemReady爲false,第一次進入systemReady()函數時,就是這種場景。這裏會恢復最近任務列表;

  3. 涉及到PRE_BOOT_COMPLETED廣播的處理。這個廣播在BOOT_COMPLETED廣播以前發送,並且只發給系統應用。系統應用收到該廣播後,也應該標註已經處理過該廣播,下次不用再派發過來。設計PRE_BOOT_COMPLETED廣播的目的,是爲了應對系統升級的場景:當從舊的版本升級時,系統應用可能有一些清除數據的須要,系統升級後的第一次起機時,就會向接收者派發這個廣播。

PRE_BOOT_COMPLETED的派發實如今deliverPreBootCompleted()函數中,本文不展開分析。須要知道這裏有兩個控制變量:

  • mDidUpdate: 默認爲false; 若是爲true,表示已PRE_BOOT_COMPLETED已經處理完畢,確切的說是已經檢查完畢,由於在派發該廣播以前,要檢查是否已經向接收者派發過一次該廣播了; 之因此該變量取名爲update,是由於該廣播的設計與系統升級後的操做有關;
  • mWaitingUpdate: 默認爲false; 若是有PRE_BOOT_COMPLETED的接收者,並且以前沒有處理過該廣播,則這個變量會被true,直到廣播處理完成後才被從新置成false。

通過這3步mSystemReady就被設置爲true了,再次調用該systemReady()函數,就會進入第1步的邏輯

在AMS徹底準備就緒以前,就可能有一些進程已經啓動,在這裏須要進行一個檢查,若是非peristent的進程先於AMS啓動,那麼就須要殺掉這些進程。 注意,這裏所指的進程是AMS管理的進程(系統進程和應用進程),Native進程並不在AMS的管轄範圍。

在該代碼片斷的最後,輸出了一行Event Log:

boot_process_ams_ready: xxx

進行日誌分析時,能夠根據這行日誌信息斷定AMS已經準備就緒,其餘應用進程能夠啓動了。由於只有當AMS就緒後,才能開始管理應用進程。

AMS準備就緒是個關鍵節點,在此以後,不少其餘服務就能夠開始進入準備就緒的狀態了,其實就是調用這些系統服務的systemReady()函數。

systemReady()函數的最後部分,一部分工做是發送通知:「當前用戶已經進入使用狀態了」; 另外一部分工做就是啓動桌面,有兩處關鍵調用: startHomeActivityLocked()和mStackSupervisor.resumeTopActivitiesLocked()

至此,systemReady()函數的執行邏輯已經分析完了,一共經歷了4個步驟

  • 片斷1: 主要處理PRE_BOOT_COMPLETED廣播;
  • 片斷2: 殺掉在AMS準備就緒以前就已經啓動的進程。由於這些進程要被AMS管理起來,須要在AMS準備就緒以後才啓動;
  • 片斷3: 主要任務是通知其餘系統服務進入就緒狀態。在AMS就緒完畢後,從SettingsProvider和本地文件中(urigrants.xml)讀取一些配置信息。通知其餘系統服務進入就緒狀態,啓動SystemUi;
  • 片斷4: 主要任務是啓動桌面。

systemReady()函數調用完成以後,桌面就可見了,用戶就真正見到了Android系統的可操做界面

3.4 發送ACTION_BOOT_COMPLETED廣播

在桌面啓動後,桌面進程主線程的消息隊列進入空閒狀態,此時會發起跨進程調用AMS.activityIdle(),緊接着會引起下面的調用關係:



AMS.finishBooting()函數主要進行ABI檢查,註冊一些系統廣播,啓動以前被抑制啓動的進程,發送ACTION_BOOT_COMPLETED廣播,調度性能統計功能。

總結:AMS.activityIdle() └── ActivityStackSupervisor.activityIdleInternalLocked() └── ActivityStackSupervisor.checkFinishBootingLocked() └── AMS.postFinishBooting() // 向主線程拋出FINISH_BOOTING_MSG消息 └── AMS.MainHandler.handleMessage(FINISH_BOOTING_MSG) └── AMS.finishBooting()

   系統進程啓動過程當中與AMS相關的邏輯,整體而言,能夠分爲三步:

  1. 初始化系統進程的運行環境。所謂運行環境,就是指的Context,Context蘊含了代碼執行過程當中所須要的信息,包括進程信息、包信息、資源信息等等。Android有意弱化進程的概念,強化Context的概念,在Android編程時,必定避免不了與Context打交道。對於系統進程而言,Context有必定的特殊性,因此單獨造了一個SystemContext。

  2. 初始化AMS對象。AMS對象在系統進程構建,做爲最重要的系統服務,AMS初始化要作的事情很是多。因爲各類系統服務耦合在一塊,相互影響,Android設計了「系統進程啓動階段」這個概念,就像一個簡單的狀態機,只有進入的某個階段,才能作某些操做。譬如,只有進入PHASE_ACTIVITY_MANAGER_READY,AMS才能正常工做,這時才能夠進行派發廣播、管理進程等操做。

    由於系統進程也在AMS的管轄範圍以內,因此,AMS對象構建後有一個重要的任務,就是設置系統進程的一些屬性。這時,會將第一個啓動的應用frameworks-res.apk的信息裝載到系統進程中,建立一個系統進程的ProcessRecord對象以便AMS管理。

  3. AMS初始化的配套工做。這裏所謂配套工做是指,系統要徹底運行起來,還須要經由AMS進行一系列的運做:系統設置SettingsProvider會經由AMS裝載到系統進程中;其餘系統服務在AMS準備就緒後,也會進入就緒狀態,表示能夠正常工做;桌面會經由AMS啓動,最終ACTION_BOOT_COMPLETED廣播發出。

參考文章:http://duanqz.github.io/2016-07-15-AMS-LaunchProcess#3-%E6%80%BB%E7%BB%93

相關文章
相關標籤/搜索