startActivityLocked是startActivityMayWait第二階段的工作重點,該函數有點長,請讀者耐心看代碼。
**ActivityStack.java::startActivityLocked**
~~~
final int startActivityLocked(IApplicationThreadcaller,
Intent intent, String resolvedType,
Uri[] grantedUriPermissions,
int grantedMode, ActivityInfo aInfo, IBinder resultTo,
String resultWho, int requestCode,
int callingPid, int callingUid, boolean onlyIfNeeded,
boolean componentSpecified, ActivityRecord[]outActivity) {
int err = START_SUCCESS;
ProcessRecord callerApp = null;
//如果caller不為空,則需要從AMS中找到它的ProcessRecord。本例的caller為null
if(caller != null) {
callerApp = mService.getRecordForAppLocked(caller);
//其實就是想得到調用進程的pid和uid
if(callerApp != null) {
callingPid = callerApp.pid;//一定要保證調用進程的pid和uid正確
callingUid = callerApp.info.uid;
}else {//如調用進程沒有在AMS中注冊,則認為其是非法的
err = START_PERMISSION_DENIED;
}
}// if (caller != null)判斷結束
//下面兩個變量意義很重要。sourceRecord用于描述啟動目標Activity的那個Activity,
//resultRecord用于描述接收啟動結果的Activity,即該Activity的onActivityResult
//將被調用以通知啟動結果,讀者可先閱讀SDK中startActivityForResult函數的說明
ActivityRecordsourceRecord = null;
ActivityRecord resultRecord = null;
if(resultTo != null) {
//本例resultTo為null,
}
//獲取Intent設置的啟動標志,它們是和Launch Mode相類似的“小把戲”,
//所以,讀者務必理解“關于Launch Mode的介紹”一節的知識點
intlaunchFlags = intent.getFlags();
if((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
&& sourceRecord != null) {
......
/*
前面介紹的Launch Mode和Activity的啟動有關,實際上還有一部分標志用于控制
Activity啟動結果的通知。有關FLAG_ACTIVITY_FORWARD_RESULT的作用,讀者可
參考SDK中的說明。使用這個標簽有個前提,即A必須先存在,正如if中sourceRecord
不為null的判斷所示。另外,讀者自己可嘗試編寫例子,以測試FLAG_ACTIVITY_FORWARD_
RESULT標志的作用
*/
}
//檢查err值及Intent的情況
if (err== START_SUCCESS && intent.getComponent() == null)
err = START_INTENT_NOT_RESOLVED;
......
//如果err不為0,則調用sendActivityResultLocked返回錯誤
if (err!= START_SUCCESS) {
if(resultRecord != null) {// resultRecord接收啟動結果
sendActivityResultLocked(-1,esultRecord, resultWho, requestCode,
Activity.RESULT_CANCELED, null);
}
.......
returnerr;
}
//檢查權限
finalint perm = mService.checkComponentPermission(aInfo.permission,
callingPid,callingUid,aInfo.applicationInfo.uid, aInfo.exported);
......//權限檢查失敗的處理,不必理會
if (mMainStack) {
//可為AMS設置一個IActivityController類型的監聽者,AMS有任何動靜都會回調該
//監聽者。不過誰又有如此本領去監聽AMS呢?在進行Monkey測試的時候,Monkey會
//設置該回調對象。這樣,Monkey就能根據AMS放映的情況進行相應處理了
if(mService.mController != null) {
boolean abort = false;
try {
Intent watchIntent = intent.cloneFilter();
//交給回調對象處理,由它判斷是否能繼續后面的行程
abort = !mService.mController.activityStarting(watchIntent,
aInfo.applicationInfo.packageName);
}......
//回調對象決定不啟動該Activity。在進行Monkey測試時,可設置黑名單,位于
//黑名單中的Activity將不能啟動
if (abort) {
.......//通知resultRecord
return START_SUCCESS;
}
}
}// if(mMainStack)判斷結束
//創建一個ActivityRecord對象
ActivityRecordr = new ActivityRecord(mService, this, callerApp, callingUid,
intent, resolvedType, aInfo, mService.mConfiguration,
resultRecord, resultWho, requestCode, componentSpecified);
if(outActivity != null)
outActivity[0] = r;//保存到輸入參數outActivity數組中
if(mMainStack) {
//mResumedActivity代表當前界面顯示的Activity
if(mResumedActivity == null
|| mResumedActivity.info.applicationInfo.uid!= callingUid) {
//檢查調用進程是否有權限切換Application,相關知識見下文的解釋
if(!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
"Activity start")) {
PendingActivityLaunch pal = new PendingActivityLaunch();
//如果調用進程沒有權限切換Activity,則只能把這次Activity啟動請求保存起來,
//后續有機會時再啟動它
pal.r = r;
pal.sourceRecord = sourceRecord;
......
//所有Pending的請求均保存到AMS mPendingActivityLaunches變量中
mService.mPendingActivityLaunches.add(pal);
mDismissKeyguardOnNextActivity = false;
return START_SWITCHES_CANCELED;
}
}//if(mResumedActivity == null...)判斷結束
if (mService.mDidAppSwitch) {//用于控制app switch,見下文解釋
mService.mAppSwitchesAllowedTime = 0;
} else{
mService.mDidAppSwitch = true;
}
//啟動處于Pending狀態的Activity
mService.doPendingActivityLaunchesLocked(false);
}// if(mMainStack)判斷結束
//調用startActivityUncheckedLocked函數
err =startActivityUncheckedLocked(r, sourceRecord,
grantedUriPermissions, grantedMode, onlyIfNeeded, true);
......
return err;
}
~~~
startActivityLocked函數的主要工作包括:
- 處理sourceRecord及resultRecord。其中,sourceRecord表示發起本次請求的Activity,resultRecord表示接收處理結果的Activity(啟動一個Activity肯定需要它完成某項事情,當目標Activity將事情成后,就需要告知請求者該事情的處理結果)。在一般情況下,sourceRecord和resultRecord應指向同一個Activity。
- 處理app Switch。如果AMS當前禁止app switch,則只能把本次啟動請求保存起來,以待允許app switch時再處理。從代碼中可知,AMS在處理本次請求前,會先調用doPendingActivityLaunchesLocked函數,在該函數內部將啟動之前因系統禁止app switch而保存的Pending請求。
- 調用startActivityUncheckedLocked處理本次Activity啟動請求。
先來看app Switch,它雖然是一個小變量,但是意義重大。
1. 關于resume/stopAppSwitches的介紹
AMS提供了兩個函數,用于暫時(注意,是暫時)禁止App切換。為什么會有這種需求呢?因為當某些重要(例如設置賬號等)Activity處于前臺(即用戶當前所見的Activity)時,不希望系統因用戶操作之外的原因而切換Activity(例如恰好此時收到來電信號而彈出來電界面)。
先來看stopAppSwitches,代碼如下:
**ActivityManagerService.java::stopAppSwitches**
~~~
public void stopAppSwitches() {
......//檢查調用進程是否有STOP_APP_SWITCHES權限
synchronized(this) {
//設置一個超時時間,過了該時間,AMS可以重新切換App(switch app)了
mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
+ APP_SWITCH_DELAY_TIME;
mDidAppSwitch = false;//設置mDidAppSwitch為false
mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
Message msg =//防止應用進程調用了stop卻沒調用resume,5秒后處理該消息
mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
}
}
~~~
在以上代碼中有兩點需要注意:
- 此處控制機制名叫app switch,而不是activity switch。為什么呢?因為如果從受保護的activity中啟動另一個activity,那么這個新activity的目的應該是針對同一任務,這次啟動就不應該受app switch的制約,反而應該對其大開綠燈。目前,在執行Settings中設置設備策略(DevicePolicy)時就會stopAppSwitch。
- 執行stopAppSwitch后,應用程序應該調resumeAppSwitches以允許app switch,但是為了防止應用程序有意或無意忘記resume app switch,系統設置了一個超時(5秒)消息,過了此超時時間,系統將處理相應的消息,其內部會resume app switch。
再來看resumeAppSwitches函數,代碼如下:
**ActivityManagerService::resumeAppSwitches**
~~~
public voidresumeAppSwitches() {
......//檢查調用進程是否有STOP_APP_SWITCHES權限
synchronized(this) {
mAppSwitchesAllowedTime = 0;
}
//注意,系統并不在此函數內啟動那些被阻止的Activity
}
~~~
在resumeAppSwitches中只設置mAppSwitchesAllowedTime的值為0,它并不處理在stop和resume這段時間內積攢起的Pending請求,那么這些請求是在何時被處理的呢?
- 從前面代碼可知,如果在執行resume app switch后,又有新的請求需要處理,則先處理那些pending的請求(調用doPendingActivityLaunchesLocked)。
- 在resumeAppSwitches中并未撤銷stopAppSwitches函數中設置的超時消息,所以在處理那條超時消息的過程中,也會處理pending的請求。
在本例中,由于不考慮app switch的情況,那么接下來的工作就是調用startActivityUncheckedLocked函數來處理本次activity的啟動請求。此時,我們已經創建了一個ActivityRecord用于保存目標Activity的相關信息。
2. startActivityUncheckedLocked函數分析
startActivityUncheckedLocked函數很長,但是目的比較簡單,即為新創建的ActivityRecord找到一個合適的Task。雖然本例最終的結果是創建一個新的Task,但是該函數的處理邏輯卻比較復雜。先看第一段分析。
(1) startActivityUncheckedLocked分析之一
**ActivityStack.java::startActivityUncheckedLocked**
~~~
final intstartActivityUncheckedLocked(ActivityRecord r,
ActivityRecord sourceRecord, Uri[] grantedUriPermissions,
intgrantedMode, boolean onlyIfNeeded, boolean doResume) {
//在本例中,sourceRecord為null,onlyIfNeeded為false,doResume為true
finalIntent intent = r.intent;
final intcallingUid = r.launchedFromUid;
intlaunchFlags = intent.getFlags();
//判斷是否需要調用因本次Activity啟動而被系統移到后臺的當前Activity的
//onUserLeaveHint函數。可閱讀SDK文檔中關于Activity onUserLeaveHint函數的說明
mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) ==0;
//設置ActivityRecord的delayedResume為true,本例中的doResume為true
if (!doResume) r.delayedResume = true;
//在本例中,notTop為null
ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
!= 0 ? r : null;
if(onlyIfNeeded) {....//在本例中,該變量為false,故略去相關代碼
}
//根據sourceRecord的情況進行對應處理,能理解下面這段if/else的判斷語句嗎
if(sourceRecord == null) {
//如果請求的發起者為空,則當然需要新建一個Task
if((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0)
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
}else if (sourceRecord.launchMode ==ActivityInfo.LAUNCH_SINGLE_INSTANCE){
//如果sourceRecord單獨占一個Instance,則新的Activity必然處于另一個Task中
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
} else if(r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
//如果啟動模式設置了singleTask或singleInstance,則也要創建新Task
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
}//if(sourceRecord== null)判斷結束
//如果新Activity和接收結果的Activity不在一個Task中,則不能啟動新的Activity
if(r.resultTo!= null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
sendActivityResultLocked(-1,r.resultTo, r.resultWho, r.requestCode,
Activity.RESULT_CANCELED, null);
r.resultTo = null;
}
~~~
startActivityUncheckedLocked第一階段的工作還算簡單,主要確定是否需要為新的Activity創建一個Task,即是否設置FLAG_ACTIVITY_NEW_TASK標志。
接下來看下一階段的工作。
(2) startActivityUncheckedLocked分析之二
**ActivityStack.java::startActivityUncheckedLocked**
~~~
booleanaddingToTask = false;
TaskRecord reuseTask = null;
if(((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
(launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK)== 0)
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
if(r.resultTo == null) {
//搜索mHistory,得到一個ActivityRecord
ActivityRecord taskTop = r.launchMode !=
ActivityInfo.LAUNCH_SINGLE_INSTANCE
?findTaskLocked(intent, r.info)
: findActivityLocked(intent,r.info);
if (taskTop != null ){
......//一堆復雜的邏輯處理,無非就是找到一個合適的Task,然后對應做一些
//處理。此處不討論這段代碼,讀者可根據工作中的具體情況進行研究
}
}//if(r.resultTo == null)判斷結束
}
~~~
在本例中,目標Activity首次登場,所以前面的邏輯處理都沒有起作用,建議讀者根據具體情況分析該段代碼。
下面來看startActivityUncheckLocked第三階段的工作。
(3) startActivityUncheckLocked分析之三
**ActivityStack.java::startActivityUncheckLocked**
~~~
if(r.packageName != null) {
//判斷目標Activity是否已經在棧頂,如果是,需要判斷是創建一個新的Activity
//還是調用onNewIntent(singleTop模式的處理)
ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
if (top != null && r.resultTo == null){
......//不討論此段代碼
}//if(top != null...)結束
} else {
......//通知錯誤
returnSTART_CLASS_NOT_FOUND;
}
//在本例中,肯定需要創建一個Task
booleannewTask = false;
booleankeepCurTransition = false;
if(r.resultTo == null && !addingToTask
&& (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
if(reuseTask == null) {
mService.mCurTask++;//AMS中保存了當前Task的數量
if (mService.mCurTask <= 0) mService.mCurTask = 1;
//為該AactivityRecord設置一個新的TaskRecord
r.setTask(new TaskRecord(mService.mCurTask, r.info, intent),
null,true);
}else r.setTask(reuseTask, reuseTask,true);
newTask = true;
//下面這個函數為Android 4.0新增的,用于處理FLAG_ACTIVITY_TASK_ON_HOME的情況,
//請閱讀SDK文檔對Intent的相關說明
moveHomeToFrontFromLaunchLocked(launchFlags);
}elseif......//其他處理情況
//授權控制。在SDK中啟動Activity的函數沒有授權設置方面的參數。在實際工作中,筆者曾碰
//到過一個有趣的情況:在開發的一款定制系統中,用瀏覽器下載了受DRM保護的圖片,
//此時要啟動Gallery3D來查看該圖片,但是由于為DRM目錄設置了讀寫權限,而Gallery3D
//并未聲明相關權限,結果拋出異常,導致不能瀏覽該圖片。由于startActivity等函數不能設置
//授權,最終只能修改Gallery3D并為其添加use-permissions項了
if(grantedUriPermissions != null && callingUid > 0) {
for(int i=0; i<grantedUriPermissions.length; i++) {
mService.grantUriPermissionLocked(callingUid, r.packageName,
grantedUriPermissions[i],grantedMode,
r.getUriPermissionsLocked());
}
mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
intent, r.getUriPermissionsLocked());
//調用startActivityLocked,此時ActivityRecord和TaskRecord均創建完畢
startActivityLocked(r, newTask, doResume, keepCurTransition);
return START_SUCCESS;
}//startActivityUncheckLocked函數結束
~~~
startActivityUncheckLocked的第三階段工作也比較復雜,不過針對本例,它將創建一個新的TaskRecord,并調用startActivityLocked函數進行處理。
下面我們轉戰startActivityLocked函數。
(4) startActivityLocked函數分析
**ActivityStack.java::startActivityLocked**
~~~
private final voidstartActivityLocked(ActivityRecord r, boolean newTask,
boolean doResume, boolean keepCurTransition) {
final intNH = mHistory.size();
intaddPos = -1;
if(!newTask){//如果不是新Task,則從mHistory中找到對應的ActivityRecord的位置
......
}
if(addPos < 0) addPos = NH;
//否則加到mHistory數組的最后
mHistory.add(addPos,r);
//設置ActivityRecord的inHistory變量為true,表示已經加到mHistory數組中了
r.putInHistory();
r.frontOfTask = newTask;
if (NH> 0) {
//判斷是否顯示Activity切換動畫之類的事情,需要與WindowManagerService交互
}
//最終調用resumeTopActivityLocked
if (doResume) resumeTopActivityLocked(null);//重點分析這個函數
}
~~~
在以上列出的startActivityLocked函數中,略去了一部分邏輯處理,這部分內容和Activity之間的切換動畫有關(通過這些動畫,使切換過程看起來更加平滑和美觀,需和WMS交互)。
* * * * *
**提示**:筆者認為,此處將Activity切換和動畫處理這兩個邏輯揉到一起并不合適,但是似乎也沒有更合適的地方來進行該工作了。讀者不妨自行研讀一下該段代碼以加深體會。
* * * * *
(5) startActivityUncheckedLocked總結
說實話,startActivityUncheckedLocked函數的復雜度超乎筆者的想象,光這些函數名就夠讓人頭疼的。但是針對本例而言,相關邏輯的難度還算適中,畢竟這是Activity啟動流程中最簡單的情況。可用一句話總結本例中startActivityUncheckedLocked函數的功能:創建ActivityRecord和TaskRecord并將ActivityRecord添加到mHistory末尾,然后調用resumeTopActivityLocked啟動它。
下面用一節來分析resumeTopActivityLocked函數。
3. resumeTopActivityLocked函數分析
**ActivityStack.java::resumeTopActivityLocked**
~~~
finalboolean resumeTopActivityLocked(ActivityRecord prev) {
//從mHistory中找到第一個需要啟動的ActivityRecord
ActivityRecord next = topRunningActivityLocked(null);
finalboolean userLeaving = mUserLeaving;
mUserLeaving = false;
if (next== null) {
//如果mHistory中沒有要啟動的Activity,則啟動Home
if(mMainStack) returnmService.startHomeActivityLocked();
}
//在本例中,next將是目標Activity
next.delayedResume= false;
......//和WMS交互,略去
//將該ActivityRecord從下面幾個隊列中移除
mStoppingActivities.remove(next);
mGoingToSleepActivities.remove(next);
next.sleeping = false;
mWaitingVisibleActivities.remove(next);
//如果當前正在中斷一個Activity,需先等待那個Activity pause完畢,然后系統會重新
//調用resumeTopActivityLocked函數以找到下一個要啟動的Activity
if(mPausingActivity != null) return false;
/************************請讀者注意***************************/
//①mResumedActivity指向上一次啟動的Activity,也就是當前界面顯示的這個Activity
//在本例中,當前Activity就是Home界面
if(mResumedActivity != null) {
//先中斷 Home。這種情況放到最后進行分析
startPausingLocked(userLeaving,false);
return true;
}
//②如果mResumedActivity為空,則一定是系統第一個啟動的Activity,讀者應能猜測到它就
//是Home
......//如果prev不為空,則需要通知WMS進行與Activity切換相關的工作
try {
//通知PKMS修改該Package stop狀態,詳細信息參考第4章“readLPw的‘佐料’”
//一節的說明
AppGlobals.getPackageManager().setPackageStoppedState(
next.packageName, false);
}......
if(prev!= null){
......//還是和WMS有關,通知它停止繪畫
}
if(next.app != null && next.app.thread != null) {
//如果該ActivityRecord已有對應的進程存在,則只需要重啟Activity。就本例而言,
//此進程還不存在,所以要先創建一個應用進程
} else {
//第一次啟動
if (!next.hasBeenLaunched) {
next.hasBeenLaunched = true;
} else {
......//通知WMS顯示啟動界面
}
//調用另外一個startSpecificActivityLocked函數
startSpecificActivityLocked(next, true, true);
}
returntrue;
}
~~~
resumeTopActivityLocked函數中有兩個非常重要的關鍵點:
- 如果mResumedActivity不為空,則需要先暫停(pause)這個Activity。由代碼中的注釋可知,mResumedActivity代表上一次啟動的(即當前正顯示的)Activity。現在要啟動一個新的Activity,須先停止當前Activity,這部分工作由startPausingLocked函數完成。
- 那么,mResumedActivity什么時候為空呢?當然是在啟動全系統第一個Activity時,即啟動Home界面的時候。除此之外,該值都不會為空。
先分析第二個關鍵點,即mResumedActivity為null的情況選擇分析此種情況的原因是:如果先分析startPausingLocked,則后續分析會牽扯三個進程,即當前Activity所在進程、AMS所在進程及目標進程,分析的難度相當大。
好了,繼續我們的分析。resumeTopActivityLocked最后將調用另外一個startSpecificActivityLocked,該函數將真正創建一個應用進程。
(1) startSpecificActivityLocked分析
**ActivityStack.java::startSpecificActivityLocked**
~~~
private final voidstartSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
//從AMS中查詢是否已經存在滿足要求的進程(根據processName和uid來查找)
//在本例中,查詢結果應該為null
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid);
//設置啟動時間等信息
if(r.launchTime == 0) {
r.launchTime = SystemClock.uptimeMillis();
if(mInitialStartTime == 0) mInitialStartTime = r.launchTime;
} else if(mInitialStartTime == 0) {
mInitialStartTime = SystemClock.uptimeMillis();
}
//如果該進程存在并已經向AMS注冊(例如之前在該進程中啟動了其他Activity)
if (app!= null && app.thread != null) {
try {
app.addPackage(r.info.packageName);
//通知該進程中的啟動目標Activity
realStartActivityLocked(r, app, andResume, checkConfig);
return;
}......
}
//如果該進程不存在,則需要調用AMS的startProcessLocked創建一個應用進程
mService.startProcessLocked(r.processName, r.info.applicationInfo,
true, 0,"activity",r.intent.getComponent(), false);
}
~~~
來看AMS的startProcessLocked函數,它將創建一個新的應用進程。
(2) startProcessLocked分析
**ActivityManagerService.java::startProcessLocked**
~~~
final ProcessRecord startProcessLocked(StringprocessName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName,
boolean allowWhileBooting) {
//根據processName和uid尋找是否已經存在ProcessRecord
ProcessRecordapp = getProcessRecordLocked(processName, info.uid);
if (app!= null && app.pid > 0) {
......//處理相關情況
}
StringhostingNameStr = hostingName != null
? hostingName.flattenToShortString() : null;
//①處理FLAG_FROM_BACKGROUND標志,見下文解釋
if((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
if(mBadProcesses.get(info.processName, info.uid) != null)
return null;
} else {
mProcessCrashTimes.remove(info.processName,info.uid);
if(mBadProcesses.get(info.processName, info.uid) != null) {
mBadProcesses.remove(info.processName, info.uid);
if (app != null) app.bad =false;
}
}
if (app== null) {
//創建一個ProcessRecord,并保存到mProcessNames中。注意,此時還沒有創建實際進程
app= newProcessRecordLocked(null, info, processName);
mProcessNames.put(processName, info.uid, app);
}else app.addPackage(info.packageName);
......
//②調用另外一個startProcessLocked函數
startProcessLocked(app, hostingType, hostingNameStr);
return(app.pid != 0) ? app : null;
}
~~~
在以上代碼中列出兩個關鍵點,其中第一點和FLAG_FROM_BACKGROUND有關,相關知識點如下:
- FLAG_FROM_BACKGROUND標識發起這次啟動的Task屬于后臺任務。很顯然,手機中沒有界面供用戶操作位于后臺Task中的Activity。如果沒有設置該標志,那么這次啟動請求就是由前臺Task因某種原因而觸發的(例如用戶單擊某個按鈕)。
- 如果一個應用進程在1分鐘內連續崩潰超過2次,則AMS會將其ProcessRecord加入所謂的mBadProcesses中。一個應用崩潰后,系統會彈出一個警告框以提醒用戶。但是,如果一個后臺Task啟動了一個“BadProcess”,然后該Process崩潰,結果彈出一個警告框,那么用戶就會覺得很奇怪:“為什么突然彈出一個框?”因此,此處將禁止后臺Task啟動“Bad Process”。如果用戶主動選擇啟動(例如單擊一個按鈕),則不能禁止該操作,并且要把應用進程從mBadProcesses中移除,以給它們“重新做人”的機會。當然,要是該應用每次啟動時都會崩潰,而且用戶不停地去啟動,那該用戶可能是位測試工作者。
* * * * *
**提示**:這其實是一種安全機制,防止不健全的程序不斷啟動可能會崩潰的組件,但是這種機制并不限制用戶的行為。
* * * * *
下面來看第二個關鍵點,即另一個startProcessLocked函數,其代碼如下:
**ActivityManagerService.java::startProcessLocked**
~~~
private final voidstartProcessLocked(ProcessRecord app,
String hostingType, StringhostingNameStr) {
if(app.pid > 0 && app.pid != MY_PID) {
synchronized (mPidsSelfLocked) {
mPidsSelfLocked.remove(app.pid);
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
}
app.pid = 0;
}
//mProcessesOnHold用于保存那些在系統還沒有準備好就提前請求啟動的ProcessRecord
mProcessesOnHold.remove(app);
updateCpuStats();
System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
mProcDeaths[0] = 0;
try {
intuid = app.info.uid;
int[] gids = null;
try {//從PKMS中查詢該進程所屬的gid
gids = mContext.getPackageManager().getPackageGids(
app.info.packageName);
}......
......//工廠測試
intdebugFlags = 0;
if((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
debugFlags |=Zygote.DEBUG_ENABLE_DEBUGGER;
debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
}......//設置其他一些debugFlags
//發送消息給Zygote,它將派生一個子進程,該子進程執行ActivityThread的main函數
//注意,我們傳遞給Zygote的參數并沒有包含任何與Activity相關的信息。現在僅僅啟動
//一個應用進程
Process.ProcessStartResult startResult =
Process.start("android.app.ActivityThread",
app.processName, uid, uid, gids, debugFlags,
app.info.targetSdkVersion, null);
//電量統計項
BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
synchronized (bs) {
if(bs.isOnBattery()) app.batteryStats.incStartsLocked();
}
//如果該進程為persisitent,則需要通知Watchdog,實際上processStarted內部只
//關心剛才創建的進程是不是com.android.phone
if(app.persistent) {
Watchdog.getInstance().processStarted(app.processName,
startResult.pid);
}
app.pid= startResult.pid;
app.usingWrapper = startResult.usingWrapper;
app.removed = false;
synchronized (mPidsSelfLocked) {
//以pid為key,將代表該進程的ProcessRecord對象加入到mPidsSelfLocked中保管
this.mPidsSelfLocked.put(startResult.pid, app);
//發送一個超時消息,如果這個新創建的應用進程10秒內沒有和AMS交互,則可斷定
//該應用進程啟動失敗
Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
msg.obj = app;
//正常的超時時間為10秒。不過如果該應用進程通過valgrind加載,則延長到300秒
//valgrind是Linux平臺上一款檢查內存泄露的程序,被加載的應用將在它的環境中工作,
//這項工作需耗費較長時間。讀者可查詢valgrind的用法
mHandler.sendMessageDelayed(msg,startResult.usingWrapper
?PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
}......
}
~~~
startProcessLocked通過發送消息給Zygote以派生一個應用進程[^①],讀者仔細研究所發消息的內容,大概會發現此處并未設置和Activity相關的信息,也就是說,該進程啟動后,將完全不知道自己要干什么,怎么辦?下面就此進行分析。
4. startActivity分析之半程總結
很抱歉,我們現在還處于startActivity分析之旅的中間點,即使越過了很多險灘惡途,一路走來還是發覺有點艱難。此處用圖6-14來記錄半程中的各個關鍵點。
:-: 
圖6-14 startActivity半程總結
圖6-14列出了針對本例的調用順序,其中對每個函數的大體功能也做了簡單描述。
* * * * *
**注意**:圖6-14中的調用順序及功能說明只是針對本例而言的。讀者以后可結合具體情況再深入研究其中的內容。
* * * * *
5. 應用進程的創建及初始化
如前所述,應用進程的入口是ActivityThread的main函數,它是在主線程中執行的,其代碼如下:
**ActivityThread.java::main**
~~~
public static void main(String[] args) {
SamplingProfilerIntegration.start();
//和調試及strictMode有關
CloseGuard.setEnabled(false);
//設置進程名為"<pre-initialized>"
Process.setArgV0("<pre-initialized>");
//準備主線程消息循環
Looper.prepareMainLooper();
if(sMainThreadHandler == null)
sMainThreadHandler = new Handler();
//創建一個ActivityThread對象
ActivityThread thread = new ActivityThread();
//①調用attach函數,注意其參數值為false
thread.attach(false);
Looper.loop(); //進入主線程消息循環
throw newRuntimeException("Main thread loop unexpectedly exited");
}
~~~
在main函數內部將創建一個消息循環Loop,接著調用ActivityThread的attach函數,最終將主線程加入消息循環。
我們在分析AMS的setSystemProcess時曾分析過ActivityThread的attach函數,那時傳入的參數值為true。現在來看設置其為false的情況:
**ActivityThread.java::attach**
~~~
private void attach(boolean system) {
sThreadLocal.set(this);
mSystemThread = system;
if(!system) {
ViewRootImpl.addFirstDrawHandler(new Runnable() {
public void run() {
ensureJitEnabled();
}
});
//設置在DDMS中看到的本進程的名字為"<pre-initialized>"
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>");
//設置RuntimeInit的mApplicationObject參數,后續會介紹RuntimeInit類
RuntimeInit.setApplicationObject(mAppThread.asBinder());
//獲取和AMS交互的Binder客戶端
IActivityManager mgr = ActivityManagerNative.getDefault();
try {
//①調用AMS的attachApplication,mAppThread為ApplicationThread類型,
//它是應用進程和AMS交互的接口
mgr.attachApplication(mAppThread);
}......
} else......// system process的處理
ViewRootImpl.addConfigCallback(newComponentCallbacks2()
{.......//添加回調函數});
}
~~~
我們知道,AMS創建一個應用進程后,會設置一個超時時間(一般是10秒)。如果超過這個時間,應用進程還沒有和AMS交互,則斷定該進程創建失敗。所以,應用進程啟動后,需要盡快和AMS交互,即調用AMS的attachApplication函數。在該函數內部將調用attachApplicationLocked,所以此處直接分析attachApplicationLocked,先看其第一階段的工作。
(1) attachApplicationLocked分析之一
**ActivityManagerService.java::attachApplicationLocked**
~~~
private final booleanattachApplicationLocked(IApplicationThread thread,
int pid) {//此pid代表調用進程的pid
ProcessRecord app;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);//根據pid查找對應的ProcessRecord對象
}
}else app = null;
/*
如果該應用進程由AMS啟動,則它一定在AMS中有對應的ProcessRecord,讀者可回顧前面創建
應用進程的代碼:AMS先創建了一個ProcessRecord對象,然后才發命令給Zygote。
如果此處app為null,表示AMS沒有該進程的記錄,故需要“殺死”它
*/
if (app== null) {
if(pid > 0 && pid != MY_PID) //如果pid大于零,且不是SystemServer進程,則
//Quietly(即不打印任何輸出)”殺死”process
Process.killProcessQuiet(pid);
else{
//調用ApplicationThread的scheduleExit函數。應用進程完成處理工作后
//將退出運行
//為何不像上面一樣直接殺死它呢?可查閱linux pid相關的知識并自行解答
thread.scheduleExit();
}
returnfalse;
}
/*
判斷app的thread是否為空,如果不為空,則表示該ProcessRecord對象還未和一個
應用進程綁定。注意,app是根據pid查找到的,如果舊進程沒有被殺死,系統則不會重用
該pid。為什么此處會出現ProcessRecord thread不為空的情況呢?見下面代碼的注釋說明
*/
if(app.thread != null) handleAppDiedLocked(app, true, true);
StringprocessName = app.processName;
try {
/*
創建一個應用進程訃告接收對象。當應用進程退出時,該對象的binderDied將被調
用。這樣,AMS就能做相應處理。binderDied函數將在另外一個線程中執行,其內部也會
調用handleAppDiedLocked。假如用戶在binderDied被調用之前又啟動一個進程,
那么就會出現以上代碼中app.thread不為null的情況。這是多線程環境中常出現的
情況,不熟悉多線程編程的讀者要仔細體會。
*/
AppDeathRecipient adr = new AppDeathRecipient(pp, pid, thread);
thread.asBinder().linkToDeath(adr, 0);
app.deathRecipient = adr;
}......
//設置該進程的調度優先級和oom_adj等成員
app.thread= thread;
app.curAdj = app.setAdj = -100;
app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.forcingToForeground = null;
app.foregroundServices = false;
app.hasShownUi = false;
app.debugging = false;
//啟動成功,從消息隊列中撤銷PROC_START_TIMEOUT_MSG消息
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
~~~
attachApplicationLocked第一階段的工作比較簡單:
- 設置代表該應用進程的ProcessRecrod對象的一些成員變量,例如用于和應用進程交互的thread對象、進程調度優先級及oom_adj的值等。
- 從消息隊列中撤銷PROC_START_TIMEOUT_MSG。
至此,該進程啟動成功,但是這一階段的工作僅針對進程本身(如設置調度優先級,oom_adj等),還沒有涉及和Activity啟動相關的內容,這部分工作將在第二階段完成。
(2) attachApplicationLocked分析之二
**ActivityManagerService.java::attachApplicationLocked**
~~~
......
//SystemServer早就啟動完畢,所以normalMode為true
booleannormalMode = mProcessesReady || isAllowedWhileBooting(app.info);
/*
我們在6.2.3的標題1中分析過generateApplicationProvidersLocked函數,
在該函數內部將查詢(根據進程名,uid確定)PKMS以獲取需運行在該進程中的ContentProvider
*/
Listproviders = normalMode ? generateApplicationProvidersLocked(app) : null;
try {
int testMode = IApplicationThread.DEBUG_OFF;
if(mDebugApp != null && mDebugApp.equals(processName)) {
......//處理debug選項
}
......//處理Profile
boolean isRestrictedBackupMode = false;
......//
//dex化對應的apk包
ensurePackageDexOpt(app.instrumentationInfo!= null ?
app.instrumentationInfo.packageName : app.info.packageName);
//如果設置了Instrumentation類,該類所在的Package也需要dex化
if(app.instrumentationClass != null)
ensurePackageDexOpt(app.instrumentationClass.getPackageName());
ApplicationInfo appInfo =app.instrumentationInfo != null
? app.instrumentationInfo :app.info;
//查詢該Application使用的CompatibiliyInfo
app.compat =compatibilityInfoForPackageLocked(appInfo);
if (profileFd != null) //用于記錄性能文件
profileFd = profileFd.dup();
//①通過ApplicationThread和應用進程交互,調用其bindApplication函數
thread.bindApplication(processName,appInfo, providers,
app.instrumentationClass, profileFile, profileFd,
profileAutoStop,app.instrumentationArguments,
app.instrumentationWatcher,testMode,
isRestrictedBackupMode || !normalMode, app.persistent,
mConfiguration, app.compat, getCommonServicesLocked(),
mCoreSettingsObserver.getCoreSettingsLocked());
//updateLruProcessLocked函數以后再作分析
updateLruProcessLocked(app,false, true);
//記錄兩個時間
app.lastRequestedGc= app.lastLowMemory = SystemClock.uptimeMillis();
}......//try結束
..//從mProcessesOnHold和mPersistentStartingProcesses中刪除相關信息
mPersistentStartingProcesses.remove(app);
mProcessesOnHold.remove(app);
~~~
由以上代碼可知,第二階段的工作主要是為調用ApplicationThread的bindApplication做準備,將在后面的章節中分析該函數的具體內容。此處先來看它的原型。
~~~
/*
正如我們在前面分析時提到的,剛創建的這個進程并不知道自己的歷史使命是什么,甚至連自己的
進程名都不知道,只能設為"<pre-initialized>"。其實,Android應用進程的歷史使命是
AMS在其啟動后才賦予它的,這一點和我們理解的一般意義上的進程不太一樣。根據之前的介紹, Android的組件應該運行在Android運行環境中。從OS角度來說,該運行環境需要和一個進程綁定。
所以,創建應用進程這一步只是創建了一個能運行Android運行環境的容器,而我們的工作實際上
還遠未結束。
bindApplication的功能就是創建并初始化位于該進程中的Android運行環境
*/
public final void bindApplication(
StringprocessName,//進程名,一般是package名
ApplicationInfo appInfo,//該進程對應的ApplicationInfo
List<ProviderInfo> providers,//在該APackage中聲明的Provider信息
ComponentName instrumentationName,//和instrumentation有關
//下面3個參數和性能統計有關
StringprofileFile,
ParcelFileDescriptor profileFd, boolean autoStopProfiler,
//這兩個和Instrumentation有關,在本例中,這幾個參數暫時都沒有作用
Bundle instrumentationArgs,
IInstrumentationWatcherinstrumentationWatcher,
intdebugMode,//調試模式
boolean isRestrictedBackupMode,
boolean persistent,//該進程是否是persist
Configuration config,//當前的配置信息,如屏幕大小和語言等
CompatibilityInfocompatInfo,//兼容信息
//AMS將常用的Service信息傳遞給應用進程,目前傳遞的Service信息只有PKMS、
//WMS及AlarmManagerService。讀者可參看AMS getCommonServicesLocked函數
Map<String,IBinder> services,
BundlecoreSettings)//核心配置參數,目前僅有“long_press”值
~~~
對bindApplication的原型分析就到此為止,再來看attachApplicationLocked最后一階段的工作。
(3) attachApplicationLocked分析之三
**ActivityManagerService.java::attachApplicationLocked**
~~~
booleanbadApp = false;
booleandidSomething = false;
/*
至此,應用進程已經準備好了Android運行環境,下面這句調用代碼將返回ActivityStack中
第一個需要運行的ActivityRecord。由于多線程的原因,難道能保證得到的hr就是我們的目標
Activity嗎?
*/
ActivityRecord hr = mMainStack.topRunningActivityLocked(null);
if (hr !=null && normalMode) {
//需要根據processName和uid等確定該Activity是否運行與目標進程有關
if(hr.app == null && app.info.uid == hr.info.applicationInfo.uid
&& processName.equals(hr.processName)) {
try {
//調用AS的realStartActivityLocked啟動該Activity,最后兩個參數為true
if (mMainStack.realStartActivityLocked(hr, app, true, true)) {
didSomething = true;
}
} catch (Exception e) {
badApp = true; //設置badApp為true
}
} else{
//如果hr和目標進程無關,則調用ensureActivitiesVisibleLocked函數處理它
mMainStack.ensureActivitiesVisibleLocked(hr, null, processName, 0);
}
}// if (hr!= null && normalMode)判斷結束
//mPendingServices存儲那些因目標進程還未啟動而處于等待狀態的ServiceRecord
if(!badApp && mPendingServices.size() > 0) {
ServiceRecord sr = null;
try{
for (int i=0; i<mPendingServices.size(); i++) {
sr = mPendingServices.get(i);
//和Activity不一樣的是,如果Service不屬于目標進程,則暫不處理
if (app.info.uid != sr.appInfo.uid
||!processName.equals(sr.processName)) continue;//繼續循環
//該Service將運行在目標進程中,所以從mPendingService中移除它
mPendingServices.remove(i);
i--;
//處理此service的啟動,以后再作分析
realStartServiceLocked(sr, app);
didSomething = true;//設置該值為true
}
}
}......
......//啟動等待的BroadcastReceiver
......//啟動等待的BackupAgent,相關代碼類似Service的啟動
if(badApp) {
//如果以上幾個組件啟動有錯誤,則設置badApp為true。此處將調用handleAppDiedLocked
//進行處理。該函數我們以后再作分析
handleAppDiedLocked(app, false, true);
returnfalse;
}
/*
調整進程的oom_adj值。didSomething表示在以上流程中是否啟動了Acivity或其他組件。
如果啟動了任一組件,則didSomething為true。讀者以后會知道,這里的啟動只是向
應用進程發出對應的指令,客戶端進程是否成功處理還是未知數。基于這種考慮,所以此處不宜
馬上調節進程的oom_adj。
讀者可簡單地把oom_adj看做一種優先級。如果一個應用進程沒有運行任何組件,那么當內存
出現不足時,該進程是最先被系統殺死的。反之,如果一個進程運行的組件越多,那么它就越不易被
系統殺死以回收內存。updateOomAdjLocked就是根據該進程中組件的情況對應調節進程的
oom_adj值的。
*/
if(!didSomething) updateOomAdjLocked();
returntrue;
}
~~~
attachApplicationLocked第三階段的工作就是通知應用進程啟動Activity和Service等組件,其中用于啟動Activity的函數是ActivityStack realStartActivityLocked。
此處先來分析應用進程的bindApplication,該函數將為應用進程綁定一個Application。
* * * * *
**提示**:還記得AMS中System Context執行的兩次init嗎?第二次init的功能就是將Context和對應的Application綁定在一起。
* * * * *
(4) ApplicationThread的bindApplication分析
bindApplication在ApplicationThread中的實現,其代碼如下:
**ActivityThread.java::bindApplication**
~~~
public final void bindApplication(......) {
if(services != null)//保存AMS傳遞過來的系統Service信息
ServiceManager.initServiceCache(services);
//向主線程消息隊列添加SET_CORE_SETTINGS消息
setCoreSettings(coreSettings);
//創建一個AppBindData對象,其實就是用來存儲一些參數
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
data.providers = providers;
data.instrumentationName = instrumentationName;
......//將AMS傳過來的參數保存到AppBindData中
//向主線程發送H.BIND_APPLICATION消息
queueOrSendMessage(H.BIND_APPLICATION, data);
}
~~~
由以上代碼可知,ApplicationThread接收到來自AMS的指令后,均會將指令中的參數封裝到一個數據結構中,然后通過發送消息的方式轉交給主線程去處理。BIND_APPLICATION最終將由handleBindApplication函數處理。該函數并不復雜,但是其中有些點是值得關注的,這些點主要是初始化應用進程的一些參數。handleBindApplication函數的代碼如下:
**ActivityThread.java::handleBindApplication**
~~~
private void handleBindApplication(AppBindDatadata) {
mBoundApplication = data;
mConfiguration = new Configuration(data.config);
mCompatConfiguration = new Configuration(data.config);
//初始化性能統計對象
mProfiler = new Profiler();
mProfiler.profileFile = data.initProfileFile;
mProfiler.profileFd = data.initProfileFd;
mProfiler.autoStopProfiler = data.initAutoStopProfiler;
//設置進程名。從此,之前那個默默無名的進程終于有了自己的名字
Process.setArgV0(data.processName);
android.ddm.DdmHandleAppName.setAppName(data.processName);
if(data.persistent) {
//對于persistent的進程,在低內存設備上,不允許其使用硬件加速顯示
Display display =
WindowManagerImpl.getDefault().getDefaultDisplay();
//當內存大于512MB,或者屏幕尺寸大于1024*600,可以使用硬件加速
if(!ActivityManager.isHighEndGfx(display))
HardwareRenderer.disable(false);
}
//啟動性能統計
if(mProfiler.profileFd != null) mProfiler.startProfiling();
//如果目標SDK版本小于12,則設置AsyncTask使用pool executor,否則使用
//serializedexecutor。這些executor涉及Java Concurrent類,對此不熟悉的讀者
//請自行學習和研究。
if(data.appInfo.targetSdkVersion <= 12)
AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
//設置timezone
TimeZone.setDefault(null);
//設置語言
Locale.setDefault(data.config.locale);
//設置資源及兼容模式
applyConfigurationToResourcesLocked(data.config, data.compatInfo);
applyCompatConfiguration();
//根據傳遞過來的ApplicationInfo創建一個對應的LoadApk對象
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
//對于系統APK,如果當前系統為userdebug/eng版,則需要記錄log信息到dropbox的日志記錄
if((data.appInfo.flags &
(ApplicationInfo.FLAG_SYSTEM |
ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0) {
StrictMode.conditionallyEnableDebugLogging();
}
/*
如目標SDK版本大于9,則不允許在主線程使用網絡操作(如Socketconnect等),否則拋出
NetworkOnMainThreadException,這么做的目的是防止應用程序在主線程中因網絡操作執行
時間過長而造成用戶體驗下降。說實話,沒有必要進行這種限制,在主線程中是否網絡操作
是應用的事情。再說,Socket也可作為進程間通信的手段,在這種情況下,網絡操作耗時很短。
作為系統,不應該設置這種限制。另外,Goolge可以提供一些開發指南或規范來指導開發者,
而不應如此蠻橫地強加限制。
*/
if (data.appInfo.targetSdkVersion> 9)
StrictMode.enableDeathOnNetwork();
//如果沒有設置屏幕密度,則為Bitmap設置默認的屏幕密度
if((data.appInfo.flags
&ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) == 0)
Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT);
if(data.debugMode != IApplicationThread.DEBUG_OFF){
......//調試模式相關處理
}
IBinder b= ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
IConnectivityManager service =
IConnectivityManager.Stub.asInterface(b);
try {
//設置Http代理信息
ProxyPropertiesproxyProperties = service.getProxy();
Proxy.setHttpProxySystemProperty(proxyProperties);
} catch(RemoteException e) {}
if(data.instrumentationName != null){
//在正常情況下,此條件不滿足
} else {
//創建Instrumentation對象,在正常情況都再這個條件下執行
mInstrumentation = new Instrumentation();
}
//如果Package中聲明了FLAG_LARGE_HEAP,則可跳過虛擬機的內存限制,放心使用內存
if((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0)
dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
//創建一個Application,data.info為LoadedApk類型,在其內部會通過Java反射機制
//創建一個在該APK AndroidManifest.xml中聲明的Application對象
Applicationapp = data.info.makeApplication(
data.restrictedBackupMode, null);
//mInitialApplication保存該進程中第一個創建的Application
mInitialApplication = app;
//安裝本Package中攜帶的ContentProvider
if(!data.restrictedBackupMode){
List<ProviderInfo> providers = data.providers;
if(providers != null) {
//installContentProviders我們已經分析過了
installContentProviders(app, providers);
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
}
}
//調用Application的onCreate函數,做一些初始工作
mInstrumentation.callApplicationOnCreate(app);
}
~~~
由以上代碼可知,bindApplication函數將設置一些初始化參數,其中最重要的有:
- 創建一個Application對象,該對象是本進程中運行的第一個Application。
- 如果該Application有ContentProvider,則應安裝它們。
* * * * *
**提示**:從以上代碼可知,ContentProvider的創建就在bindApplication函數中,其時機早于其他組件的創建。
* * * * *
(5) 應用進程的創建及初始化總結
本節從應用進程的入口函數main開始,分析了應用進程和AMS之間的兩次重要交互,它們分別是:
- 在應用進程啟動后,需要盡快調用AMS的attachApplication函數,該函數是這個剛呱呱墜地的應用進程第一次和AMS交互。此時的它還默默“無名”,連一個確定的進程名都沒有。不過沒關系,attachApplication函數將根據創建該應用進程之前所保存的ProcessRecord為其準備一切“手續”。
- attachApplication準備好一切后,將調用應用進程的bindApplication函數,在該函數內部將發消息給主線程,最終該消息由handleBindApplication處理。handleBindApplication將為該進程設置進程名,初始化一些策略和參數信息等。另外,它還創建一個Application對象。同時,如果該Application聲明了ContentProvider,還需要為該進程安裝ContentProvider。
* * * * *
**提示**:這個流程有點類似生孩子,一般生之前需要到醫院去登記,生完后又需去注冊戶口,如此這般,這個孩子才會在社會有合法的身份。
* * * * *
6. ActivityStack realStartActivityLocked分析
如前所述,AMS調用完bindApplication后,將通過realStartActivityLocked啟動Activity。在此之前,要創建完應用進程并初始化Android運行環境(除此之外,連ContentProvider都安裝好了)。
**ActivityStack.java::realStartActivityLocked**
~~~
//注意,在本例中該函數的最后兩個參數的值都為true
final booleanrealStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
r.startFreezingScreenLocked(app, 0);
mService.mWindowManager.setAppVisibility(r,true);
if(checkConfig) {
......//處理Config發生變化的情況
mService.updateConfigurationLocked(config, r, false);
}
r.app =app;
app.waitingToKill = null;
//將ActivityRecord加到ProcessRecord的activities中保存
int idx= app.activities.indexOf(r);
if (idx< 0) app.activities.add(r);
//更新進程的調度優先級等,以后再分析該函數
mService.updateLruProcessLocked(app, true, true);
try {
List<ResultInfo> results = null;
List<Intent> newIntents = null;
if(andResume) {
results = r.results;
newIntents = r.newIntents;
}
if(r.isHomeActivity) mService.mHomeProcess = app;
//看看是否有dex對應Package的需要
mService.ensurePackageDexOpt(
r.intent.getComponent().getPackageName());
r.sleeping = false;
r.forceNewConfig = false;
......
//①通知應用進程啟動Activity
app.thread. scheduleLaunchActivity (new Intent(r.intent), r,
System.identityHashCode(r), r.info, mService.mConfiguration,
r.compat, r.icicle, results, newIntents, !andResume,
mService.isNextTransitionForward(), profileFile, profileFd,
profileAutoStop);
if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
......//處理heavy-weight的情況
}
}
} ......//try結束
r.launchFailed = false;
......
if(andResume) {
r.state = ActivityState.RESUMED;
r.stopped = false;
mResumedActivity = r;//設置mResumedActivity為目標Activity
r.task.touchActiveTime();
//添加該任務到近期任務列表中
if(mMainStack) mService.addRecentTaskLocked(r.task);
//②關鍵函數,見下文分析
completeResumeLocked(r);
//如果在這些過程中,用戶按了Power鍵,怎么辦?
checkReadyForSleepLocked();
r.icicle = null;
r.haveState = false;
}......
//啟動系統設置向導Activity,當系統更新或初次使用時需要進行配置
if(mMainStack) mService.startSetupActivityLocked();
returntrue;
}
~~~
在以上代碼中有兩個關鍵函數,分別是:scheduleLaunchActivity和completeResumeLocked。其中,scheduleLaunchActivity用于和應用進程交互,通知它啟動目標Activity。而completeResumeLocked將繼續AMS的處理流程。先來看第一個關鍵函數。
(1) scheduleLaunchActivity函數分析
**ActivityThread.java::scheduleLaunchActivity**
~~~
public final void scheduleLaunchActivity(Intentintent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig,CompatibilityInfo compatInfo,
Bundlestate, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, booleanisForward,
StringprofileName, ParcelFileDescriptor profileFd,
booleanautoStopProfiler) {
ActivityClientRecord r = new ActivityClientRecord();
......//保存AMS發送過來的參數信息
//向主線程發送消息,該消息的處理在handleLaunchActivity中進行
queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
}
~~~
**ActivityThread.java::handleMessage**
~~~
public void handleMessage(Message msg) {
switch(msg.what) {
case LAUNCH_ACTIVITY: {
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
//根據ApplicationInfo得到對應的PackageInfo
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
//調用handleLaunchActivity處理
handleLaunchActivity(r, null);
}break;
......
}
~~~
**ActivityThread.java::handleLaunchActivity**
~~~
private voidhandleLaunchActivity(ActivityClientRecord r,
Intent customIntent){
unscheduleGcIdler();
if (r.profileFd != null) {......//略去}
handleConfigurationChanged(null, null);
/*
①創建Activity,通過Java反射機制創建目標Activity,將在內部完成Activity生命周期
的前兩步,即調用其onCreate和onStart函數。至此,我們的目標com.dfp.test.TestActivity
創建完畢
*/
Activitya = performLaunchActivity(r, customIntent);
if (a !=null) {
r.createdConfig = new Configuration(mConfiguration);
BundleoldState = r.state;
//②調用handleResumeActivity,其內部有個關鍵點,見下文分析
handleResumeActivity(r.token, false, r.isForward);
if(!r.activity.mFinished && r.startsNotResumed) {
.......//
. r.paused = true;
}else {
//如果啟動錯誤,通知AMS
ActivityManagerNative.getDefault()
.finishActivity(r.token,Activity.RESULT_CANCELED, null);
}
}
~~~
handleLaunchActivity的工作包括:
- 首先調用performLaunchActivity,該在函數內部通過Java反射機制創建目標Activity,然后調用它的onCreate及onStart函數。
- 調用handleResumeActivity,會在其內部調用目標Activity的onResume函數。除此之外,handleResumeActivity還完成了一件很重要的事情,見下面的代碼:
**ActivityThread.java::handleResumeActivity**
~~~
final void handleResumeActivity(IBinder token,boolean clearHide,
booleanisForward) {
unscheduleGcIdler();
//內部調用目標Activity的onResume函數
ActivityClientRecord r = performResumeActivity(token, clearHide);
if (r !=null) {
finalActivity a = r.activity;
final int forwardBit = isForward ?
WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
......
if(!r.onlyLocalRequest) {
//將上面完成onResume的Activity保存到mNewActivities中
r.nextIdle = mNewActivities;
mNewActivities = r;
//①向消息隊列中添加一個Idler對象
Looper.myQueue().addIdleHandler(new Idler());
}
r.onlyLocalRequest = false;
......
}
~~~
根據第2章對MessageQueue的分析,當消息隊列中沒有其他要處理的消息時,將處理以上代碼中通過addIdleHandler添加的Idler對象,也就是說,Idler對象的優先級最低,這是不是說它的工作不重要呢?非也。至少在handleResumeActivity函數中添加的這個Idler并不不簡單,其代碼如下:
**ActivityThread.java::Idler**
~~~
private class Idler implements MessageQueue.IdleHandler{
publicfinal boolean queueIdle() {
ActivityClientRecord a = mNewActivities;
booleanstopProfiling = false;
......
if (a !=null) {
mNewActivities = null;
IActivityManager am = ActivityManagerNative.getDefault();
ActivityClientRecord prev;
do {
if(a.activity != null && !a.activity.mFinished) {
//調用AMS的activityIdle
am.activityIdle(a.token, a.createdConfig, stopProfiling);
a.createdConfig = null;
}
prev =a;
a =a.nextIdle;
prev.nextIdle = null;
} while(a != null); //do循環結束
}//if(a!=null)判斷結束
......
ensureJitEnabled();
returnfalse;
}// queueIdle函數結束
}
~~~
由以上代碼可知,Idler將為那些已經完成onResume的Activity調用AMS的activityIdle函數。該函數是Activity成功創建并啟動的流程中與AMS交互的最后一步。雖然對應用進程來說,Idler處理的優先級最低,但AMS似乎不這么認為,因為它還設置了超時等待,以處理應用進程沒有及時調用activityIdle的情況。這個超時等待即由realStartActivityLocked中最后一個關鍵點completeResumeLocked函數設置。
(2) completeResumeLocked函數分析
**ActivityStack.java::completeResumeLocked**
~~~
private final voidcompleteResumeLocked(ActivityRecord next) {
next.idle = false;
next.results = null;
next.newIntents = null;
//發送一個超時處理消息,默認為10秒。IDLE_TIMEOUT_MSG就是針對acitivityIdle函數的
Messagemsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
msg.obj= next;
mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
//通知AMS
if(mMainStack) mService.reportResumedActivityLocked(next);
......//略去其他邏輯的代碼
}
~~~
由以上代碼可知,AMS給了應用進程10秒的時間,希望它在10秒內調用activityIdle函數。這個時間不算長,和前面AMS等待應用進程啟動的超時時間一樣。所以,筆者有些困惑,為什么要把這么重要的操作放到idler中去做。
下面來看activityIdle函數,在其內部將調用ActivityStack activityIdleInternal。
(3) activityIdleInternal函數分析
**ActivityStack.java::activityIdleInternal**
~~~
final ActivityRecord activityIdleInternal(IBindertoken, boolean fromTimeout,
Configuration config) {
/*
如果應用進程在超時時間內調用了activityIdleInternal函數,則fromTimeout為false
否則,一旦超時,在IDLE_TIMEOUT_MSG的消息處理中也會調用該函數,并設置fromTimeout
為true
*/
ActivityRecord res = null;
ArrayList<ActivityRecord> stops = null;
ArrayList<ActivityRecord> finishes = null;
ArrayList<ActivityRecord> thumbnails = null;
int NS =0;
int NF =0;
int NT =0;
IApplicationThread sendThumbnail = null;
booleanbooting = false;
booleanenableScreen = false;
synchronized (mService) {
//從消息隊列中撤銷IDLE_TIMEOUT_MSG
if(token != null) mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
int index= indexOfTokenLocked(token);
if(index >= 0) {
ActivityRecord r = mHistory.get(index);
res =r;
//注意,只有fromTimeout為true,才會走執行下面的條件語句
if(fromTimeout) reportActivityLaunchedLocked(fromTimeout, r, -1, -1);
if(config != null) r.configuration =config;
/*
mLaunchingActivity是一個WakeLock,它能防止在操作Activity過程中掉電,同時
這個WakeLock又不能長時間使用,否則有可能耗費過多電量。所以,系統設置了一個超時
處理消息LAUNCH_TIMEOUT_MSG,超時時間為10秒。一旦目標Activity啟動成功,
就需要需要釋放 WakeLock
*/
if(mResumedActivity == r && mLaunchingActivity.isHeld()) {
mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
mLaunchingActivity.release();
}
r.idle = true;
mService.scheduleAppGcsLocked();
......
ensureActivitiesVisibleLocked(null, 0);
if(mMainStack) {
if(!mService.mBooted) {
mService.mBooted = true;
enableScreen = true;
}
}//if (mMainStack)判斷結束
} else if(fromTimeout) {//注意,只有fromTimeout為true,才會走下面的case
reportActivityLaunchedLocked(fromTimeout, null, -1, -1);
}
/*
①processStoppingActivitiesLocked函數返回那些因本次Activity啟動而
被暫停(paused)的Activity
*/
stops =processStoppingActivitiesLocked(true);
......
for (i=0;i<NS; i++) {
ActivityRecord r = (ActivityRecord)stops.get(i);
synchronized (mService) {
//如果這些Acitivity 處于finishing狀態,則通知它們執行Destroy操作,最終它們
//的onDestroy函數會被調用
if(r.finishing) finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
else //否則將通知它們執行stop操作,最終Activity的onStop被調用
stopActivityLocked(r);
}//synchronized結束
}//for循環結束
......//處理等待結束的Activities
//發送ACTION_BOOT_COMPLETED廣播
if(booting) mService.finishBooting();
......
returnres;
}
~~~
在activityIdleInternal中有一個非常重要的關鍵點,即處理那些因為本次Activity啟動而被暫停的Activity。有兩種情況需考慮:
- 如果被暫停的Activity處于finishing狀態(例如Activity在其onStop中調用了finish函數),則調用finishCurrentActivityLocked。
- 否則,要調用stopActivityLocked處理暫停的Activity。
此處涉及除AMS和目標進程外的第三個進程,即被切換到后臺的那個進程。不過至此,我們的目標Activity終于正式登上了歷史舞臺。
* * * * *
**提示**:本例的分析結束了嗎?沒有。因為am設置了-W選項,所以其實我們還在startActivityAndWait函數中等待結果。ActivityStack中有兩個函數能夠觸發AMS notifyAll,一個是reportActivityLaunchedLocked,另一個是reportActivityVisibleLocked。前面介紹的activityInternal函數只在fromTimeout為true時才會調用reportActivityLaunchedLocked,而本例中fromTimeout為false,如何是好?該問題的解答非常復雜,姑且先一語帶過:當Activity顯示出來時,其在AMS中對應ActivityRecord對象的windowVisible函數將被調用,其內部會觸發reportActivityLaunchedLocked函數,這樣我們的startActivityAndWait才能被喚醒。
* * * * *
7. startActivity分析之后半程總結
總結startActivity后半部分的流程,主要涉及目標進程和AMS的交互,如圖6-15所示。
:-: 
圖6-15 startActivity后半程總結
圖6-15中涉及16個重要函數調用,而且這僅是startActivity后半部分的調用流程,可見整個流程有多么復雜!
8. startPausingLocked函數分析
現在我們分析圖6-14中的startPausingLocked分支。根據前面的介紹,當啟動一個新Activity時,系統將先行處理當前的Activity,即調用startPausingLocked函數來暫停當前Activity。
(1) startPausingLocked分析
**ActivityStack.java::startPausingLocked**
~~~
private final void startPausingLocked(booleanuserLeaving, boolean uiSleeping) {
//mResumedActivity保存當前正顯示的Activity,
ActivityRecord prev = mResumedActivity;
mResumedActivity = null;
//設置mPausingActivity為當前Activity
mPausingActivity = prev;
mLastPausedActivity = prev;
prev.state = ActivityState.PAUSING;//設置狀態為PAUSING
prev.task.touchActiveTime();
......
if(prev.app != null && prev.app.thread != null) {
try {
//①調用當前Activity所在進程的schedulePauseActivity函數
prev.app.thread.schedulePauseActivity(prev,prev.finishing,
userLeaving,prev.configChangeFlags);
if(mMainStack) mService.updateUsageStats(prev, false);
} ......//catch分支
}......//else分支
if(!mService.mSleeping && !mService.mShuttingDown) {
//獲取WakeLock,以防止在Activity切換過程中掉電
mLaunchingActivity.acquire();
if(!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
}
}
if(mPausingActivity != null) {
//暫停輸入事件派發
if(!uiSleeping) prev.pauseKeyDispatchingLocked();
//設置PAUSE超時,時間為500毫秒,這個時間相對較短
Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
msg.obj = prev;
mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
}......//else分支
}
~~~
startPausingLocked將調用應用進程的schedulePauseActivity函數,并設置500毫秒的超時時間,所以應用進程需盡快完成相關處理。和scheduleLaunchActivity一樣,schedulePauseActivity將向ActivityThread主線程發送PAUSE_ACTIVITY消息,最終該消息由handlePauseActivity來處理。
(2) handlePauseActivity分析
**ActivityThread.java::handlePauseActivity**
~~~
private void handlePauseActivity(IBinder token,boolean finished,
boolean userLeaving, int configChanges){
//當Activity處于finishing狀態時,finished參數為true,不過在本例中該值為false
ActivityClientRecord r = mActivities.get(token);
if (r !=null) {
//調用Activity的onUserLeaving函數,
if(userLeaving) performUserLeavingActivity(r);
r.activity.mConfigChangeFlags |=configChanges;
//調用Activity的onPause函數
performPauseActivity(token, finished, r.isPreHoneycomb());
......
try {
//調用AMS的activityPaused函數
ActivityManagerNative.getDefault().activityPaused(token);
}......
}
}
~~~
**ActivityManagerService.java::activityPaused**
~~~
public final void activityPaused(IBinder token) {
......
mMainStack.activityPaused(token, false);
}
~~~
**ActivityStack.java::activityPaused**
~~~
final void activityPaused(IBinder token, booleantimeout) {
ActivityRecord r = null;
synchronized (mService) {
int index= indexOfTokenLocked(token);
if (index>= 0) {
r =mHistory.get(index);
//從消息隊列中撤銷PAUSE_TIMEOUT_MSG消息
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
if(mPausingActivity == r) {
r.state = ActivityState.PAUSED;//設置ActivityRecord的狀態
completePauseLocked();//完成本次Pause操作
}......
}
}
~~~
(3) completePauseLocked分析
**ActivityStack.java::completePauseLocked**
~~~
private final void completePauseLocked() {
ActivityRecord prev = mPausingActivity;
if (prev!= null) {
if(prev.finishing) {
prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
} elseif (prev.app != null) {
if(prev.configDestroy) {
destroyActivityLocked(prev, true, false);
} else {
//①將剛才被暫停的Activity保存到mStoppingActivities中
mStoppingActivities.add(prev);
if(mStoppingActivities.size() > 3) {
//如果被暫停的Activity超過3個,則發送IDLE_NOW_MSG消息,該消息最終
//由我們前面介紹的activeIdleInternal處理
scheduleIdleLocked();
}
}
//設置mPausingActivity為null,這是圖6-14②、③分支的分割點
mPausingActivity = null;
}
//②resumeTopActivityLocked將啟動目標Activity
if(!mService.isSleeping()) resumeTopActivityLocked(prev);
......
}
~~~
就本例而言,以上代碼還算簡單,最后還是通過resumeTopActivityLocked來啟動目標Activity。當然,由于之前已經設置了mPausingActivity為null,所以最終會走到圖6-14中③的分支。
(4) stopActivityLocked分析
根據前面的介紹,此次目標Activity將走完onCreate、onStart和onResume流程,但是被暫停的Activity才剛走完onPause流程,那么它的onStop什么時候調用呢?
答案就在activityIdelInternal中,它將為mStoppingActivities中的成員調用stopActivityLocked函數。
**ActivityStack.java::stopActivityLocked**
~~~
privatefinal void stopActivityLocked(ActivityRecord r) {
if((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
|| (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
if(!r.finishing) {
requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
"no-history");
}
} elseif (r.app != null && r.app.thread != null) {
try {
r.stopped = false;
//設置STOPPING狀態,并調用對應的scheduleStopActivity函數
r.state = ActivityState.STOPPING;
r.app.thread.scheduleStopActivity(r, r.visible,
r.configChangeFlags);
}......
}
~~~
對應進程的scheduleStopActivity函數將根據visible的情況,向主線程消息循環發送H. STOP_ACTIVITY_HIDE或H. STOP_ACTIVITY_SHOW消息。不論哪種情況,最終都由handleStopActivity來處理。
**ActivityThread.java::handleStopActivity**
~~~
private void handleStopActivity(IBinder token,boolean show, int configChanges) {
ActivityClientRecord r = mActivities.get(token);
r.activity.mConfigChangeFlags |= configChanges;
StopInfoinfo = new StopInfo();
//調用Activity的onStop函數
performStopActivityInner(r, info, show, true);
......
try { //調用AMS的activityStopped函數
ActivityManagerNative.getDefault().activityStopped(
r.token, r.state, info.thumbnail, info.description);
}
}
~~~
AMS沒有為stop設置超時消息處理。嚴格來說,還是有超時限制的,只是這個超時處理與activityIdleInternal結合起來了。
(5) startPausingLocked總結
總結startPausingLocked流程,如圖6-16所示。
:-: 
圖6-16 startPausingActivity流程總結
圖6-16比較簡單,讀者最好結合代碼再把流程走一遍,以加深理解。
9. startActivity總結
Activity的啟動就介紹到這里。這一路分析下來,相信讀者也和筆者一樣覺得此行絕不輕松。先回顧一下此次旅程:
- 行程的起點是am。am是Android中很重要的程序,讀者務必要掌握它的用法。我們利用am start命令,發起本次目標Activity的啟動請求。
- 接下來進入ActivityManagerService和ActivityStack這兩個核心類。對于啟動Activity來說,這段行程又可分細分為兩個階段:第一階段的主要工作就是根據啟動模式和啟動標志找到或創建ActivityRecord及對應的TaskRecord;第二階段工作就是處理Activity啟動或切換相關的工作。
- 首先討論了AMS直接創建目標進程并運行Activity的流程,其中涉及目標進程的創建,在目標進程中Android運行環境的初始化,目標Activity的創建以及觸發onCreate、onStart及onResume等其生命周期中重要函數調用等相關知識點。
- 接著又討論了AMS先pause當前Activity,然后再創建目標進程并運行Activity的流程。其中牽扯到兩個應用進程和AMS的交互,其難度之大可見一斑。
讀者在閱讀本節時,務必要區分此旅程中兩個階段工作的重點:其一是找到合適的ActivityRecord和TaskRecord;其二是調度相關進程進行Activity切換。在SDK文檔中,介紹最為詳細的是第一階段中系統的處理策略,例如啟動模式、啟動標志的作用等。第二階段工作其實是與Android組件調度相關的工作。SDK文檔只是針對單個Activity進行生命周期方面的介紹。
坦誠地說,這次旅程略過不少邏輯情況。原因有二,一方面受限于精力和篇幅,另方面是作為調度核心類,和AMS相關的代碼及處理邏輯非常復雜,而且其間還夾雜了與WMS的交互邏輯,使復雜度更甚。再者,筆者個人感覺這部分代碼絕談不上高效、嚴謹和美觀,甚至有些丑陋(在分析它們的過程中,遠沒有研究Audio、Surface時那種暢快淋漓的感覺)。
此處列出幾個供讀者深入研究的點:
- 各種啟動模式、啟動標志的處理流程。
- Configuration發生變化時Activity的處理,以及在Activity中對狀態保存及恢復的處理流程。
- Activity生命周期各個階段的轉換及相關處理。Android 2.3以后新增的與Fragment的生命周期相關的轉換及處理。
>[info]**建議**:在研究代碼前,先仔細閱讀SDK文檔相關內容,以獲取必要的感性認識,否則直接看代碼很容易迷失方向。
[^①]:關于Zygote的工作原理,請讀者閱讀卷I第4章“深入理解Zygote”
- 前言
- 第1章 搭建Android源碼工作環境
- 1.1 Android系統架構
- 1.2 搭建開發環境
- 1.2.1 下載源碼
- 1.2.2 編譯源碼
- 1.2.3 利用Eclipse調試system_process
- 1.3 本章小結
- 第2章 深入理解Java Binder和MessageQueue
- 2.1 概述
- 2.2 Java層中的Binder架構分析
- 2.2.1 Binder架構總覽
- 2.2.2 初始化Java層Binder框架
- 2.2.3 addService實例分析
- 2.2.4 Java層Binder架構總結
- 2.3 心系兩界的MessageQueue
- 2.3.1 MessageQueue的創建
- 2.3.2 提取消息
- 2.3.3 nativePollOnce函數分析
- 2.3.4 MessageQueue總結
- 2.4 本章小結
- 第3章 深入理解SystemServer
- 3.1 概述
- 3.2 SystemServer分析
- 3.2.1 main函數分析
- 3.2.2 Service群英會
- 3.3 EntropyService分析
- 3.4 DropBoxManagerService分析
- 3.4.1 DBMS構造函數分析
- 3.4.2 dropbox日志文件的添加
- 3.4.3 DBMS和settings數據庫
- 3.5 DiskStatsService和DeviceStorageMonitorService分析
- 3.5.1 DiskStatsService分析
- 3.5.2 DeviceStorageManagerService分析
- 3.6 SamplingProfilerService分析
- 3.6.1 SamplingProfilerService構造函數分析
- 3.6.2 SamplingProfilerIntegration分析
- 3.7 ClipboardService分析
- 3.7.1 復制數據到剪貼板
- 3.7.2 從剪切板粘貼數據
- 3.7.3 CBS中的權限管理
- 3.8 本章小結
- 第4章 深入理解PackageManagerService
- 4.1 概述
- 4.2 初識PackageManagerService
- 4.3 PKMS的main函數分析
- 4.3.1 構造函數分析之前期準備工作
- 4.3.2 構造函數分析之掃描Package
- 4.3.3 構造函數分析之掃尾工作
- 4.3.4 PKMS構造函數總結
- 4.4 APK Installation分析
- 4.4.1 adb install分析
- 4.4.2 pm分析
- 4.4.3 installPackageWithVerification函數分析
- 4.4.4 APK 安裝流程總結
- 4.4.5 Verification介紹
- 4.5 queryIntentActivities分析
- 4.5.1 Intent及IntentFilter介紹
- 4.5.2 Activity信息的管理
- 4.5.3 Intent 匹配查詢分析
- 4.5.4 queryIntentActivities總結
- 4.6 installd及UserManager介紹
- 4.6.1 installd介紹
- 4.6.2 UserManager介紹
- 4.7 本章學習指導
- 4.8 本章小結
- 第5章 深入理解PowerManagerService
- 5.1 概述
- 5.2 初識PowerManagerService
- 5.2.1 PMS構造函數分析
- 5.2.2 init分析
- 5.2.3 systemReady分析
- 5.2.4 BootComplete處理
- 5.2.5 初識PowerManagerService總結
- 5.3 PMS WakeLock分析
- 5.3.1 WakeLock客戶端分析
- 5.3.2 PMS acquireWakeLock分析
- 5.3.3 Power類及LightService類介紹
- 5.3.4 WakeLock總結
- 5.4 userActivity及Power按鍵處理分析
- 5.4.1 userActivity分析
- 5.4.2 Power按鍵處理分析
- 5.5 BatteryService及BatteryStatsService分析
- 5.5.1 BatteryService分析
- 5.5.2 BatteryStatsService分析
- 5.5.3 BatteryService及BatteryStatsService總結
- 5.6 本章學習指導
- 5.7 本章小結
- 第6章 深入理解ActivityManagerService
- 6.1 概述
- 6.2 初識ActivityManagerService
- 6.2.1 ActivityManagerService的main函數分析
- 6.2.2 AMS的 setSystemProcess分析
- 6.2.3 AMS的 installSystemProviders函數分析
- 6.2.4 AMS的 systemReady分析
- 6.2.5 初識ActivityManagerService總結
- 6.3 startActivity分析
- 6.3.1 從am說起
- 6.3.2 AMS的startActivityAndWait函數分析
- 6.3.3 startActivityLocked分析
- 6.4 Broadcast和BroadcastReceiver分析
- 6.4.1 registerReceiver流程分析
- 6.4.2 sendBroadcast流程分析
- 6.4.3 BROADCAST_INTENT_MSG消息處理函數
- 6.4.4 應用進程處理廣播分析
- 6.4.5 廣播處理總結
- 6.5 startService之按圖索驥
- 6.5.1 Service知識介紹
- 6.5.2 startService流程圖
- 6.6 AMS中的進程管理
- 6.6.1 Linux進程管理介紹
- 6.6.2 關于Android中的進程管理的介紹
- 6.6.3 AMS進程管理函數分析
- 6.6.4 AMS進程管理總結
- 6.7 App的 Crash處理
- 6.7.1 應用進程的Crash處理
- 6.7.2 AMS的handleApplicationCrash分析
- 6.7.3 AppDeathRecipient binderDied分析
- 6.7.4 App的Crash處理總結
- 6.8 本章學習指導
- 6.9 本章小結
- 第7章 深入理解ContentProvider
- 7.1 概述
- 7.2 MediaProvider的啟動及創建
- 7.2.1 Context的getContentResolver函數分析
- 7.2.2 MediaStore.Image.Media的query函數分析
- 7.2.3 MediaProvider的啟動及創建總結
- 7.3 SQLite創建數據庫分析
- 7.3.1 SQLite及SQLiteDatabase家族
- 7.3.2 MediaProvider創建數據庫分析
- 7.3.3 SQLiteDatabase創建數據庫的分析總結
- 7.4 Cursor 的query函數的實現分析
- 7.4.1 提取query關鍵點
- 7.4.2 MediaProvider 的query分析
- 7.4.3 query關鍵點分析
- 7.4.4 Cursor query實現分析總結
- 7.5 Cursor close函數實現分析
- 7.5.1 客戶端close的分析
- 7.5.2 服務端close的分析
- 7.5.3 finalize函數分析
- 7.5.4 Cursor close函數總結
- 7.6 ContentResolver openAssetFileDescriptor函數分析
- 7.6.1 openAssetFileDescriptor之客戶端調用分析
- 7.6.2 ContentProvider的 openTypedAssetFile函數分析
- 7.6.3 跨進程傳遞文件描述符的探討
- 7.6.4 openAssetFileDescriptor函數分析總結
- 7.7 本章學習指導
- 7.8 本章小結
- 第8章 深入理解ContentService和AccountManagerService
- 8.1 概述
- 8.2 數據更新通知機制分析
- 8.2.1 初識ContentService
- 8.2.2 ContentResovler 的registerContentObserver分析
- 8.2.3 ContentResolver的 notifyChange分析
- 8.2.4 數據更新通知機制總結和深入探討
- 8.3 AccountManagerService分析
- 8.3.1 初識AccountManagerService
- 8.3.2 AccountManager addAccount分析
- 8.3.3 AccountManagerService的分析總結
- 8.4 數據同步管理SyncManager分析
- 8.4.1 初識SyncManager
- 8.4.2 ContentResolver 的requestSync分析
- 8.4.3 數據同步管理SyncManager分析總結
- 8.5 本章學習指導
- 8.6 本章小結