一、Activity啟動(dòng)過(guò)程
? ? 首先我們要知道Activity有冷啟動(dòng)和熱啟動(dòng)之分卵佛,通俗來(lái)說(shuō)冷啟動(dòng)就是應(yīng)用進(jìn)程尚未創(chuàng)建杨赤,熱啟動(dòng)則已經(jīng)創(chuàng)建完成。
? ??在點(diǎn)擊桌面應(yīng)用圖標(biāo)時(shí)截汪,即將要啟動(dòng)的App將和Launcher疾牲、AMS、Zygote這三者多次通信挫鸽,才會(huì)啟動(dòng)一個(gè)App,然后再啟動(dòng)Activity说敏。
追蹤源碼,我們可以得到以下整體的時(shí)序圖:
簡(jiǎn)單的梳理下整體流程丢郊,我們可以直接得到以下流程:
Launcher進(jìn)程通過(guò)Binder機(jī)制通知AMS
AMS則判斷應(yīng)用進(jìn)程是否已經(jīng)存在(冷啟動(dòng))盔沫,不存在則通過(guò)Socket通訊通知Zygote進(jìn)程fork應(yīng)用進(jìn)程,已經(jīng)啟動(dòng)(熱啟動(dòng))則無(wú)需再次創(chuàng)建App進(jìn)程枫匾。
應(yīng)用進(jìn)程創(chuàng)建完成之后則會(huì)通過(guò)Binder機(jī)制通知AMS 創(chuàng)建完成架诞。
AMS通過(guò)Binder機(jī)制請(qǐng)求ApplicationThread創(chuàng)建并啟動(dòng)根Activity。
ApplicationThread通過(guò)Handle機(jī)制通知主線程ActivityThread干茉,最終調(diào)用到根Activity的onCreate谴忧、onStart、onResume等方法完成創(chuàng)建角虫。
二沾谓、Service的啟動(dòng)過(guò)程
????Service的啟動(dòng)還是和Activity有很多相似處的,都需要和AMS打招呼戳鹅。
????眾所周知均驶,Service的啟動(dòng)有兩種方式一種StartService,一種bindService枫虏,那它們的啟動(dòng)過(guò)程是否一樣呢妇穴?帶著疑惑我們往下看。
????首先我們看StartService隶债,直接分析源碼腾它,可以得到以下時(shí)序圖:
????注:1.bringUpServiceLocked方法調(diào)用時(shí),其中啟動(dòng)Service時(shí)會(huì)判斷app==null死讹,app的類型是ProcessRecord瞒滴,用來(lái)描述運(yùn)行的應(yīng)用程序進(jìn)程的信息,在其中將Service運(yùn)行的進(jìn)程名和uid傳遞給ActivityManagerService的getProcessRecordLocked方法赞警,從而獲取運(yùn)行Service的應(yīng)用程序進(jìn)程信息ProcessRecord妓忍,如果用來(lái)運(yùn)行Service的應(yīng)用程序進(jìn)程不存在稀并,就會(huì)調(diào)用ActivityManagerService的startProcessLocked方法來(lái)創(chuàng)建對(duì)應(yīng)的應(yīng)用程序進(jìn)程;如果用來(lái)運(yùn)行Service的應(yīng)用程序進(jìn)程存在单默,會(huì)調(diào)用realStartServiceLocked方法。
????2.H是ActivityThread的內(nèi)部類并繼承自Handler忘瓦,AMS通過(guò)IApplicationThread向應(yīng)用程序進(jìn)程發(fā)送消息搁廓,接受消息的操作是在應(yīng)用程序進(jìn)程的Binder線程池中進(jìn)行,因此需要Handler來(lái)發(fā)送消息切換到主線程耕皮。
????總結(jié)下來(lái)就是
????下面接著分析下bindService境蜕,它的流程會(huì)相對(duì)startService復(fù)雜一丟丟,照例直接分析源碼凌停,可以得到以下時(shí)序圖:
????大致總結(jié)一下就是應(yīng)用進(jìn)程這邊調(diào)用一系列方法最終與AMS通信bindService粱年,然后AMS中調(diào)用activeService類中的方法,然后又通過(guò)ApplicationThread與應(yīng)用進(jìn)程這邊通信handleBindService罚拟,然后通知AMS去publishService台诗,調(diào)用的activeService的publishServiceLocked方法,其中調(diào)用了ServiceDispatcher.InnerConnection的connected方法赐俗,再調(diào)用ServiceDispatcher的connected方法拉队,ServiceDispatcher是LoadedApk的內(nèi)部類,并調(diào)用Handler類型的對(duì)象mActivityThread的post方法阻逮,mActivityThread實(shí)際指向的是ActivityThread的內(nèi)部類H粱快,最終通過(guò)H類的post方法將RunConnection對(duì)象的內(nèi)容運(yùn)行在主線程中,RunConnections是LoadedApk的內(nèi)部類叔扼,最后調(diào)用mConnection的onServiceConnected事哭,mConnection的類型是ServiceConnection,這樣客戶端實(shí)現(xiàn)ServiceConnection接口類的onServiceConnected方法就會(huì)被調(diào)用瓜富。
三鳍咱、BroadcastReceiver的注冊(cè)、發(fā)送和接收
? ?廣播注冊(cè)分為動(dòng)態(tài)注冊(cè)和靜態(tài)注冊(cè)食呻,首先我們分析動(dòng)態(tài)注冊(cè)流炕。
????動(dòng)態(tài)注冊(cè)的過(guò)程是從ContextWrapper#registerReceiver()開(kāi)始的. 和Activity或者Service一樣. ContextWrapper并沒(méi)有做實(shí)際的工作, 而是將注冊(cè)的過(guò)程直接交給了ContextImpl來(lái)完成。
????ContextImpl#registerReceiver()方法調(diào)用了本類的registerReceiverInternal()方法仅胞。
????系統(tǒng)首先從mPackageInfo獲取到IIntentReceiver對(duì)象, 然后再采用跨進(jìn)程的方式向AMS發(fā)送廣播注冊(cè)的請(qǐng)求. 之所以采用IIntentReceiver而不是直接采用BroadcastReceiver, 這是因?yàn)樯鲜鲎?cè)過(guò)程中是一個(gè)進(jìn)程間通信的過(guò)程. 而BroadcastReceiver作為Android中的一個(gè)組件是不能直接跨進(jìn)程傳遞的. 所以需要通過(guò)IIntentReceiver來(lái)實(shí)現(xiàn)通信每辟。
????IIntentReceiver作為一個(gè)Binder接口, 它的具體實(shí)現(xiàn)是LoadedApk.ReceiverDispatcher.InnerReceiver, ReceiverDispatcher的內(nèi)部同時(shí)保存了BroadcastReceiver和InnerReceiver, 這樣當(dāng)接收到廣播的時(shí)候, ReceiverDispatcher可以很方便的調(diào)用BroadcastReceiver#onReceive()方法. 這里和Service很像有同樣的類, 并且內(nèi)部類中同樣也是一個(gè)Binder接口。
????由于注冊(cè)廣播真正實(shí)現(xiàn)過(guò)程是在AMS中, 因此跟進(jìn)AMS中, 首先看registerReceiver()方法, 這里只關(guān)心里面的核心部分. 這段代碼最終會(huì)把遠(yuǎn)程的InnerReceiver對(duì)象以及IntentFilter對(duì)象存儲(chǔ)起來(lái), 這樣整個(gè)廣播的注冊(cè)就完成了干旧。
靜態(tài)注冊(cè)的過(guò)程就比較簡(jiǎn)單
1.AndroidManifest.xml中的receiver解析成ParsedActivity, 存放在PackageImpl的receivers(PackageImpl父類是ParsingPackageImpl而且實(shí)現(xiàn)了AndroidPackage接口)
2.receivers最終會(huì)存放在mComponentResolver(PMS)的mReceivers中渠欺,mReceivers包含了所有安裝應(yīng)用的receiver,通過(guò)ComponentName就可以獲得相應(yīng)的ParsedActivity椎眯,如:
3.mReceivers.mActivities.get(new ComponentName(“com.example.myapplication”, “com.example.myapplication.MyReceive”))挠将,既可以獲得MyReceiver的ParsedActivity
4.receiver中的一個(gè)IntentFilter(intent-filter)對(duì)應(yīng)一個(gè)ParsedIntentInfo胳岂,一個(gè)Pair<ParsedActivity, ParsedIntentInfo>
5.Pair<ParsedActivity, ParsedIntentInfo>被放入mComponentResolver的mFilters
6.mActions被放入mComponentResolver的mActionToFilter
????部分靜態(tài)廣播注冊(cè)需要權(quán)限,不是注冊(cè)了就能收到舔稀。其實(shí)要接收廣播還:涉及權(quán)限乳丰、進(jìn)程優(yōu)先級(jí)、flag標(biāo)簽等各類無(wú)法接收到廣播的情況内贮〔埃總而言之靜態(tài)廣播注冊(cè)是在包安裝解析的時(shí)候就開(kāi)始注冊(cè),并將廣播信息存儲(chǔ)在PMS(PackageManagerService)中了夜郁。
? ??廣播的發(fā)送主要有幾種:普通廣播什燕、有序廣播。
? ? 前面都一樣都是通過(guò)ContextImpl去與AMS打交道竞端,然后AMS這邊方法中會(huì)根據(jù)intent-filter查找出匹配的廣播接收者并經(jīng)過(guò)一系列的條件過(guò)濾. 最終會(huì)將滿足條件的廣播接收者添加到BroadcastQueue中, 接著BroadcastQueue就會(huì)將廣播發(fā)送給相應(yīng)廣播接收者屎即。應(yīng)用接收到廣播, 同時(shí)onReceive()方法是在廣播接收者的主線程中被調(diào)用的。
補(bǔ)充小知識(shí)
1:所有靜態(tài)廣播Receiver 都是串行處理事富,(靜態(tài)廣播接收者屬于在發(fā)送此廣播時(shí)屬于有序廣播范疇)
2:動(dòng)態(tài)廣播 Receiver按照發(fā)送此廣播時(shí)指定的方式 進(jìn)行 串行或者并行分發(fā)
其中:如果是普通廣播:那么通過(guò) 并行方式分發(fā)
? ? ? ? 如果是 有序廣播(sendOrderxxxx):那么通過(guò) 串行方式分發(fā)
3:Android系統(tǒng)在處理廣播時(shí):動(dòng)態(tài)廣播接收者 優(yōu)先于 靜態(tài)廣播接收者 收到
4:廣播分發(fā)處理關(guān)鍵類:BroadcastQueue/ BroadcastRecord
5.本地廣播:為了解決全局廣播的安全性問(wèn)題技俐,Android引進(jìn)了本地廣播機(jī)制。本地廣播發(fā)出后只能夠在應(yīng)用程序內(nèi)部傳遞统台,也只有應(yīng)用程序內(nèi)部的接收器能接收到本地廣播虽另,這樣廣播的安全性問(wèn)題就能得到解決了。本地廣播和全局廣播不同的地方在于本地廣播主要使用LocalBroadcastManager對(duì)廣播的發(fā)送饺谬、注冊(cè)捂刺、注銷進(jìn)行管理。
四募寨、ContentProvider的啟動(dòng)過(guò)程
????ContentProvider的啟動(dòng)過(guò)程和其他3大組件基本類似族展,都是通過(guò)AMS實(shí)現(xiàn)進(jìn)程間的數(shù)據(jù)共享。
????在activity中如果想通過(guò)provider來(lái)實(shí)現(xiàn)增刪查改拔鹰,首先需要獲取contentprovider仪缸,大致過(guò)程為在context中獲取contentResolver,然后通過(guò)contentResolver去ActivityManagerService中查詢對(duì)應(yīng)的provider列肢,如果沒(méi)有則進(jìn)入PackageManagerService中查找:
????1)首先每個(gè)context類都會(huì)內(nèi)部包含了一個(gè)ContentResolver的子對(duì)象ApplicationContentResolver恰画。
????2)通過(guò)調(diào)用ApplicationContentResolver的主要方法query來(lái)獲取CP的數(shù)據(jù)庫(kù)數(shù)據(jù)。
????3)調(diào)用的過(guò)程首先會(huì)調(diào)用ContentResolver的核心方法acquireProvider()瓷马。而acquireProvider()方法是一個(gè)抽象方法拴还,其實(shí)現(xiàn)是交由子類實(shí)現(xiàn)。
????4)通過(guò)子類的acquireProvider()方法實(shí)現(xiàn)了解到主要的實(shí)現(xiàn)是交由ActivityThread類來(lái)完成欧聘。
????5)ActivityThread類會(huì)做出一個(gè)判斷片林,如果本地保存一個(gè)需要獲取的CP對(duì)象實(shí)例,就會(huì)直接返回這個(gè)對(duì)象實(shí)例,如果沒(méi)有保存费封,則會(huì)訪問(wèn)AMS對(duì)象去查找獲取一個(gè)對(duì)象的CP對(duì)象實(shí)例焕妙,當(dāng)找到這個(gè)對(duì)象實(shí)例后會(huì)保存到本地以便日后快速獲取。
????6)如果在AMS里面沒(méi)有找到弓摘,就會(huì)繼續(xù)深入到PMS里去從全部的provider中查找焚鹊。
????7)獲取到CP對(duì)象實(shí)例后會(huì)通過(guò)層層返回,最后再調(diào)用該CP對(duì)象的query方法獲取相應(yīng)的數(shù)據(jù)韧献。
首先在應(yīng)用的的manifest中需要進(jìn)行讀寫權(quán)限申明,這個(gè)申明的定義跟之前provider定義中讀寫所需權(quán)限屬性值是一樣的:
????在activity中獲取ContentResolver調(diào)用其中的操作方法時(shí)寺旺,需要傳入相對(duì)應(yīng)的參數(shù):
????contentResolver.query(Uri uri, String[] projection,String selection, String[] selectionArgs,String orderBy);
????uri:傳入對(duì)應(yīng)uri是為了查找到對(duì)應(yīng)的provider,跟provider在manifest中定義的authorities值是一樣
????projection:選擇需要返回的對(duì)象屬性值势决,有時(shí)候不需要將對(duì)象的值全部返回。
????selection/selectionArgs:查詢條件
????orderBy: 返回的對(duì)象排序方式
????類似其他的delete蓝撇、insert和update操作果复。最主要的是傳入正確的Uri才能找到對(duì)應(yīng)的provider。
????此處加個(gè)小知識(shí)點(diǎn):ContentProvider onCreate()優(yōu)先執(zhí)行于 Application onCreate()方法渤昌,感興趣的小伙伴可以通過(guò)查看源碼的方式驗(yàn)證虽抄。
淺談一個(gè)小知識(shí)點(diǎn)—AMS的啟動(dòng):
????AMS,即ActivityManagerService独柑,是安卓java framework的一個(gè)服務(wù)迈窟,運(yùn)行在system_server進(jìn)程。
????在系統(tǒng)開(kāi)機(jī)啟動(dòng)之后忌栅,system_server會(huì)執(zhí)行三大服務(wù)啟動(dòng)
????startBootstrapServices() :?jiǎn)?dòng)引導(dǎo)服務(wù)车酣,在這里實(shí)際上已經(jīng)new了AMS,在new方法里索绪,已經(jīng)初始化了AMS的大部分重要的屬性。AMS的Looper和各種handler也是在這里準(zhǔn)備好的瑞驱。
????startCoreServices():核心服務(wù)娘摔。
????在創(chuàng)建完AMS之后凳寺,system_server的run方法會(huì)執(zhí)行到startOtherServices(),在啟動(dòng)“其他服務(wù)”完畢之后杆融,會(huì)調(diào)入到AMS的systemReady()方法,在這里會(huì)啟動(dòng)launcher激况。
????可以說(shuō)灿渴,在這個(gè)方法執(zhí)行完畢之后够话,系統(tǒng)就已經(jīng)啟動(dòng)完成了蓝翰。