安卓應(yīng)用啟動(dòng)簡介

  1. 安卓系統(tǒng)中,組件踢代,應(yīng)用,與進(jìn)程的關(guān)系:

    1. 一個(gè)組件需要依附于一個(gè)應(yīng)用(其對(duì)應(yīng)Application類必須先初始化戒劫,ContentProvider除外半夷,看后面)
    2. 一個(gè)應(yīng)用可以擁有多個(gè)進(jìn)程(其Application對(duì)象在每個(gè)進(jìn)程中被初始化一遍)
    3. 一個(gè)進(jìn)程可以承載多個(gè)應(yīng)用 (一個(gè)進(jìn)程可以擁有多個(gè)Application對(duì)象)
  2. 例子:

    1. 通常情況婆廊,一個(gè)應(yīng)用運(yùn)行與一個(gè)進(jìn)程,對(duì)應(yīng)一個(gè)Application對(duì)象
    2. 一個(gè)應(yīng)用中巫橄,某些組件在注冊(cè)清單中指定了不同進(jìn)程淘邻,則啟動(dòng)時(shí)會(huì)將這些組件在對(duì)應(yīng)進(jìn)程中啟動(dòng),且在這之前湘换,會(huì)在每個(gè)對(duì)應(yīng)進(jìn)程中初始化這個(gè)應(yīng)用的Application對(duì)象宾舅。
    3. 一個(gè)進(jìn)程承載多個(gè)應(yīng)用,若多個(gè)應(yīng)用指定相同UID彩倚,且擁有相同簽名筹我,則這些應(yīng)用可以運(yùn)作在同一個(gè)進(jìn)程,則每個(gè)應(yīng)用的Application都會(huì)在這個(gè)進(jìn)程中初始化
  3. 四大組件的啟動(dòng)都涉及到進(jìn)程和應(yīng)用的啟動(dòng)帆离,我們這里以最常見的Activity的啟動(dòng)來解析安卓應(yīng)用的啟動(dòng)流程蔬蕊,以下是Activity的啟動(dòng)分類:

Activity啟動(dòng)分類.png

四種判斷結(jié)果分別各舉一例情況:

  1. Activity已經(jīng)以SingleTask,SingleTop哥谷,SingleInstance 模式啟動(dòng)岸夯,當(dāng)有其它意圖再次啟動(dòng)該Activity 時(shí),不再重復(fù)創(chuàng)建實(shí)例们妥,當(dāng)前Activity走onNewIntent方法猜扮,獲取外部傳入的數(shù)據(jù),并根據(jù)當(dāng)前Activity所處的情況监婶,走其它生命周期旅赢。
  2. Activity以普通啟動(dòng)模式,此情況為一般情況压储,直接創(chuàng)建Activity實(shí)例鲜漩,并走生命周期。
  3. UserId和簽名相同的應(yīng)用可以運(yùn)行于同一個(gè)進(jìn)程中集惋,當(dāng)需要啟動(dòng)應(yīng)用時(shí)孕似,若判斷出這個(gè)進(jìn)程已經(jīng)啟動(dòng),則在對(duì)應(yīng)進(jìn)程中刮刑,完成應(yīng)用的Application的實(shí)例化和生命周期喉祭,再完成Activity的實(shí)例化與生命周期。
  4. 在進(jìn)程也不存在的情況下雷绢,則先讓進(jìn)程啟動(dòng)泛烙,完成初始化工作,再在進(jìn)程完成Application的實(shí)例化與生命周期翘紊,再讓后完成Activity的實(shí)例化與生命周期蔽氨。

以下具體分析第四種情況,即需要啟動(dòng)的Activity所需依附的進(jìn)程未啟動(dòng)

概念明確:

  1. 安卓的四大組件的管理全部由ActivityManagerService(以下簡稱AMS)及其幾個(gè)協(xié)助類完成,啟動(dòng)Activity時(shí)鹉究,我們需要向AMS發(fā)出我們的啟動(dòng)意圖宇立,AMS會(huì)解析意圖,并作出對(duì)應(yīng)的處理自赔。
  2. Binder作為安卓的IPC機(jī)制妈嘹,其分為C/S兩端。Server端接收Client端發(fā)過來的數(shù)據(jù)并作出處理绍妨,并返回處理結(jié)果润脸。
  3. Binder服務(wù)端的對(duì)象,當(dāng)被Binder客戶端跨進(jìn)程調(diào)用時(shí)他去,其方法的執(zhí)行是在Binder線程里毙驯。
  4. Binder分為匿名Binder和有名Binder,有名可以直接通過ServiceManager獲取孤页,即通過鍵名查詢到對(duì)應(yīng)的Binder尔苦。匿名Binder未將自己注冊(cè)到ServiceManager,所以不能通過鍵名獲取到行施。
  5. AMS本身為Binder子類允坚,為一個(gè)Binder服務(wù)端,工作在system_server進(jìn)程蛾号,其在系統(tǒng)啟動(dòng)時(shí)將自己注冊(cè)入ServiceManager稠项,所以其為有名Binder,與服務(wù)端對(duì)應(yīng)的客戶端BinderProxy對(duì)象存在于各個(gè)應(yīng)用進(jìn)程里鲜结,但通常使用其封裝類ActivityManagerProxy(AMP)展运,與AMS完成遠(yuǎn)程調(diào)用。
  6. Binder可以通過Binder傳遞精刷,要使用匿名Binder拗胜,需要先利用其它Binder獲取到這個(gè)匿名Binder,如應(yīng)用進(jìn)程就在啟動(dòng)時(shí)將自己的匿名Binder ApplicationThread通過AMS/AMP傳遞給了system_server進(jìn)程怒允,這樣system_server進(jìn)程就存有了應(yīng)用進(jìn)程的Binder客戶端埂软,可以通過這個(gè)客戶端調(diào)用應(yīng)用進(jìn)程的方法,從而實(shí)現(xiàn)對(duì)應(yīng)用的管理纫事。
  7. Instrumentation勘畔,用于管理應(yīng)用程序和系統(tǒng)(主要與應(yīng)用程序內(nèi)的Activity)的交互過程,如startActivity時(shí)由Instrumentation對(duì)象將請(qǐng)求發(fā)往AMS,而系統(tǒng)對(duì)組件管理通Instrumentation對(duì)象實(shí)現(xiàn)丽惶,如Activity對(duì)象創(chuàng)建與生命周期的調(diào)用炫七,Instrumentation將在應(yīng)用初始化時(shí)被初始化,每個(gè)進(jìn)程只會(huì)存在一個(gè)Instrumentation對(duì)象钾唬,且每個(gè)Activity都有此對(duì)象的引用万哪,
  8. AMS 對(duì)四大組件的管理具體實(shí)現(xiàn)是由幾個(gè)類的協(xié)助完成的侠驯,ActivityStarter對(duì)應(yīng)Activity,ActiveService 對(duì)應(yīng)service壤圃,BroadcastQueue對(duì)應(yīng)Broadcast陵霉。與Activity相關(guān)還涉及到ActivityStack和ActivityStackSupervisor,負(fù)責(zé)Activity伍绳,Task與Stack管理,Activity啟動(dòng)過程中乍桂,AMS冲杀,ActivityStarter,ActivityStack睹酌,ActivityStackSupervisor需要協(xié)同工作权谁,以下我們稱這幾個(gè)類為AMS模塊。
  9. ActivityThread憋沿,與其內(nèi)部類ApplicationThread協(xié)同旺芽,與AMS交互,其mian方法可以理解為應(yīng)用進(jìn)程的根方法辐啄,進(jìn)程初始化完成后主線程會(huì)進(jìn)入Looper循環(huán)采章,開始接收ApplicationThread轉(zhuǎn)發(fā)過來的消息。
  10. ApplicationThread壶辜,Binder子類悯舟,匿名Binder,作為Binder服務(wù)端砸民,接收AMS發(fā)過來的消息抵怎,由于服務(wù)端的方法在Binder調(diào)用時(shí)都運(yùn)行在Binder線程,所以需要再通過Hander轉(zhuǎn)發(fā)到主線程中岭参,ApplicationThread接收到的調(diào)用都會(huì)通過Handler再轉(zhuǎn)到主線程中處理反惕,對(duì)應(yīng)的處理方法都是ActivityThread的方法。

啟動(dòng)流程:

調(diào)用流程.png
  1. 從startActivity開始演侯,Activity重寫了Context的startActivity方法姿染,但大致流程是不變的,以下為Lancher應(yīng)用啟動(dòng)一個(gè)應(yīng)用時(shí)主線程的調(diào)用棧:

    img

    可以看出:

    1. Activity的startActivity走了startActivityForResult方法
    2. startActivityForResult調(diào)用了Instrumentation的execStartActivity方法
    3. Instrumentation 最終調(diào)用AMP的startActivity蚌本,AMP會(huì)將Intent傳遞給AMS盔粹,所以現(xiàn)在system_server進(jìn)程里就會(huì)有一個(gè)Binder線程會(huì)去調(diào)用AMS的startActivity 方法,這次調(diào)用中做了幾件重要的事:
      1. 解析Intent程癌,并根據(jù)pkms掃描到的信息舷嗡,創(chuàng)建對(duì)應(yīng)的ActivityRecord,每一個(gè)ActivityRecord對(duì)應(yīng)一個(gè)應(yīng)用進(jìn)程中的Activity實(shí)例嵌莉,ActivityRecord中還會(huì)創(chuàng)建這個(gè)Activity對(duì)應(yīng)的唯一的token进萄,其會(huì)在Activity創(chuàng)建時(shí)被傳遞給對(duì)應(yīng)的Activity,
      2. 通知WMS,顯示startWindow 中鼠,即對(duì)應(yīng)應(yīng)用Activity的主題里面windowBackground對(duì)應(yīng)資源可婶,這個(gè)窗口由system_server進(jìn)程顯示,不必等到應(yīng)用進(jìn)程啟動(dòng)后再顯示援雇,所以其啟動(dòng)速度很快矛渴。
      3. 遠(yuǎn)程調(diào)用當(dāng)前前臺(tái)Activity的schedulePause方法,對(duì)應(yīng)Activity的主線程會(huì)走onPause生命周期惫搏。 走完后具温,其會(huì)再通知AMS,它已經(jīng)走完onPause筐赔,AMS開始準(zhǔn)備啟動(dòng)目標(biāo)Activity铣猩。
  2. 在ActivityStackSupervisor這個(gè)類中,判斷出 要啟動(dòng)的Activity所需要的進(jìn)程還未啟動(dòng)茴丰,所以需要先啟動(dòng)其進(jìn)程:

    1. AMS 通知Zygote 進(jìn)程啟動(dòng)一個(gè)應(yīng)用進(jìn)程达皿,這個(gè)IPC是socket,Zygote 進(jìn)程收到消息后fork出一個(gè)進(jìn)程贿肩,這個(gè)進(jìn)程就是新的Activity所需依附的應(yīng)用進(jìn)程峦椰,應(yīng)用進(jìn)程被fork出來之后,將AMS傳遞過來的參數(shù)配置給自己尸曼,然后就會(huì)反射調(diào)用ActivityThread的main方法们何。

    2. 此時(shí)AMS對(duì)這個(gè)新進(jìn)程還是無感知的,需要新進(jìn)程主動(dòng)‘聯(lián)系’AMS控轿,所以進(jìn)程進(jìn)入ActivityThread的main之后冤竹,主要做兩件事:

      1. 實(shí)例化自身,進(jìn)而實(shí)例化其成員變量ApplicationThread(匿名Binder服務(wù)端)茬射,通過AMP遠(yuǎn)程調(diào)用AMS的attachApplication方法鹦蠕,把自己的ApplicationThread傳遞給AMS模塊,現(xiàn)在AMS就知道新進(jìn)程已經(jīng)創(chuàng)建完畢在抛,并得到了其ApplicationThread客戶端钟病,可以通過這個(gè)Binder遠(yuǎn)程管理應(yīng)用進(jìn)程。

        final IActivityManager mgr = ActivityManagerNative.getDefault();
        try {
            mgr.attachApplication(mAppThread);
        } catch (RemoteException ex) {
            // Ignore
        }
        
      2. 調(diào)用Looper.prepareMainLooper 準(zhǔn)備主線程Looper刚梭, Looper.loop() 進(jìn)入循環(huán)肠阱,等待外界發(fā)來消息,此時(shí)朴读,應(yīng)用的進(jìn)程初始化算完成屹徘,從被fork出來到配置參數(shù),到將自己注冊(cè)入AMS衅金,再Loop主線程進(jìn)入循環(huán)噪伊,等待外部消息簿煌。

    3. 啟動(dòng)Application:

      以上完成了應(yīng)用進(jìn)程的初始化,AMS模塊在收到應(yīng)用進(jìn)程發(fā)過來消息后鉴吹,會(huì)連續(xù)做兩件事姨伟,應(yīng)用的啟動(dòng)和組件的啟動(dòng),這里就是Activity的啟動(dòng)豆励。

      AMS收到應(yīng)用進(jìn)程準(zhǔn)備完畢的消息后夺荒,會(huì)通過傳遞過來的ApplicationThread,調(diào)用其bindApplication方法肆糕,然后在應(yīng)用進(jìn)程中般堆,ApplicationThread將這消息轉(zhuǎn)發(fā)給主線程,所以在ActivityThread中會(huì)走到handleBindApplication诚啃,這個(gè)方法里完成:

      1. Application的實(shí)例化,在LoadedApk里面完成私沮,并添加到ActivityThead中的Application列表始赎。

        try {
            java.lang.ClassLoader cl = getClassLoader();
            if (!mPackageName.equals("android")) {
                initializeJavaContextClassLoader();
            }
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        } catch (Exception e) {
            if (!mActivityThread.mInstrumentation.onException(app, e)) {
                throw new RuntimeException(
                    "Unable to instantiate application " + appClass
                    + ": " + e.toString(), e);
            }
        }
        mActivityThread.mAllApplications.add(app);
        mApplication = app;
        
        mInitialApplication = app;
        

        并復(fù)制給mInitialApplication,這個(gè)變量保存安卓進(jìn)程中第一個(gè)啟動(dòng)的Application仔燕,如果多個(gè)應(yīng)用共享進(jìn)程造垛,那這個(gè)變量就是第一個(gè)啟動(dòng)的應(yīng)用的Application

      2. ContentProvider的實(shí)例化和onCreate,并注冊(cè)到AMS

      3. Application的onCreate

    4. Activity的啟動(dòng)

      bindApplication之后晰搀,AMS模塊接著就會(huì)調(diào)用realStartActivityLocked五辽,同樣是通過ApplicationThread,調(diào)用其scheduleLaunchActivity外恕,同樣通過Handler轉(zhuǎn)到主線程杆逗,調(diào)用ActivityThread的handleLaunchActivity 方法,這里這個(gè)方法里完成幾件事:

      1. Activity的對(duì)象創(chuàng)建鳞疲,通過Instrumentation完成

      2. 調(diào)用Activity的attach罪郊,這里面會(huì)將一個(gè)contextImpl對(duì)象傳遞給Activity,Activity本身是ContextWrapper尚洽,很多操作是委托給contextImpl完成的悔橄,同時(shí)還會(huì)創(chuàng)PhoneWindow對(duì)象作為成員變量

      3. 走生命周期

        if (r.isPersistable()) {
            mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
        } else {
            mInstrumentation.callActivityOnCreate(activity, r.state);
        }
        ////////////////////
        if (!r.activity.mFinished) {
            activity.performStart();
        }
        ////////////////////
        performResumeActivity(token, clearHide);
        

        分別會(huì)調(diào)用Activity的onCreate,onStart腺毫,onResume癣疟,方法

      4. 將視圖添加到WMS

        從PhoneWindow拿到DecorView,調(diào)用WindowManager的addView潮酒,addView里面會(huì)走到WindowManagerGlobal里面睛挚,創(chuàng)建ViewRootImpl,完成與WMS的通信澈灼,之后開始繪制視圖

        r.window = r.activity.getWindow();
        View decor = r.window.getDecorView();
        decor.setVisibility(View.INVISIBLE);
        ViewManager wm = a.getWindowManager();
        WindowManager.LayoutParams l = r.window.getAttributes();
        a.mDecor = decor;
        l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
        l.softInputMode |= forwardBit;
        if (a.mVisibleFromClient) {
            a.mWindowAdded = true;
            wm.addView(decor, l);
        }
        
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末竞川,一起剝皮案震驚了整個(gè)濱河市店溢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌委乌,老刑警劉巖床牧,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異遭贸,居然都是意外死亡戈咳,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門壕吹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來著蛙,“玉大人,你說我怎么就攤上這事耳贬√けぃ” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵咒劲,是天一觀的道長顷蟆。 經(jīng)常有香客問我,道長腐魂,這世上最難降的妖魔是什么帐偎? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮蛔屹,結(jié)果婚禮上削樊,老公的妹妹穿的比我還像新娘。我一直安慰自己兔毒,他們只是感情好漫贞,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著眼刃,像睡著了一般绕辖。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上擂红,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天仪际,我揣著相機(jī)與錄音,去河邊找鬼昵骤。 笑死树碱,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的变秦。 我是一名探鬼主播成榜,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蹦玫!你這毒婦竟也來了赎婚?” 一聲冷哼從身側(cè)響起刘绣,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎挣输,沒想到半個(gè)月后纬凤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡撩嚼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年停士,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片完丽。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡恋技,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出逻族,到底是詐尸還是另有隱情蜻底,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布聘鳞,位于F島的核電站朱躺,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏搁痛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一宇弛、第九天 我趴在偏房一處隱蔽的房頂上張望鸡典。 院中可真熱鬧,春花似錦枪芒、人聲如沸彻况。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纽甘。三九已至,卻和暖如春抽碌,著一層夾襖步出監(jiān)牢的瞬間悍赢,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國打工货徙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留左权,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓痴颊,卻偏偏與公主長得像赏迟,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蠢棱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

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