Android源碼解析四大組件系列(二)---Activity啟動過程的總體把握

轉載請注明文章出處LooperJing

之前寫過Service的啟動過程,相對來說Activity的啟動過程比Service的啟動過程更為復雜,其一Activity的生命周期方法比Service多,其二Activity具有啟動模式和返回棧。寫本文的目的在于更清晰的梳理Activity的啟動過程,加強自己的內功修煉,博客粉絲日益增多,力在以最簡單的方式讓大家理解,跟大家一起學習。

Activity的啟動過程計劃用三篇博客來寫;

  • 第一篇(本文),側重Binder視角或者從進程這方面,對Activity啟動先從整體有個把握,代碼少,理論多。
  • 第二篇,深入源碼,分析Launcher進程向SystemServer進程發起startActivity請求,SystemServer進程在向zygote進程發起請求,最后孵化出應用進程的這一過程。
  • 第三篇:深入源碼,由Zygote進程孵化的應用進程是如何啟動Activity的。

一、Binder的基本理解

Activity的啟動有多次IPC過程,所以Binder屬于預備知識,幫助我們更好理解系統的C/S的這種架構模式,我看過幾篇文章還不錯,推薦給大家。

二、Activity啟動的雙向IPC過程

一般Android各個應用進程的啟動都以這樣一條路線,init進程 –> Zygote進程 –> SystemServer進程 –>各種應用進程

  • Init進程:Linux的根進程,Android系統是基于Linux系統的,因此可以算作是整個android操作系統的第一個進程;
  • Zygote進程是所有應用進程的父進程,所有的應用進程都是它孵化出來的;
  • SystemServer進程含有一些核心的服務,比如ActivityManagerService,PackageManagerService,WindowManagerService等;
  • 各種應用進程:啟動自己編寫的客戶端應用時,有自己的虛擬機與運行環境。

由此可知應用的第一個Activity的啟動是多個進程相互配合的結果,多個進程相互配合就少不了使用Binder進行IPC了,現在看一次IPC調用的過程是怎樣的。

Activity到AMS一次IPC調用

上圖大概說明了一次IPC的過程,或許你現在對里面各個類還不是很清楚,沒關系,大致了解一下

ActivityManagerService(下文簡稱AMS),AMS是Android中最核心的服務,實現了ActivityManager,主要負責系統中四大組件的啟動、切換、調度及應用進程的管理和調度等工作,AMS提供了一個ArrayList mHistory來管理所有的Activity,Activity在AMS中的形式是ActivityRecord,Task在AMS中的形式為TaskRecord,進程在AMS中的管理形式為ProcessRecord,它在Android中特別重要。

ActivityManagerNative(下文簡稱AMN):由于AMS是系統核心服務在SystemServer進程里面,很多API不能直接開放供客戶端使用,所以需要通過IPC的方式,具體是這樣的,ActivityManager類內部調用AMN的getDefault函數得到一個ActivityManagerProxy對象,通過它可與AMS通信。

ActivityManagerProxy(下文簡稱AMP):AMP是AMS在客戶端進程的一個代理,通過AMP里面的方法請求AMS。

Instrumentation:Instrumentaion是一個工具類,一個大管家。當它被啟用時,系統先創建它,再通過它來創建其他組件。另外,系統和組件之間的交互也將通過Instrumentation來傳遞,這樣,Instrumentation就能監測系統和這些組件的交互情況了。在實際使用中,我們可以創建Instrumentation的派生類來進行相應的處理。Android中Junit的使用到了Intrstrumentation。關于它更詳細的了解,戳我

OK,現在我們知道,Activity是如何向AMS發出startActivity這個請求了,這意味著Activity可以與AMS進行通信,但是AMS卻不能與Activity通信,Binder是單向的,所以在Activity發出請求之后,AMS需要通知Activity發生狀態改變,要做到這一點,自然就在AMS到Activity這個過程建立一個Binder,如下。

AMS到Activity的一次IPC過程

大致過程就是,SystemServer進程在收到請求后,再通過IPC向應用進程發送scheduleLaunchActivity請求,應用進程的binder線程(ApplicationThread)在收到請求后,通過handler向主線程發送LAUNCH_ACTIVITY消息,主線程在收到Message后,創建目標Activity,并回調Activity.onCreate()等方法。

對上面的理解不是太明白,在看下面這張圖,簡單多了,AMS到Activity這個過程建立了一個Binder,Activity到AMS這個過程也建立了一個Binder,這就能相互通信了。


雙向Binder的建立

上圖就是Activity與AMS之間的雙向Binder連接,(備注:這個就是理解Activity啟動流程的指南針,不記住這個,復雜的啟動流程會讓你暈頭轉向)。Activity用IActivityManager提供的API向AMS提出執行某個動作的請求(本例中是啟動RemoteService),AMS通過IApplicationThread提供的API來控制Activity所在的應用程序,這些API包括schedulePauseActivity()、scheduleStopActivity()等。

IActivityManager接口定義的API,啟動四大組件的等多種請求都在里面。


對IActivityManager了解更近一步

IApplicationThread接口定義的API,一看就比IActivityManager高逼格一點,IActivityManager好多方法是start開頭,表示去AMS請求,IApplicationThread以schedule開頭,表示對Activity進行調度。


對IApplicationThread了解更近一步

分析到這里,我們不知不覺間忽略了兩個問題,那就是啟動Activity至少需要兩個前提,第一是,應用進程存在,第二AMS已經初始化完畢。在調用startActivity方法時候,如果我們的應用進程不存在,Activity能啟動嗎,當然是不能的,比如點擊桌面圖標的時候,這個時候需要先創建進程。關于Zygote孵化應用進程,這個暫時不說,先看看AMS服務注冊。

三、AMS服務注冊

先忽略 Activity調用ActivityManagerService啟動應用,直接從SystemServer的main方法說起。

 SystemServer.java

 /**
    * The main entry point from zygote.
    */
   public static void main(String[] args) {
       new SystemServer().run();
   }

run方法中,調用了startBootstrapServices。

 private void startBootstrapServices() {
      
       ......
       //啟動AMS服務
       Installer installer = mSystemServiceManager.startService(Installer.class);

       //請注意這里參數是Lifecycle,因為AMS是在Lifecycle里面new出來的
       mActivityManagerService = mSystemServiceManager.startService(
               ActivityManagerService.Lifecycle.class).getService();
       mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
       mActivityManagerService.setInstaller(installer);

       mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);

       mActivityManagerService.initPowerManagement();

        ......
       mActivityManagerService.setSystemProcess();
     ......
}

 public SystemService startService(String className) {
       final Class<SystemService> serviceClass;
       try {
           serviceClass = (Class<SystemService>)Class.forName(className);
       } catch (ClassNotFoundException ex) {
           Slog.i(TAG, "Starting " + className);
       }
       return startService(serviceClass);
   }

繼續

public <T extends SystemService> T startService(Class<T> serviceClass) {
       try {
           final String name = serviceClass.getName();
           // 1、創建服務
           final T service;
           try {
               Constructor<T> constructor = serviceClass.getConstructor(Context.class);
             // 如果傳進來的是ActivityManagerService.Lifecycle對象,那么ActivityManagerService就能被創建
               service = constructor.newInstance(mContext);
           } catch (InstantiationException ex) {
               throw new RuntimeException("Failed to create service " + name
                       + ": service could not be instantiated", ex);
           }
           // 2、注冊服務
           mServices.add(service);

           // 3、啟動服務
           try {
               service.onStart();
           } catch (RuntimeException ex) {
               throw new RuntimeException("Failed to start service " + name
                       + ": onStart threw an exception", ex);
           }
           return service;
       } finally {
           Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
       }
   }
ActivityManagerService.java

  public static final class Lifecycle extends SystemService {
       private final ActivityManagerService mService;

       public Lifecycle(Context context) {
           super(context);
         //ActivityManagerService被new出來了
           mService = new ActivityManagerService(context);
       }

       @Override
       public void onStart() {
         //  啟動
           mService.start();
       }

       public ActivityManagerService getService() {
           return mService;
       }
   }

 private void start() {
       Process.removeAllProcessGroups();
       mProcessCpuThread.start();

       mBatteryStatsService.publish(mContext);
       mAppOpsService.publish(mContext);
       Slog.d("AppOps", "AppOpsService published");
       LocalServices.addService(ActivityManagerInternal.class, new LocalService());
   }

回到 startBootstrapServices里面調用的 mActivityManagerService.setSystemProcess();

public void setSystemProcess() {
       try {
           ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
           ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
           ServiceManager.addService("meminfo", new MemBinder(this));
           ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
           ServiceManager.addService("dbinfo", new DbBinder(this));
           ......


      // 設置application info LoadedApkinfo 有關 framework-res.apk
       ApplicationInfo info = mContext.getPackageManager().getApplicationInfo( "android", STOCK_PM_FLAGS);
       mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());
       
       //給SystemServer進程創建ProcessRecord,adj值,就是將SystemServer進程加入到AMS進程管理機制中,跟應用進程一致
       synchronized (this) {
           ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);
           app.persistent = true;
           app.pid = MY_PID;
           app.maxAdj = ProcessList.SYSTEM_ADJ;
           app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
           synchronized (mPidsSelfLocked) {
               mPidsSelfLocked.put(app.pid, app);
           }
           updateLruProcessLocked(app, false, null);
           updateOomAdjLocked();
 }

ServiceManager這里面注冊了很多的服務,可通過dumpsys <服務名>命令查看。比如查看CPU信息命令dumpsys cpuinfo,查看graphics信息命令dumpsys gfxinfo。在Android中所有的核心服務,并不是直接給上層使用,都先交給ServiceManager管理,上層使用的時候可以從ServiceManager獲取,ServiceManager相當于一個路由作用。現在來看一張經典的圖。其中注冊服務,獲取服務以及使用服務,每一次都是一個完整的Binder IPC過程,可見理解Binder是多么的重要啊。關于AMS啟動得深入了解,請戳我

  • 注冊服務:首先AMS注冊到ServiceManager。AMS所在進程(SystemServer)是客戶端,ServiceManager是服務端。
  • 獲取服務:Client進程使用AMS前,須先向ServiceManager中獲取AMS的代理類AMP。該過程。AMP所在進程(應用進程)是客戶端,ServiceManager是服務端。
  • 使用服務: app進程根據得到的代理類AMP,便可以直接與AMS所在進程交互。該過程,AMP所在進程(應用進程)是客戶端,AMS所在進程(SystemServer)是服務端。

OK ,本文終于寫完了,翻看源碼,查閱資料,畫圖花了兩天時間,最后回顧一下,本文解釋了雙向Binder是如何建立的?這個是最重要的部分,其次AMS作為管理Android系統組件的核心服務,AMS是如何注冊的?(在SystemServer執行run()方法的時候被創建,并運行在獨立的進程中)。OK,see you。

·

Please accept mybest wishes for your happiness and success

參考鏈接:

http://www.cloudchou.com/android/post-788.html

[Android源碼解析之(八)-->Zygote進程啟動流程]
(http://blog.csdn.net/qq_23547831/article/details/51104873)

[深入理解Android卷二 全文-第六章]深入理解ActivityManagerService

深入AndroidFramework源碼內部剖析Service的啟動過程

Android系統啟動-SystemServer

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,622評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,716評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,746評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,991評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,706評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,036評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,029評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,203評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,725評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,451評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,677評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,161評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,857評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,266評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,606評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,407評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,643評論 2 380

推薦閱讀更多精彩內容