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

轉(zhuǎn)載請(qǐng)注明文章出處LooperJing辛友!

之前寫過Service的啟動(dòng)過程办陷,相對(duì)來說Activity的啟動(dòng)過程比Service的啟動(dòng)過程更為復(fù)雜膨报,其一Activity的生命周期方法比Service多瞳步,其二Activity具有啟動(dòng)模式和返回棧抠璃。寫本文的目的在于更清晰的梳理Activity的啟動(dòng)過程术奖,加強(qiáng)自己的內(nèi)功修煉礁遵,博客粉絲日益增多,力在以最簡(jiǎn)單的方式讓大家理解采记,跟大家一起學(xué)習(xí)佣耐。

Activity的啟動(dòng)過程計(jì)劃用三篇博客來寫淹接;

  • 第一篇(本文)背稼,側(cè)重Binder視角或者從進(jìn)程這方面,對(duì)Activity啟動(dòng)先從整體有個(gè)把握磅氨,代碼少既棺,理論多讽挟。
  • 第二篇,深入源碼丸冕,分析Launcher進(jìn)程向SystemServer進(jìn)程發(fā)起startActivity請(qǐng)求,SystemServer進(jìn)程在向zygote進(jìn)程發(fā)起請(qǐng)求耽梅,最后孵化出應(yīng)用進(jìn)程的這一過程。
  • 第三篇:深入源碼胖烛,由Zygote進(jìn)程孵化的應(yīng)用進(jìn)程是如何啟動(dòng)Activity的眼姐。

一、Binder的基本理解

Activity的啟動(dòng)有多次IPC過程佩番,所以Binder屬于預(yù)備知識(shí)众旗,幫助我們更好理解系統(tǒng)的C/S的這種架構(gòu)模式,我看過幾篇文章還不錯(cuò)趟畏,推薦給大家逝钥。

二益眉、Activity啟動(dòng)的雙向IPC過程

一般Android各個(gè)應(yīng)用進(jìn)程的啟動(dòng)都以這樣一條路線晌柬,init進(jìn)程 –> Zygote進(jìn)程 –> SystemServer進(jìn)程 –>各種應(yīng)用進(jìn)程

  • Init進(jìn)程:Linux的根進(jìn)程姥份,Android系統(tǒng)是基于Linux系統(tǒng)的,因此可以算作是整個(gè)android操作系統(tǒng)的第一個(gè)進(jìn)程年碘;
  • Zygote進(jìn)程是所有應(yīng)用進(jìn)程的父進(jìn)程澈歉,所有的應(yīng)用進(jìn)程都是它孵化出來的;
  • SystemServer進(jìn)程含有一些核心的服務(wù)屿衅,比如ActivityManagerService埃难,PackageManagerService,WindowManagerService等涤久;
  • 各種應(yīng)用進(jìn)程:?jiǎn)?dòng)自己編寫的客戶端應(yīng)用時(shí)涡尘,有自己的虛擬機(jī)與運(yùn)行環(huán)境。

由此可知應(yīng)用的第一個(gè)Activity的啟動(dòng)是多個(gè)進(jìn)程相互配合的結(jié)果响迂,多個(gè)進(jìn)程相互配合就少不了使用Binder進(jìn)行IPC了考抄,現(xiàn)在看一次IPC調(diào)用的過程是怎樣的。

Activity到AMS一次IPC調(diào)用

上圖大概說明了一次IPC的過程蔗彤,或許你現(xiàn)在對(duì)里面各個(gè)類還不是很清楚川梅,沒關(guān)系,大致了解一下

ActivityManagerService(下文簡(jiǎn)稱AMS)然遏,AMS是Android中最核心的服務(wù)挑势,實(shí)現(xiàn)了ActivityManager,主要負(fù)責(zé)系統(tǒng)中四大組件的啟動(dòng)啦鸣、切換潮饱、調(diào)度及應(yīng)用進(jìn)程的管理和調(diào)度等工作,AMS提供了一個(gè)ArrayList mHistory來管理所有的Activity诫给,Activity在AMS中的形式是ActivityRecord香拉,Task在AMS中的形式為TaskRecord,進(jìn)程在AMS中的管理形式為ProcessRecord中狂,它在Android中特別重要凫碌。

ActivityManagerNative(下文簡(jiǎn)稱AMN):由于AMS是系統(tǒng)核心服務(wù)在SystemServer進(jìn)程里面,很多API不能直接開放供客戶端使用胃榕,所以需要通過IPC的方式盛险,具體是這樣的,ActivityManager類內(nèi)部調(diào)用AMN的getDefault函數(shù)得到一個(gè)ActivityManagerProxy對(duì)象勋又,通過它可與AMS通信苦掘。

ActivityManagerProxy(下文簡(jiǎn)稱AMP):AMP是AMS在客戶端進(jìn)程的一個(gè)代理,通過AMP里面的方法請(qǐng)求AMS楔壤。

Instrumentation:Instrumentaion是一個(gè)工具類鹤啡,一個(gè)大管家。當(dāng)它被啟用時(shí)蹲嚣,系統(tǒng)先創(chuàng)建它递瑰,再通過它來創(chuàng)建其他組件祟牲。另外,系統(tǒng)和組件之間的交互也將通過Instrumentation來傳遞抖部,這樣说贝,Instrumentation就能監(jiān)測(cè)系統(tǒng)和這些組件的交互情況了。在實(shí)際使用中慎颗,我們可以創(chuàng)建Instrumentation的派生類來進(jìn)行相應(yīng)的處理乡恕。Android中Junit的使用到了Intrstrumentation。關(guān)于它更詳細(xì)的了解哗总,戳我几颜。

OK倍试,現(xiàn)在我們知道讯屈,Activity是如何向AMS發(fā)出startActivity這個(gè)請(qǐng)求了,這意味著Activity可以與AMS進(jìn)行通信县习,但是AMS卻不能與Activity通信涮母,Binder是單向的,所以在Activity發(fā)出請(qǐng)求之后躁愿,AMS需要通知Activity發(fā)生狀態(tài)改變叛本,要做到這一點(diǎn),自然就在AMS到Activity這個(gè)過程建立一個(gè)Binder彤钟,如下来候。

AMS到Activity的一次IPC過程

大致過程就是,SystemServer進(jìn)程在收到請(qǐng)求后逸雹,再通過IPC向應(yīng)用進(jìn)程發(fā)送scheduleLaunchActivity請(qǐng)求营搅,應(yīng)用進(jìn)程的binder線程(ApplicationThread)在收到請(qǐng)求后,通過handler向主線程發(fā)送LAUNCH_ACTIVITY消息梆砸,主線程在收到Message后转质,創(chuàng)建目標(biāo)Activity,并回調(diào)Activity.onCreate()等方法帖世。

對(duì)上面的理解不是太明白休蟹,在看下面這張圖,簡(jiǎn)單多了日矫,AMS到Activity這個(gè)過程建立了一個(gè)Binder赂弓,Activity到AMS這個(gè)過程也建立了一個(gè)Binder,這就能相互通信了哪轿。


雙向Binder的建立

上圖就是Activity與AMS之間的雙向Binder連接拣展,(備注:這個(gè)就是理解Activity啟動(dòng)流程的指南針,不記住這個(gè)缔逛,復(fù)雜的啟動(dòng)流程會(huì)讓你暈頭轉(zhuǎn)向)备埃。Activity用IActivityManager提供的API向AMS提出執(zhí)行某個(gè)動(dòng)作的請(qǐng)求(本例中是啟動(dòng)RemoteService)姓惑,AMS通過IApplicationThread提供的API來控制Activity所在的應(yīng)用程序,這些API包括schedulePauseActivity()按脚、scheduleStopActivity()等于毙。

IActivityManager接口定義的API,啟動(dòng)四大組件的等多種請(qǐng)求都在里面辅搬。


對(duì)IActivityManager了解更近一步

IApplicationThread接口定義的API唯沮,一看就比IActivityManager高逼格一點(diǎn),IActivityManager好多方法是start開頭堪遂,表示去AMS請(qǐng)求介蛉,IApplicationThread以schedule開頭,表示對(duì)Activity進(jìn)行調(diào)度溶褪。


對(duì)IApplicationThread了解更近一步

分析到這里币旧,我們不知不覺間忽略了兩個(gè)問題,那就是啟動(dòng)Activity至少需要兩個(gè)前提猿妈,第一是吹菱,應(yīng)用進(jìn)程存在,第二AMS已經(jīng)初始化完畢彭则。在調(diào)用startActivity方法時(shí)候鳍刷,如果我們的應(yīng)用進(jìn)程不存在,Activity能啟動(dòng)嗎俯抖,當(dāng)然是不能的输瓜,比如點(diǎn)擊桌面圖標(biāo)的時(shí)候,這個(gè)時(shí)候需要先創(chuàng)建進(jìn)程芬萍。關(guān)于Zygote孵化應(yīng)用進(jìn)程尤揣,這個(gè)暫時(shí)不說,先看看AMS服務(wù)注冊(cè)担忧。

三芹缔、AMS服務(wù)注冊(cè)

先忽略 Activity調(diào)用ActivityManagerService啟動(dòng)應(yīng)用,直接從SystemServer的main方法說起瓶盛。

 SystemServer.java

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

run方法中最欠,調(diào)用了startBootstrapServices。

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

       //請(qǐng)注意這里參數(shù)是Lifecycle惩猫,因?yàn)锳MS是在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);
   }

繼續(xù)

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

           // 3拌阴、啟動(dòng)服務(wù)
           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() {
         //  啟動(dòng)
           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里面調(diào)用的 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));
           ......


      // 設(shè)置application info LoadedApkinfo 有關(guān) framework-res.apk
       ApplicationInfo info = mContext.getPackageManager().getApplicationInfo( "android", STOCK_PM_FLAGS);
       mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());
       
       //給SystemServer進(jìn)程創(chuàng)建ProcessRecord,adj值奶镶,就是將SystemServer進(jìn)程加入到AMS進(jìn)程管理機(jī)制中迟赃,跟應(yīng)用進(jìn)程一致
       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這里面注冊(cè)了很多的服務(wù)陪拘,可通過dumpsys <服務(wù)名>命令查看。比如查看CPU信息命令dumpsys cpuinfo纤壁,查看graphics信息命令dumpsys gfxinfo左刽。在Android中所有的核心服務(wù),并不是直接給上層使用酌媒,都先交給ServiceManager管理欠痴,上層使用的時(shí)候可以從ServiceManager獲取,ServiceManager相當(dāng)于一個(gè)路由作用∶胱桑現(xiàn)在來看一張經(jīng)典的圖喇辽。其中注冊(cè)服務(wù),獲取服務(wù)以及使用服務(wù)雨席,每一次都是一個(gè)完整的Binder IPC過程菩咨,可見理解Binder是多么的重要啊。關(guān)于AMS啟動(dòng)得深入了解舅世,請(qǐng)戳我旦委。

  • 注冊(cè)服務(wù):首先AMS注冊(cè)到ServiceManager奇徒。AMS所在進(jìn)程(SystemServer)是客戶端雏亚,ServiceManager是服務(wù)端。
  • 獲取服務(wù):Client進(jìn)程使用AMS前摩钙,須先向ServiceManager中獲取AMS的代理類AMP罢低。該過程。AMP所在進(jìn)程(應(yīng)用進(jìn)程)是客戶端胖笛,ServiceManager是服務(wù)端网持。
  • 使用服務(wù): app進(jìn)程根據(jù)得到的代理類AMP,便可以直接與AMS所在進(jìn)程交互。該過程长踊,AMP所在進(jìn)程(應(yīng)用進(jìn)程)是客戶端功舀,AMS所在進(jìn)程(SystemServer)是服務(wù)端。

OK 身弊,本文終于寫完了辟汰,翻看源碼,查閱資料阱佛,畫圖花了兩天時(shí)間帖汞,最后回顧一下,本文解釋了雙向Binder是如何建立的凑术?這個(gè)是最重要的部分翩蘸,其次AMS作為管理Android系統(tǒng)組件的核心服務(wù),AMS是如何注冊(cè)的淮逊?(在SystemServer執(zhí)行run()方法的時(shí)候被創(chuàng)建催首,并運(yùn)行在獨(dú)立的進(jìn)程中)扶踊。OK,see you郎任。

·

Please accept mybest wishes for your happiness and success

參考鏈接:

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

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

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

深入AndroidFramework源碼內(nèi)部剖析Service的啟動(dòng)過程

Android系統(tǒng)啟動(dòng)-SystemServer

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末姻檀,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子涝滴,更是在濱河造成了極大的恐慌绣版,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件歼疮,死亡現(xiàn)場(chǎng)離奇詭異杂抽,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)韩脏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門缩麸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人赡矢,你說我怎么就攤上這事杭朱。” “怎么了吹散?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵弧械,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我空民,道長(zhǎng)刃唐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任界轩,我火速辦了婚禮画饥,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘浊猾。我一直安慰自己抖甘,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布葫慎。 她就那樣靜靜地躺著衔彻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪幅疼。 梳的紋絲不亂的頭發(fā)上米奸,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音爽篷,去河邊找鬼悴晰。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的铡溪。 我是一名探鬼主播漂辐,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼棕硫!你這毒婦竟也來了髓涯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤哈扮,失蹤者是張志新(化名)和其女友劉穎纬纪,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體滑肉,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡包各,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了靶庙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片问畅。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖六荒,靈堂內(nèi)的尸體忽然破棺而出护姆,到底是詐尸還是另有隱情,我是刑警寧澤掏击,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布卵皂,位于F島的核電站,受9級(jí)特大地震影響铐料,放射性物質(zhì)發(fā)生泄漏渐裂。R本人自食惡果不足惜豺旬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一钠惩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧族阅,春花似錦篓跛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鲤遥,卻和暖如春沐寺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背盖奈。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來泰國打工混坞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓究孕,卻偏偏與公主長(zhǎng)得像啥酱,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子厨诸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容