Android四大組件

frameworks/base/services/core/java/com/android/server/am/
  - ActivityManagerService.java
  - ProcessRecord
  - ActivityStackSupervisor.java 
  - ActivityStack.java
  - ActiveServices
  - BroadcastQueue

一. 引言

Android系統(tǒng)內(nèi)部非常復(fù)雜缘眶,經(jīng)層層封裝后,app只需要簡(jiǎn)單的幾行代碼便可完成任一組件的啟動(dòng)/結(jié)束、 生命周期的操作面殖。然而每一次看似簡(jiǎn)單的操作,背后所有的復(fù)雜工作都是交由系統(tǒng)來完成哭廉。

組件啟動(dòng)后脊僚,首先需要依賴進(jìn)程,那么就需要先創(chuàng)建進(jìn)程遵绰,系統(tǒng)需要記錄每個(gè)進(jìn)程辽幌,這便產(chǎn)生了ProcessRecord。 Android中椿访,對(duì)于進(jìn)程的概念被弱化乌企,通過抽象后的四大組件。讓開發(fā)者幾乎感受不到進(jìn)程的存在成玫。 當(dāng)應(yīng)用退出時(shí)加酵,進(jìn)程也并非馬上退出,而是成為cache/empty進(jìn)程哭当,下次該應(yīng)用再啟動(dòng)的時(shí)候虽画,可以不用 再創(chuàng)建進(jìn)程直接初始化組件即可,提高啟動(dòng)速度荣病。先來說一說進(jìn)程码撰。

二. 進(jìn)程管理

Android系統(tǒng)中用于描述進(jìn)程的數(shù)據(jù)結(jié)構(gòu)是ProcessRecord對(duì)象,AMS便是管理進(jìn)程的核心模塊个盆。四大組件 (Activity,Service, BroadcastReceiver, ContentProvider)定義在AndroidManifest.xml文件脖岛, 每一項(xiàng)都可以用屬性android:process指定所運(yùn)行的進(jìn)程。同一個(gè)app可以運(yùn)行在通過一個(gè)進(jìn)程颊亮,也可以運(yùn)行在多個(gè)進(jìn)程柴梆, 甚至多個(gè)app可以共享同一個(gè)進(jìn)程。例如:AndroidManifest.xml中定義Service:

<service android:name =".GityuanService" android:process =":remote" >  
    <intent-filter>  
       <action android:name ="com.action.gityuan" />  
    </intent-filter>  
</service>

GityuanService這個(gè)服務(wù)運(yùn)行在remote進(jìn)程终惑。

2.1 進(jìn)程關(guān)系圖

以一幅圖來展示AMS管理進(jìn)程的相關(guān)成員變量以及ProcessRecord對(duì)象:

點(diǎn)擊查看大圖

[圖片上傳中...(image-dc86ea-1513257973227-2)]

2.2 進(jìn)程與AMS的關(guān)聯(lián)

這里只介紹AMS的進(jìn)程相關(guān)的成員變量:

  1. mProcessNames:數(shù)據(jù)類型為ProcessMap<processrecord style="box-sizing: border-box; user-select: text !important;">绍在,以進(jìn)程名和userId為key來記錄ProcessRecord;</processrecord>
    • 添加進(jìn)程,addProcessNameLocked()
    • 刪除進(jìn)程,removeProcessNameLocked()
  2. mPidsSelfLocked: 數(shù)據(jù)類型為SparseArray<processrecord style="box-sizing: border-box; user-select: text !important;">偿渡,以進(jìn)程pid為key來記錄ProcessRecord;</processrecord>
    • startProcessLocked()臼寄,移除已存在進(jìn)程,增加新創(chuàng)建進(jìn)程pid信息溜宽;
    • removeProcessLocked吉拳,processStartTimedOutLocked,cleanUpApplicationRecordLocked移除進(jìn)程适揉;
  3. mLruProcesses:數(shù)據(jù)類型為ArrayList<processrecord style="box-sizing: border-box; user-select: text !important;">留攒,以進(jìn)程最近使用情況來排序記錄ProcessRecord;</processrecord>
    • 其中第一個(gè)元素代表的便是最近最少使用的進(jìn)程;
    • updateLruProcessLocked()更新進(jìn)程隊(duì)列位置嫉嘀;
  4. mRemovedProcesses:數(shù)據(jù)類型為ArrayList<processrecord style="box-sizing: border-box; user-select: text !important;">炼邀,記錄所有需要強(qiáng)制移除的進(jìn)程;</processrecord>
  5. mProcessesToGc:數(shù)據(jù)類型為ArrayList<processrecord style="box-sizing: border-box; user-select: text !important;">剪侮,記錄系統(tǒng)進(jìn)入idle狀態(tài)需執(zhí)行g(shù)c操作的進(jìn)程拭宁;</processrecord>
  6. mPendingPssProcesses:數(shù)據(jù)類型為ArrayList<processrecord style="box-sizing: border-box; user-select: text !important;">,記錄將要收集內(nèi)存使用數(shù)據(jù)PSS的進(jìn)程票彪;</processrecord>
  7. mProcessesOnHold:數(shù)據(jù)類型為ArrayList<processrecord style="box-sizing: border-box; user-select: text !important;">,記錄剛開機(jī)過程不狮,系統(tǒng)還沒與偶準(zhǔn)備就緒的情況下降铸, 所有需要啟動(dòng)的進(jìn)程都放入到該隊(duì)列;</processrecord>
  8. mPersistentStartingProcesses:數(shù)據(jù)類型ArrayList<processrecord style="box-sizing: border-box; user-select: text !important;">摇零,正在啟動(dòng)的persistent進(jìn)程推掸;</processrecord>
  9. mHomeProcess: 記錄包含home Activity所在的進(jìn)程;
  10. mPreviousProcess:記錄用戶上一次剛訪問的進(jìn)程驻仅;其中mPreviousProcessVisibleTime記錄上一個(gè)進(jìn)程的用戶訪問時(shí)間谅畅;
  11. mProcessList: 數(shù)據(jù)類型ProcessList,用于進(jìn)程管理噪服,Adj常量定義位于該文件毡泻;

其中最為常見的是mProcessNames,mPidsSelfLocked粘优,mLruProcesses這3個(gè)對(duì)象仇味;

2.3 進(jìn)程與組件的關(guān)聯(lián)

系統(tǒng)AMS這邊是由ProcessRecord對(duì)象記錄進(jìn)程,進(jìn)程自身比較重要成員變量如下:

  1. processName:記錄進(jìn)程名雹顺,默認(rèn)情況下進(jìn)程名和該進(jìn)程運(yùn)行的第一個(gè)apk的包名是相同的丹墨,當(dāng)然也可以自定義進(jìn)程名;
  2. pid: 記錄進(jìn)程pid嬉愧,該值在由進(jìn)程創(chuàng)建時(shí)內(nèi)核所分配的贩挣。
  3. thread:執(zhí)行完attachApplicationLocked()方法,會(huì)把客戶端進(jìn)程ApplicationThread的binder服務(wù)的代理端傳遞到 AMS,并保持到ProcessRecord的成員變量thread王财;
    • ProcessRecord.makeActive卵迂,賦值;
    • ProcessRecord.makeInactive搪搏,清空狭握;
  4. info:記錄運(yùn)行在該進(jìn)程的第一個(gè)應(yīng)用;
  5. pkgList: 記錄運(yùn)行在該進(jìn)程中所有的包名疯溺,比如通過addPackage()添加论颅;
  6. pkgDeps:記錄該進(jìn)程所依賴的包名,比如通過addPackageDependency()添加囱嫩;
  7. lastActivityTime:每次updateLruProcessLocked()過程會(huì)更新該值恃疯;
  8. killedByAm:當(dāng)值為true,意味著該進(jìn)程是被AMS所殺墨闲,而非由于內(nèi)存低而被LMK所殺今妄;
  9. killed:當(dāng)值為true,意味著該進(jìn)程被殺鸳碧,不論是AMS還是其他方式盾鳞;
  10. waitingToKill:比如cleanUpRemovedTaskLocked()過程會(huì)賦值為”remove task”,當(dāng)該進(jìn)程處于后臺(tái)且

任一組件都運(yùn)行在某個(gè)進(jìn)程瞻离,再來說說ProcessRecord對(duì)象中與組件的關(guān)聯(lián)關(guān)系:

成員變量 說明 對(duì)應(yīng)組件
activities 記錄進(jìn)程的ActivityRecord列表 Activity
services 記錄進(jìn)程的ActivityRecord列表 Service
executingServices 記錄進(jìn)程的正在執(zhí)行的ActivityRecord列表 Service
connections 記錄該進(jìn)程bind的ConnectionRecord集合 Service
receivers 動(dòng)態(tài)注冊(cè)的廣播接收者ReceiverList集合 Broadcast
curReceiver 當(dāng)前正在處理的一個(gè)廣播BroadcastRecord Broadcast
pubProviders 該進(jìn)程發(fā)布的ContentProviderRecord的map表 ContentProvider
conProviders 該進(jìn)程所請(qǐng)求的ContentProviderConnection列表 ContentProvider

說明:

  • connections:舉例來說腾仅,進(jìn)程A調(diào)用bindService()方法去bind遠(yuǎn)程進(jìn)程B的Service。 此時(shí)會(huì)在進(jìn)程A的ProcessRecord.connections添加一個(gè)ConnectionRecord.
  • pubProviders: 該進(jìn)程所有對(duì)外發(fā)布的ContentProvider信息套利,這是是以ArrayMap形式保存推励,即 以provider的name為key,以ContentProviderRecord為value的鍵值對(duì)結(jié)構(gòu)體。
  • conProviders: 當(dāng)進(jìn)程A調(diào)用query()的過程肉迫,會(huì)執(zhí)行g(shù)etContentProvider()方法去向進(jìn)程B請(qǐng)求 provider的代理验辞。此時(shí)會(huì)在進(jìn)程A的ProcessRecord.conProviders添加一個(gè)ContentProviderConnection。

三. AMS的組件管理

組件啟動(dòng)喊衫,先填充完進(jìn)程信息跌造,接下來還需要完善組件本身的信息,各個(gè)組件在system_server的核心信息記錄如下:

  • Service的信息記錄在ActiveServices和AMS
  • Broadcast信息記錄在BroadcastQueue和AMS
  • Activity信息記錄在ActivityStack族购,ActivityStackSupervisor鼻听,以及AMS;
  • Provider信息記錄在ProviderMap和AMS;

可見,AMS是整個(gè)四大組件最為核心的對(duì)象联四,所有組件都或多或少依賴該對(duì)象的數(shù)據(jù)結(jié)構(gòu)信息撑碴。 關(guān)系圖如下:點(diǎn)擊查看大圖

[圖片上傳中...(image-5a3c91-1513257973227-1)]

3.1 Activity

AMS對(duì)象

public final class ActivityManagerService extends ...{
    //當(dāng)前聚焦的Activity
    ActivityRecord mFocusedActivity = null;
    //用于管理各個(gè)Activity棧
    final ActivityStackSupervisor mStackSupervisor;
}

ASS對(duì)象

public final class ActivityStackSupervisor implements DisplayListener {
    //桌面app所在棧
    ActivityStack mHomeStack;

    //當(dāng)前可以接受Input事件,或許啟動(dòng)下一個(gè)Activity的棧
    ActivityStack mFocusedStack;

    //當(dāng)該值等于mFocusedStack朝墩,代表當(dāng)前棧頂?shù)腁ctivity已進(jìn)入resumed狀態(tài)醉拓;
    //當(dāng)該值等于上一個(gè)舊棧時(shí)伟姐,代表正處理activity切換狀態(tài);
    private ActivityStack mLastFocusedStack;

    //在完成相應(yīng)目標(biāo)前亿卤,等待新的Activity成為可見的Activity列表
    final ArrayList<ActivityRecord> mWaitingVisibleActivities = new ArrayList<>();

    //等待找到下一個(gè)可見Activity的等待列表
    final ArrayList<IActivityManager.WaitResult> mWaitingActivityVisible = new ArrayList<>();

    //等待找到下一個(gè)已啟動(dòng)Activity的等待列表
    final ArrayList<IActivityManager.WaitResult> mWaitingActivityLaunched = new ArrayList<>();

    //等待上一個(gè)activity安置完成愤兵,則即將進(jìn)入被stopped的Activity列表
    final ArrayList<ActivityRecord> mStoppingActivities = new ArrayList<>();

    //等待上一個(gè)activity安置完成,則即將進(jìn)入被finished的Activity列表
    final ArrayList<ActivityRecord> mFinishingActivities = new ArrayList<>();

    //即將進(jìn)入sleep狀態(tài)的進(jìn)程所對(duì)應(yīng)的Activity列表
    final ArrayList<ActivityRecord> mGoingToSleepActivities = new ArrayList<>();
}

AS對(duì)象

final class ActivityStack{
    //記錄該棧中所有的task
    private final ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();

    //按LRU方式排序的Activity列表排吴,隊(duì)尾成員是最新活動(dòng)的Activity
    final ArrayList<ActivityRecord> mLRUActivities = new ArrayList<>();

    //正在執(zhí)行pausing過程的Activity
    ActivityRecord mPausingActivity = null;

    //已處于paused狀態(tài)的Activity
    ActivityRecord mLastPausedActivity = null;

    //已處于Resumed狀態(tài)的Activity
    ActivityRecord mResumedActivity = null;
}

3.2 Service

[-> ActiveServices.java]

public final class ActiveServices {
    //記錄不同User下所有的Service信息
    final SparseArray<ServiceMap> mServiceMap = new SparseArray<>();

    //bind service的連接信息秆乳,以IServiceConnection的Bp端作為Keys
    final ArrayMap<IBinder, ArrayList<ConnectionRecord>> mServiceConnections = new ArrayMap<>();

    //已請(qǐng)求啟動(dòng)但尚未啟動(dòng)的Service列表
    final ArrayList<ServiceRecord> mPendingServices = new ArrayList<>();

    //crash后需要計(jì)劃重啟的Service列表
    final ArrayList<ServiceRecord> mRestartingServices = new ArrayList<>();

    //正在執(zhí)行destroyed的service列表
    final ArrayList<ServiceRecord> mDestroyingServices = new ArrayList<>();
}

3.3 Broadcast

[-> ActivityManagerService.java]

public final class ActivityManagerService extends ...{
    //前臺(tái)廣播隊(duì)列
    BroadcastQueue mFgBroadcastQueue;
    //后臺(tái)廣播隊(duì)列
    BroadcastQueue mBgBroadcastQueue;
    //廣播隊(duì)列數(shù)組,也就是前臺(tái)和后臺(tái)廣播隊(duì)列
    final BroadcastQueue[] mBroadcastQueues = new BroadcastQueue[2];

    //粘性廣播钻哩,[userId屹堰,action,ArrayList<Intent>]
    final SparseArray<ArrayMap<String, ArrayList<Intent>>> mStickyBroadcasts;

    //動(dòng)態(tài)注冊(cè)的廣播接收者街氢,其中key為客戶端InnerReceiver的Bp端扯键,value為ReceiverList
    final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();

    //從廣播intent到已注冊(cè)接收者的解析器
    final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver;
}

[-> BroadcastQueue.java]

public final class BroadcastQueue{
    //并行廣播列表
    final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<>();
    //串行廣播列表
    final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<>();

    //即將要處理的串行廣播珊肃,等待目標(biāo)進(jìn)程創(chuàng)建完成荣刑。每個(gè)廣播隊(duì)列只有一個(gè),其他必須等待該廣播完成伦乔。
    BroadcastRecord mPendingBroadcast = null;
}

3.4 Provider

[-> ActivityManagerService.java]

public final class ActivityManagerService extends ...{
    //記錄系統(tǒng)所有的provider信息
    final ProviderMap mProviderMap;

    //記錄有client正在等待的provider列表厉亏,當(dāng)provider發(fā)布完成則從該隊(duì)列移除
    final ArrayList<ContentProviderRecord> mLaunchingProviders;
}

[-> ProviderMap.java]

public final class ProviderMap {
    //以provider名字(auth)為key的方式所記錄的provider信息
    private final HashMap<String, ContentProviderRecord> mSingletonByName;
    //以provider組件名(ComponentName)為key的方式所記錄的provider信息
    private final HashMap<ComponentName, ContentProviderRecord> mSingletonByClass;

    //記錄不同UserId下的,以auth為key的方式所記錄的provider信息
    private final SparseArray<HashMap<String, ContentProviderRecord>> mProvidersByNamePerUser;
    //記錄不同UserId下的烈和,以ComponentName為key的方式所記錄的provider信息
    private final SparseArray<HashMap<ComponentName, ContentProviderRecord>> mProvidersByClassPerUser;
}

同一個(gè)provider組件名爱只,可能對(duì)應(yīng)多個(gè)provider名。

四. App端的組件信息

關(guān)系圖如下:點(diǎn)擊查看大圖

[圖片上傳中...(image-6b8d58-1513257973227-0)]

App端的組件信息斥杜,都保存在ActivityThread和LoadedApk這兩個(gè)對(duì)象虱颗,主要保存信息:

  • ActivityThread:記錄provider, activity, service在客戶端的相關(guān)信息沥匈;
  • LoadedApk: 記錄動(dòng)態(tài)注冊(cè)的廣播接收器蔗喂,以及bind方式啟動(dòng)service在客戶端的相關(guān)信息;
?著作權(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)容