android N程序啟動流程(二)(上一個activity的暫停、程序啟動、綁定程序與建立application)
第二部分将分為:上一個activity的暫停、程序啟動、綁定程序與建立application
5. 上一個activity的暫停

圖5.1 上一個activity的暫停
接着章節3.6的startActivityUnchecked中會調用最後有調用resumeFocusedStackTopActivityLocked,我們接下去從這裡開始講解。
5.1 resumeFocusedStackTopActivityLocked(ActivityStackSupervisor.java)
resumeFocusedStackTopActivityLocked恢複目前focus的堆棧stack中的頂端活動對象top activity
1) 上面章節3.6中setTaskFromReuseOrCreateNewTask->computeStackFocus->mSupervisor.getStack已經建立了mTargetStack,并将其添加到ActivityDisplay的mStack中去。
2) 章節3.6中moveToFront的insertTaskAtTop中也設定了需要啟動的應用如test2.com.myapplication成為堆棧頂端Top的程序
3) 章節4.2中setFocusStackUnchecked也設定了mTargetStack為test2
//上面章節3.6中setTaskFromReuseOrCreateNewTask已經建立了mTargetStack,
//章節3.6中moveToFront的insertTaskAtTop中也設定了需要啟動的應用如test2.com.myapplication
//成為堆棧頂端Top的程序
boolean resumeFocusedStackTopActivityLocked(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
if (targetStack != null && isFocusedStack(targetStack)) {
//targetStack不為null,而且isFocusedStack也是test2,故此處是會進來的
return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
//...
}
5.2 resumeTopActivityUncheckedLocked(ActivityStack.java)
resumeFocusedStackTopActivityLocked恢複目前focus堆棧stack中的頂端活動對象
1) 此處的stack this對象是test2上一章節5.1中說的mTargetStack
2) 此時是第一次看到resumeTopActivityInnerLocked,故是第一次進入,傳遞的prev是test2.com.myapplication我們先看第一次進入該函數的處理邏輯(第二次的請忽略先)
3) 此處邏輯依次是resumeTopActivityUncheckedLocked->resumeTopActivityInnerLocked->pauseBackStacks
4) 第一次進入由于在pauseBackStacks傳回有需要pause的應用,故pausing==true,pauseBackStacks做完不久就直接傳回了
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
//....
result = resumeTopActivityInnerLocked(prev, options);
//....
}
//第一次進來的時候prev是test2.com.myapplication(是以會先pause上一個應用如com.android.launcher);
//第二次進來是prev是com.android.launcher,此時launcher已經pause了,
//會進入下一個應用的resume流程(如test2.com.myapplication)
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
//...
//第一次進來topRunningActivityLocked是test2,第二次進來也是test2,
//此處是在moveActivityStackToFront中已經設定過了
final ActivityRecord next = topRunningActivityLocked();
//...
//此處allPausedActivitiesComplete是true,不會進入這裡,
//說明之前已經沒有需要pause的應用(第一次進來mPausingActivity還沒有設定過==null)
//或者pause完成(第二次進來)
if (!mStackSupervisor.allPausedActivitiesComplete()) {
…
return false;
}
//...
//是否有設定标志位在pausing的時候resume,預設沒有設定都是false
final boolean dontWaitForPause = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != ;
//此處判斷是否有需要pasue的程序(是所有stack而不僅僅是目前stack),
//第一次進來會pause launcher(launcher的堆棧中有mResumedActivity,
//但是章節4.2已經将焦點切換到test2)故回報pausing==true,第二次直接傳回pausing==false
boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);
//mResumedActivity一直都是null(由于目前mTargetStack是新new出來的給程序test2使用),
//隻有在test2 resume之後才會設定,如在minimalResumeActivityLocked之後設定,故不會走下面的邏輯
if (mResumedActivity != null) {
//...
}
//第一次走的pausing是true(代表有需要暫停的應用,如launcher),第二次pausing是false
if (pausing) {
//...
//第一次進來到這裡就結束了
return true;
//此處一般都是不走的mResumedActivity == null,第二次pausing是false,
//但是還是有activity繼續resume(allResumedActivitiesComplete傳回false)
} else if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
mStackSupervisor.allResumedActivitiesComplete()) {
...
return true;
}
//第二次時會進來這裡prev != next,此處next代表test2.com.myapplication,
//prev代表com.android.launcher
if (prev != null && prev != next) {
if (!mStackSupervisor.mWaitingVisibleActivities.contains(prev)
&& next != null && !next.nowVisible) {
//等待prev的界面launcher隐藏,此處在mStackSupervisor的
//processStoppingActivitiesLocked時才會remove
mStackSupervisor.mWaitingVisibleActivities.add(prev);
} else {
//...
}
//...
//第二次進來時prev == com.android.launcher
if (prev != null) {
//launcher是沒有finishing的,不進入這裡
if (prev.finishing) {
//...
//準備resume test2.com.myapplication時prev代表com.android.launcher,會進來這裡
} else {
//prev.task不等于next.task,mLaunchTaskBehind是false,
//WMS中傳輸類型是TRANSIT_TASK_OPEN
mWindowManager.prepareAppTransition(prev.task == next.task
? TRANSIT_ACTIVITY_OPEN
: next.mLaunchTaskBehind
? TRANSIT_TASK_OPEN_BEHIND
: TRANSIT_TASK_OPEN, false);
}
} else {
//...
}
//...
//此處next(test2.com.myapplication)程序都還沒有起來,不會進入這裡
if (next.app != null && next.app.thread != null) {
//...
//next(test2.com.myapplication)進入的是else
} else {
//第一次啟動hasBeenLaunched肯定是false,是以會進入此處
if (!next.hasBeenLaunched) {
next.hasBeenLaunched = true;
} else {
...
}
//這裡才是真正啟動test2程序的地方
mStackSupervisor.startSpecificActivityLocked(next, true, true);
}
//...
}
5.3 pauseBackStacks(ActivityStackSupervisor.java)
pauseBackStacks周遊ActivityDisplay顯示裝置中的所有棧,當循環到luancher的時候,由于launcher已經不是focus的stack棧,但是它的mResumedActivity仍然存在,代表這個activity需要進行pause暫停的操作。
boolean pauseBackStacks(boolean userLeaving, boolean resuming, boolean dontWait) {
//...
//周遊stacks目前顯示裝置的所有堆棧
final ActivityStack stack = stacks.get(stackNdx);
//stack是launcher,isFocusedStack是false,mResumedActivity是launcher不等于null
if (!isFocusedStack(stack) && stack.mResumedActivity != null) {
//launcher的stack進行pause的操作,注意resuming是true,dontWait是false,
//userLeaving是true,在章節3.6 startActivityUnchecked->setInitialState中設定
someActivityPaused |= stack.startPausingLocked(userLeaving, false, resuming,
dontWait);
//...
}
5.4 startPausingLocked(ActivityStack.java)
1) startPausingLocked這個函數是啟動應用暫停pause(如此處的是上一個應用launcher),設定目前狀态為pausing
2) 進入ActivityThread處理暫停任務之前會在eventlog中輸出am_pause_activity的資訊,表示将要開始該應用的暫停了
3) 不過最重要的函數還是ActivityThread的schedulePauseActivity,該函數會處理pause任務
//userLeaving==true, uiSleeping==false, resuming==true, dontWait==false
final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,
boolean dontWait) {
//第一次進來mPausingActivity是null,應用沒有暫停就沒有所謂的mPausingActivity
if (mPausingActivity != null) {
//...
}
//mResumedActivity是目前resume的activity,此處是launcher
ActivityRecord prev = mResumedActivity;
//注意此處pause之後将設定mResumedActivity==null,代表沒有該Stack沒有resume的activity了
mResumedActivity = null;
//launcher設定為正在pause的程序
mPausingActivity = prev;
//設定上一個暫停的應用
mLastPausedActivity = prev;
//标定該程序在PAUSING狀态
prev.state = ActivityState.PAUSING;
//此處next是test2,章節4.2的insertTaskAtTop已經設定過
final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();
//pause應用會觸發cpu狀态更新,可以使用adb shell dumpsys cpuinfo查詢
mService.updateCpuStats();
//prev是launcher,裡面的app和thread都是已經建立的,所有此處會進入
if (prev.app != null && prev.app.thread != null) {
try {
//event log中的am_pause_activity,代表應用的pause開始
EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
prev.userId, System.identityHashCode(prev),
prev.shortComponentName);
//cpu前背景切換,用于耗電統計
mService.updateUsageStats(prev, false);
//ActivityThread裡面的方法是handle(異步),此處才是activity的真正的pause執行的地方
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
userLeaving, prev.configChangeFlags, dontWait);
//...
//mPausingActivity就是launcher,是以會進來此處。
if (mPausingActivity != null) {
//uiSleeping==false
if (!uiSleeping) {
//應用的pause的時候,會暫停接收輸入事件,此時系統觸摸了不回報給上層
prev.pauseKeyDispatchingLocked();
}
//dontWait==false,章節5.2中設定dontWaitForPause
if (dontWait) {
//隻有當dontWait是true的時候才會走這裡,就是不等待pause完成
completePauseLocked(false);
return false;
} else {
//launcher的最後onpause會走到這裡來
Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
msg.obj = prev;
prev.pauseTime = SystemClock.uptimeMillis();
//設定pause的逾時時間為500ms
mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
//傳回ture,代表有響應的activity正在pausing,
//故在章節5.2 resumeTopActivityInnerLocked運作完該函數後不久就傳回了
return true;
}
} else {
//...
}
ps:上面也看到了pause的時候會限制輸入事件,如果應用一直重新開機又挂掉又重新開機,此時如果不停調用pause/finish的話會限制輸入事件的分發pauseKeyDispatchingLocked,當然這種情況隻是極端情況,一般不會出現
5.5 schedulePauseActivity(ActivityThread.java)
1) schedulePauseActivity這個是通過handler(一直想吐槽這個hander也類名也太簡潔了的點吧,一個”H”就搞定)在UI主線程裡面做的事情
2) 主要流程是schedulePauseActivity->PAUSE_ACTIVITY->handlePauseActivity->performPauseActivity->performPauseActivityIfNeeded
3) 我們主要關注performPauseActivityIfNeeded目前activity暫停(這部分本章節講解)、activityPaused通知AMS上一個activity暫停完成(這部分下一章裡講解)。
//ActivityThread給外部提供的接口,pause暫停是通過應用的主線程進行處理
public final void schedulePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport) {
int seq = getLifecycleSeq();
//...
//finished等于false,走的是PAUSE_ACTIVITY,userLeaving==true,dontReport==dontWait==false
sendMessage(
finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
token,
(userLeaving ? USER_LEAVING : ) | (dontReport ? DONT_REPORT : ),
configChanges,
seq);
}
//handler傳遞,調用的是handlePauseActivity
case PAUSE_ACTIVITY: {
//...
//進入pause的處理
handlePauseActivity((IBinder) args.arg1, false,
(args.argi1 & USER_LEAVING) != , args.argi2,
(args.argi1 & DONT_REPORT) != , args.argi3);
//...
} break;
//finished是false,userLeaving==true,dontReport==false
private void handlePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport, int seq) {
ActivityClientRecord r = mActivities.get(token);
...
if (r != null) {
//userLeaving一般都是true
if (userLeaving) {
//會進入此處,會調用activity.performUserLeaving,當離開使用者可視的時候會調用
performUserLeavingActivity(r);
}
//...
//此處是pause上一個應用launcher,isPreHoneycomb是android3.0之前用的,此處是false
performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity");
//dontReport一般沒有設定都是false,故一般都是進入此處的
if (!dontReport) {
try {
//通知AMS上一個應用完成pause了,這裡接下去就會resume下一個應用(先啟動程序),
//下一章會講到
ActivityManagerNative.getDefault().activityPaused(token);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
mSomeActivitiesChanged = true;
}
}
final Bundle performPauseActivity(ActivityClientRecord r, boolean finished,
boolean saveState, String reason) {
//saveState是false,不跑這裡
if (!r.activity.mFinished && saveState) {
callCallActivityOnSaveInstanceState(r);
}
//這裡才是pause activity的地方
performPauseActivityIfNeeded(r, reason);
// 将目前pause的應用的OnActivityPausedListener暫停監聽去除
ArrayList<OnActivityPausedListener> listeners;
synchronized (mOnPauseListeners) {
listeners = mOnPauseListeners.remove(r.activity);
}
//...
for (int i = ; i < size; i++) {
//此處是調用注冊了該activity thread的監聽onPaused的回調,
//如NfcAdapter.java中的ActivityThread.currentActivityThread()
//.registerOnActivityPausedListener(activity,mForegroundDispatchListener);
listeners.get(i).onPaused(r.activity);
}
//...
}
5.6 performPauseActivityIfNeeded(ActivityThread.java)
1) 通過代理類Instrumentation調用callActivityOnPause,其調用的是activity的performPause(分别會調用mFragments.dispatchPause、activity的onPause,application的ActivityLifecycleCallback生命周期回調方法onActivityPaused)
2) OnPause調用完成後會在event log中寫入am_on_paused_called,代表activity的OnPause已經完成(如果你使用onpause有問題,可以從am_pause_activity到am_on_paused_called之間所花費的時間做初步判斷)
3) 注意OnPause完成之後paused會指派為true,代表目前是暫停狀态
private void performPauseActivityIfNeeded(ActivityClientRecord r, String reason) {
if (r.paused) {
//如果之前paused==true了就直接傳回,activitythread建立設定成false,
//oncreate将設定成ture,onresume将設定成false
//上一個activity的上一個狀态是onresume,正在pause,故此處是paused==false
return;
}
try {
//這裡解釋一下mCalled,這個值是用來判斷是否有調用activity生命周期的函數
r.activity.mCalled = false;
//這就就是具體調用activity的performPause的地方
//(包括mFragments.dispatchPause、activity的onPause,
//application的ActivityLifecycleCallback生命周期回調方法onActivityPaused),
//運作完之後mCalled會設定成true
mInstrumentation.callActivityOnPause(r.activity);
//寫event log,am_on_paused_called,說明pause已經調用
EventLog.writeEvent(LOG_AM_ON_PAUSE_CALLED, UserHandle.myUserId(),
r.activity.getComponentName().getClassName(), reason);
//...
//運作了之後設定标緻位paused==true
r.paused = true;
}
到目前為止基本上把上一個activity的OnPause流程講解完了。
6. 程序啟動(一)am_proc_start
講了一大堆,是不是發現我們需要啟動的程序test2怎麼還沒到呢,流程有點長,目前android的預設架構就是這樣,大家耐心的繼續看下去,我們這一章節就開始講到程序啟動(這部分應該很多文章都有提到,了解的同學可以不必細看)。
其實這些流程隻是學習作用,對我們了解android架構有一定幫助,解決問題(僅針對那些代碼不規範自己改出來的問題)時有幫助,不過這些都不是關注的重點,我們關注的是如何優化整個流程,如果沒有明确這個目的,對我們來說是沒有很大提升的。路漫漫其修遠,我們先把流程梳理清楚,一步步來…
圖6.1 程序啟動(一)
6.1 activityPaused(ActivityManagerService.java)
在章節5.5中的
ActivityManagerNative.getDefault().activityPaused(token)
,這個函數的意思是告訴AMS,上一個應用已經完成OnPause了,接下去的工作可以繼續下去。
public final void activityPaused(IBinder token) {
//...
//調用的是ActivityStack的activityPausedLocked,第二個參數timeout==false
stack.activityPausedLocked(token, false);
//...
}
其中token是上一個應用的Ibinder對象,我們認為是launcher就行了
6.2 activityPausedLocked(ActivityStack.java)
1) 通知launcher自身Stack棧中的activityPausedLocked,目前已經完成pause暫停操作了,可以将之前章節5.4中說的PAUSE_TIMEOUT_MSG逾時去掉。
2) mPausingActivity也是在章節5.4開始暫停的時候設定的,如果發現真正暫停的應用和完成暫停的應用是一個,代表暫停完成,調用completePauseLocked,并傳遞resumeNext==true,代表需要resume下一個應用
//AMS調用的timeout==false
final void activityPausedLocked(IBinder token, boolean timeout) {
//代表該task仍在堆棧中,此時launcher是launcher的paused
final ActivityRecord r = isInStackLocked(token);
if (r != null) {
//pause已經完成,不需要PAUSE_TIMEOUT_MSG了
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
//之前在startPausingLocked的時候設定了目前pause的應用,
//這個時候AMS傳回代表pause成功,會進入這裡
if (mPausingActivity == r) {
//pause成功,傳遞的參數是resumeNext==true,代表需要resume下一個應用
completePauseLocked(true);
return;
} else {
...
}
6.3 completePauseLocked(true)
1) mWaitingVisibleActivities這裡代表的是需要隐藏的可視界面,到目前為止我們沒有設定過,這個是在第二次進入章節5.2 resumeTopActivityInnerLocked的時候才會設定。(準備resume恢複下一個應用test2,上一個應用launcher就會放入等待隐藏的清單mWaitingVisibleActivities中)
2) 非睡眠或者關機狀态的時候會進入下一個activity的resume操作resumeFocusedStackTopActivityLocked
3) 最後ensureActivitiesVisibleLocked(ActivityStackSupervisor.java/ActivityStack.java)會更新界面相關操作,屬于WMS範疇,本文不過多涉及
{
//啟動程序後會更新界面,此處僅僅把流程列出來,由于這篇文章本身太長了,不想在額外增加内容
ensureActivitiesVisibleLocked
->ensureActivityConfigurationLocked
->makeVisibleAndRestartIfNeeded->startSpecificActivityLocked()
->screenshotActivitiesLocked
->makeInvisible->addToStopping->scheduleIdleLocked
}
private void completePauseLocked(boolean resumeNext) {
//prev,mPausingActivity是launcher
ActivityRecord prev = mPausingActivity;
//prev是不等于null的會進來這裡
if (prev != null) {
//state在startPausingLocked時設定了ActivityState.PAUSING,
//是以一般情況wasStopping都是false
final boolean wasStopping = prev.state == ActivityState.STOPPING;
//重新設定标志位是ActivityState.PAUSED,這個是已經暫停的狀态
prev.state = ActivityState.PAUSED;
//一般情況launcher啟動應用,prev.finishing==false,故不會進入這裡面
if (prev.finishing) {
//...
//prev.app是launcher
} else if (prev.app != null) {
//pause com.android.launcher時,此處會進來,prev就是com.android.launcher,
//wasStopping==false,visible==true
//第一次進來時mWaitingVisibleActivities還沒有prev(resumeTopActivityInnerLocked
//第二次運作是才會設定),故不會進來這個
if (mStackSupervisor.mWaitingVisibleActivities.remove(prev)) {
//...
}
//這個是在pause之後重新啟動,一般都是false
if (prev.deferRelaunchUntilPaused) {
//...
//wasStopping==false,也不走這裡
} else if (wasStopping) {
//...
//由于visible==true,也不是在睡眠狀态,這裡也不會進來
} else if ((!prev.visible && !hasVisibleBehindActivity())
|| mService.isSleepingOrShuttingDownLocked()) {
//...
}
} else {
//這裡實在app在onpause過程中died掉才會進入,正常不會運作
prev = null;
}
if (prev != null) {
//如果界面是凍屏的話,由于界面不再可見,将移除凍屏狀态
prev.stopFreezingScreenLocked(true /*force*/);
}
//mPausingActivity設定為null,此時pause已經全部完成
mPausingActivity = null;
}
//上面都是AMS進來的activityPausedLocked,resumeNext == true
if (resumeNext) {
//之前的moveActivityStackToFront中有設定過focus stack為test2
final ActivityStack topStack = mStackSupervisor.getFocusedStack();
//非睡眠或者關機會進入這裡
if (!mService.isSleepingOrShuttingDownLocked()) {
//一般進入這裡,會resume 下一個應用(next),
//同步的,執行了Process.start之後才會繼續往下跑
mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
} else {
...
}
if (prev != null) {
//重新恢複接收輸入事件
prev.resumeKeyDispatchingLocked();
//如果是在使用電池
if (prev.app != null && prev.cpuTimeAtResume >
&& mService.mBatteryStatsService.isOnBattery()) {
//cpuTimeAtResume是在activity resume的時候設定的,
//代表從resume到pause的時間,将作為前台運作時間
long diff = mService.mProcessCpuTracker.getCpuTimeForPid(prev.app.pid)
- prev.cpuTimeAtResume;
//...
//addForegroundTimeLocked這個是電量估算的時候用的,判斷該activity前台運作的時常
if (ps != null) {
ps.addForegroundTimeLocked(diff);
//...
}
//目前已經是onpause暫停了,清空進入resume的時間
prev.cpuTimeAtResume = ;
}
//有界面可視的時候mAppVisibilitiesChangedSinceLastPause==true(setVisible時設定),
//是以這裡會進來
if (mStackSupervisor.mAppVisibilitiesChangedSinceLastPause) {
//...
//launcher已經pause,設定mAppVisibilitiesChangedSinceLastPause==false
mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = false;
}
//最後是更新顯示界面,這裡是第一次調用ensureActivitiesVisibleLocked,
//周遊所有stack的ensureActivitiesVisibleLocked
mStackSupervisor.ensureActivitiesVisibleLocked(null, , !PRESERVE_WINDOWS);
}
6.4 resumeFocusedStackTopActivityLocked/startSpecificActivityLocked(ActivityStackSupervisor.java)
resumeFocusedStackTopActivityLocked在章節5.1-5.2已經看過,此處傳遞的targetStack是test2,pre是launcher,resumeFocusedStackTopActivityLocked(ActivityStackSupervisor.java) -> resumeTopActivityUncheckedLocked(ActivityStack.java) -> resumeTopActivityInnerLocked -> startSpecificActivityLocked(ActivityStackSupervisor.java),啟動的是next==test2
這裡就不翻回去講了,接下去講
startSpecificActivityLocked(ActivityStackSupervisor.java)
這個啟動應用的函數(注意此處是第一次進入,章節6.3提到的那一次是第二次進入,是在之後)
//r==test2,andResume==true,checkConfig==true
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
//...
//當程序都未啟動時不走這裡,thread肯定是null,熱啟動相關邏輯本次不讨論
if (app != null && app.thread != null) {
...
}
//AMS中去啟動程序
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, ,
"activity", r.intent.getComponent(), false, false, true);
}
6.5 startProcessLocked(ActivityManagerService.java)
重要看到startProcessLocked啟動程序相關名字,這個是AMS的啟動程序的api。
先關注第一次進入的邏輯:
1) 建立一個程序對象的執行個體new ProcessRecord,該對象可以代表一個程序
2) 判斷應用是32位還是64位的,用于虛拟機參數配置
3) Process.start程序啟動
4) event log寫入am_proc_start,代表程序已經啟動,這句話出來的時候應用程序已經建立
//9個參數(r.processName==test2, r.info.applicationInfo, true, 0,
//"activity", r.intent.getComponent(), false, false, true)
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName, boolean allowWhileBooting,
boolean isolated, boolean keepIfLarge) {
//注意此處entryPoint==null
return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
hostingName, allowWhileBooting, isolated, /* isolatedUid */, keepIfLarge,
null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
null /* crashHandler */);
}
//14個參數,建立ProcessRecord
final ProcessRecord startProcessLocked(String processName, ...) {
long startTime = SystemClock.elapsedRealtime();
ProcessRecord app;
//isolated(孤立應用)是false,knownToBeDead是true
if (!isolated) {
//第一次進來app肯定是null
app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
//...
//設定了背景運作,桌面啟動應用一般都不會走這裡
if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != ) {
...
} else {
//重新計算崩潰次數(crash大于等于2次服務将不會再啟動)
mAppErrors.resetProcessCrashTimeLocked(info);
//...
}
}
//這個是用來設定啟動程序時cpu的政策,可以加快app啟動速度
//預設沒有用到,需要設定USE_SCHED_BOOST才會生效
nativeMigrateToBoost();
//3s鐘後會關閉啟動程序的cpu政策,同樣此處預設沒有用到
mHandler.sendMessageDelayed(msg, APP_BOOST_MESSAGE_DELAY);
//第一次進入時沒有啟動過app/thread是null,pid是沒有的.
//第二次進來時此處app是有了,pid也生成了,但是thread還沒有
//第一次沒啟動不走這裡,第二次會進來
if (app != null && app.pid > ) {
//knownToBeDead是true,第二次進來app.thread還是null,故會進來,
//第二次是從章節6.3中ensureActivitiesVisibleLocked調用過來的
if ((!knownToBeDead && !app.killed) || app.thread == null) {
//第二次程序已經建立了,直接傳回
//...
return app;
}
//...
}
//...
//第一次走這裡,app是null
if (app == null) {
//這個是google的,用于調試卡頓的,不過除了特别有問題一般情況不會出現問題,
//50ms去掉系統或許更快,如果是給使用者的穩定版本可以考慮把這段調試代碼删除
checkTime(startTime, "startProcess: creating new process record");
//此處是new ProcessRecord
app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
//...
//建立ProcessRecord完成,該監控操作(newProcessRecordLocked)完成
checkTime(startTime, "startProcess: done creating new process record");
}
//監控程序啟動的時常是否逾時
checkTime(startTime, "startProcess: stepping in to startProcess");
//這裡才是真正的啟動程序的地方
startProcessLocked(
app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
checkTime(startTime, "startProcess: done starting proc!");
//如果有pid産生代表程序建立完成
return (app.pid != ) ? app : null;
}
//真正啟動程序的地方
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
//...
if (app.pid > && app.pid != MY_PID) {//第一次啟動app.pid == -1,不走這裡
...
}
//...
updateCpuStats();//啟動程序也會更新CPU狀态
try {
try {
//用于檢測是否可以啟動,如:是否安裝,是否正在凍屏等
AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);
}
//isolated初始值是false
if (!app.isolated) {
//...
//傳回應用使用者組的gid,如果是uid不一樣,同一個應用該值也會不一樣
permGids = pm.getPackageGids(app.info.packageName,
MATCH_DEBUG_TRIAGED_MISSING, app.userId);
MountServiceInternal mountServiceInternal = LocalServices.getService(
MountServiceInternal.class);
//擷取應用讀寫外部存儲的權限
//如果是孤立應用(uid是99000-99999)将傳回MOUNT_EXTERNAL_NONE;
//能讀傳回MOUNT_EXTERNAL_READ,能寫傳回MOUNT_EXTERNAL_WRITE
mountExternal = mountServiceInternal.getExternalStorageMountMode(uid,
app.info.packageName);
//...
}
//...
//android:multiArch="true"代表所有架構都支援,一般都不設定,
//一般應用庫檔案需要判斷是否32位還算64位,判斷方法使用
//com_android_internal_content_NativeLibraryHelper.cpp的findSupportedAbi
//requiredAbi就是為了相容32位&64位系統設計的
String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;
if (requiredAbi == null) {
//此處如果應用沒有設定實在32位還是64位運作的化,
//預設使用屬性值ro.product.cpu.abilist的第一個值arm64-v8a(64bit),
//armeabi-v7a(32bit),armeabi(32bit)
requiredAbi = Build.SUPPORTED_ABIS[];
}
String instructionSet = null;
if (app.info.primaryCpuAbi != null) {
//通過應用的庫檔案擷取虛拟機要使用那種參數
instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi);
}
//上面傳遞的entryPoint==null,isActivityProcess==true
boolean isActivityProcess = (entryPoint == null);
//将ActivityThread作為應用預設的入口函數entryPoint
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
//此處才是調用Process.start啟動程序的地方
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);//此處才是調用Process.start啟動程序的地方
//此處就是event log中am_proc_start
EventLog.writeEvent(EventLogTags.AM_PROC_START,
UserHandle.getUserId(uid), startResult.pid, uid,
app.processName, hostingType,
hostingNameStr != null ? hostingNameStr : "");
//設定程序的pid
app.setPid(startResult.pid);
//一般usingWrapper==false
app.usingWrapper = startResult.usingWrapper;
//代表正在運作
app.removed = false;
app.killed = false;
//代表沒有給AMS殺死
app.killedByAm = false;
synchronized (mPidsSelfLocked) {
//process start之後就會有pid了,此處是test2.com.myapplication的pid會生成
//會将該pid放入AMS的pid清單中
this.mPidsSelfLocked.put(startResult.pid, app);
if (isActivityProcess) {//isActivityProcess==true
//10s沒有啟動将不再啟動,該app,Process.start虛拟機程序建立是同步的,
//但是attachApplicationLocked是異步的,在attachApplication的時候
//會remove這個逾時PROC_START_TIMEOUT_MSG
mHandler.sendMessageDelayed(msg, startResult.usingWrapper
? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
...
}
7. 程序啟動(二)Process.start
Process.start這個是建立程序通用的系統方法,代碼位置:
frameworks/base/core/java/android/os/Process.java。
接下去從這個開始,這裡面大家熟悉的内容可能更多。
圖7.1 程序啟動(二)
7.1 Process.start(Process.java)
我們注意傳遞的參數processClass是android.app.ActivityThread,niceName是processName,debugFlags一般都是等于0,mountExternal代表是否可讀寫外部存儲,targetSdkVersion是這個應用的targetSdkVersion,seInfo是簽名相關(預設是”default”),abi是這個應用要運作的cpu架構(32還是64位),instructionSet是指的是arm或者arm64,appDataDir一般指的是/data這個目錄,zygoteArgs==null。
後面這些參數都會有用到,對于了解流程有很大的幫助。
//processClass是android.app.ActivityThread,niceName是processName,
//debugFlags一般都是等于0,mountExternal代表是否可讀寫外部存儲,
//targetSdkVersion是這個應用的targetSdkVersion,seInfo是簽名相關(預設是”default”),
//abi是這個應用要運作的cpu架構(32還是64位),instructionSet是指的是arm或者arm64,
//appDataDir一般指的是/data這個目錄,zygoteArgs==null
public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String[] zygoteArgs) {
try {
//通過虛拟機來建立新的程序
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, zygoteArgs);
//...
}
7.2 startViaZygote-> zygoteSendArgsAndGetResult
1) startViaZygote通将參數全部轉化成Zygote的數組String
2) openZygoteSocketIfNeeded/zygoteSocket.connect建立Socket連結,并擷取輸入輸出流對象
3) zygoteSendArgsAndGetResult通過Socket與底層互動,傳遞相應的事件内容,并擷取傳回的結果
private static ProcessStartResult startViaZygote(final String processClass,
//...
ArrayList<String> argsForZygote = new ArrayList<String>();
//...添加虛拟機參數
//最後添加的是ActivityThread應用的入口類
argsForZygote.add(processClass);
//extraArgs==null,是以後面沒有參數了
if (extraArgs != null) {
for (String arg : extraArgs) {
argsForZygote.add(arg);
}
}
//注意openZygoteSocketIfNeeded是connect Socket,
//zygoteSendArgsAndGetResult是向Socket傳遞參數
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
try {
//ZYGOTE_SOCKET的名字是"zygote",連接配接socket
primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);
//...
}
public static ZygoteState connect(String socketAddress) throws IOException {
//...
try {
//這裡是connect的地方,會通知相應的連結對象
zygoteSocket.connect(new LocalSocketAddress(socketAddress,
LocalSocketAddress.Namespace.RESERVED));
//輸入流,是用來讀東西的,例如裝置有資料輸出,然後我們讀取
zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
//輸出流是用來寫東西的,例如寫東西然後輸出到什麼位置
zygoteWriter = new BufferedWriter(new OutputStreamWriter(
zygoteSocket.getOutputStream()), );
//...
}
private static ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, ArrayList<String> args)
throws ZygoteStartFailedEx {
try {
//...
//第一個先寫的是參數大小
writer.write(Integer.toString(args.size()));
writer.newLine();
for (int i = ; i < sz; i++) {
String arg = args.get(i);
//傳遞設定參數
writer.write(arg);
writer.newLine();
}
//清空輸出流,并寫入,運作完成之後代表寫入成功,此時Socket會接受到相應消息
writer.flush();
//...
//讀取傳回的pid資料
result.pid = inputStream.readInt();
//讀取傳回的usingWrapper資料
result.usingWrapper = inputStream.readBoolean();
...
}
7.3 ZygoteInit.main(ZygoteInit.java)
1) 開機運作app_process程序(init.zygote*.rc->app_process)->app_main.main->ZygoteInit.main,Zygote受精卵程序是由init程序建立,如下通過ps可知:init程序是Zygote64受精卵程序的父程序,而system_server是通過zygote64受精卵程序建立的。(pid是該程序的id,ppid是其父程序的id)
USER PID PPID VSIZE RSS WCHAN PC NAME
root SyS_epoll_ S /init
root poll_sched S zygote64 //此處代表是64bit的
system SyS_epoll_ S system_server
2) 擷取目前作業系統的32&64位架構abiList,這個在socket connect的時候用于
2) 注冊zygote的LocalServerSocket對象(Socket的服務端,可以給别人connect)
3) 啟動系統服務startSystemServer
4) 等待Socket消息的通知來執行相應的任務runSelectLoop
5) MethodAndArgsCaller的run方法
//開機運作app_process程序(init.zygote*.rc->app_process)->app_main.main->ZygoteInit.main
public static void main(String argv[]) {
//...
try {
//Socket的名字是zygote
String socketName = "zygote";
String abiList = null;
for (int i = ; i < argv.length; i++) {
//第一次進來會設定startSystemServer==true
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
} else if (argv[i].startsWith(ABI_LIST_ARG)) {
//讀的是系統屬性ro.product.cpu.abilist64或者ro.product.cpu.abilist32裡面的值
abiList = argv[i].substring(ABI_LIST_ARG.length());
//...
//android的Socket名字:ANDROID_SOCKET_ + zygote
registerZygoteSocket(socketName);
//event log中會出現boot_progress_preload_start
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
//重新加載Cache,Classes,Resources,OpenGL,SharedLibraries,
//TextResources,WebView,AndroidKeyStoreProvider
preload();
//event log中會出現boot_progress_preload_end
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
//...
//做GC,清除一些軟引用對象
gcAndFinalize();
//...
//在初始化時unmount根目錄"/storage"
Zygote.nativeUnmountStorageOnInit();
//允許zygote建立程序
ZygoteHooks.stopZygoteNoThreadCreation();
//如果需要啟動系統服務則進入這裡
if (startSystemServer) {
//啟動系統服務system_server,先後調用fork順序是init
//->zygote64(64位系統)->system_server,如果是系統程序的話,
//這裡是永遠不會傳回的startSystemServer->handleSystemServerProcess
//->RuntimeInit.zygoteInit->SystemServer.main/run->Looper.loop()
//->(pollInner/epoll_wait)Looper.cpp,
//這個除了Loop裡面調用mQueue.quit是不會退出的
startSystemServer(abiList, socketName);
}
//會跑下來的是zygote程序,zygote程序會一直在此運作
runSelectLoop(abiList);
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
//對于此處zygote frok的子程序會進入此處,抛出MethodAndArgsCaller異常,
//會執行run方法,其實是反射調用ActivityThread.main,這個後面會講到
caller.run();
//...
}
ps: Zygote程序是用來fork各個子程序的,如system_server就是其建立的,其中zygote64是所有64位程序的父程序,zygote是所有32位程序的父程序。
7.4 runSelectLoop
runSelectLoop循環等待Socket的資料回報,這裡寫的是Select的Loop,目前androidN使用的方法是Os.poll不再有1024個Socket的限制(androidL和之前的版本使用的是select方法),後續android版本更新的話可能使用epoll(目前上層的Looper、MessageQueue就是使用epoll)
1) 循環周遊等待Socket緩沖區有可讀的資料
2) Socket.connect時會建立新的ZygoteConnection
3) ZygoteConnection執行runOnce
4) 建立子程序後,子程序退出循環,父程序繼續等待下一個Socket資料
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
//...
// sServerSocket是AMS Process.java中的ZYGOTE_SOCKET連結的對象, 用來建立程序
//sServerSocket是LocalServerSocket,代表整個socket
//fds是所有zygote Socket相關的檔案描述符
fds.add(sServerSocket.getFileDescriptor());
//peers是ZygoteConnection對象,是zygote連結之後的對象
peers.add(null);
while (true) {
//...
//events代表等待的事件類型,POLLIN類型代表我們隻關心緩沖區是否有資料可讀
pollFds[i].events = (short) POLLIN;
//...
try {
//poll函數與select類似都是,可以監視多個描述符,-1代表永不逾時,
//輪詢一遍之後等待,當裝置驅動發生自身資源可讀寫後,會喚醒其等待隊列上睡眠的程序
Os.poll(pollFds, -);
}
//...
for (int i = pollFds.length - ; i >= ; --i) {
//revents域是檔案描述符的操作結果事件掩碼,POLLIN代表有資料可讀
if ((pollFds[i].revents & POLLIN) == ) {
continue;
}
//i==0是就是外部有建立socket的時候,如Socket.connect,
//這個時候Os.poll中LocalServerSocket會有資料傳回,
//此時LocalServerSocket會accept并建立新的ZygoteConnection
if (i == ) {
//建立新的受精卵的Socket連結ZygoteConnection
ZygoteConnection newPeer = acceptCommandPeer(abiList);
//添加到ZygoteConnection數組peers
peers.add(newPeer);
//添加到zygote Socket相關的檔案描述符數組中去
fds.add(newPeer.getFileDesciptor());
//非第一次運作時,如果之前建立的Socket連結對象ZygoteConnection有資料可以讀,
//如OutputStream(zygoteWriter就是輸出流)有寫入,那麼此處會有資料,
//進入runOnce函數。
} else {
//建立子程序會抛出MethodAndArgsCaller的異常,
//給ZygoteInit.main捕獲,然後運作ActivityThread的main函數,
//子程序抛出異常後退出該循環,但是Zygote父程序還算會繼續循環的
boolean done = peers.get(i).runOnce();
//建立子程序後,父程序也就是zygote程序才會進入這裡
//...
}
}
}
}
runSelectLoop函數就是在監聽Socket端是否有資料可以讀,如果有資料來了,那麼就是建立程序,這個Zygote程序主要作用就是建立程序(子程序的一些基本資訊都不用再初始化,因為Zygote已經初始過了,相當于優化了啟動程序的流程)。
7.5 runOnce(ZygoteConnection.java)
1) 讀取相應的參數清單
2) 建立子程序forkAndSpecialize(Zygote.forkAndSpecialize -> com_android_internal_os_Zygote_nativeForkAndSpecialize/ForkAndSpecializeCommon/fork(com_android_internal_os_Zygote.cpp)),通過jni調用com_android_internal_os_Zygote_nativeForkAndSpecialize,最後調用的是fork函數,該函數用于建立程序,具體在這裡不展開,具體可以參考之前的一篇文章
Android上層如何調用一個底層函數
的章節
2.1.3 com_android_internal_os_Zygote.cpp本地函數
裡面有關于fork的講解。最終子程序傳回的是pid==0,父程序傳回的是子程序的pid。
3) 處理父程序的内容handleParentProc,如傳回給AMS章節6.5中startProcessLocked的Process.start,其值是Process.ProcessStartResult startResult,包含子程序pid
4) 處理子程序的内容handleChildProc,這個放在下一節講解
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
...
try {
//讀取相應的參數清單
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors();
}
//...
//invokeWith==null,目前沒有設定
if (parsedArgs.invokeWith != null) {
//...
}
//...
int [] fdsToClose = { -, - };
FileDescriptor fd = mSocket.getFileDescriptor();
if (fd != null) {
//用戶端的檔案描述符
fdsToClose[] = fd.getInt$();
}
fd = ZygoteInit.getServerSocketFileDescriptor();
if (fd != null) {
//服務端的檔案描述符
fdsToClose[] = fd.getInt$();
}
//調用native fork程序的地方
//此處是fock程序(Zygote.forkAndSpecialize
//->com_android_internal_os_Zygote_nativeForkAndSpecialize
//->ForkAndSpecializeCommon/fork(com_android_internal_os_Zygote.cpp))
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
parsedArgs.appDataDir);
//...
try {
//如果是子程序pid會等于0,父程序此處pid會傳回子程序的pid
if (pid == ) {
//...
//處理子程序邏輯
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
//子程序是永遠不會到這個位置來的,因為之前已經抛出MethodAndArgsCaller異常
return true;
} else {
//...
//處理父程序邏輯
return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
}
...
}
private String[] readArgumentList()
throws IOException {
//...
try {
//讀取第一個參數
String s = mSocketReader.readLine();
//第一個參數上面章節7.2 Process.java中zygoteSendArgsAndGetResult寫的就是參數個數
argc = Integer.parseInt(s);
}
//傳遞的參數最多是1024個,超過的話系統可能受到DOS攻擊
if (argc > MAX_ZYGOTE_ARGC) {
throw new IOException("max arg count exceeded");
}
for (int i = ; i < argc; i++) {
//讀出每一個參數傳回result數組中去
result[i] = mSocketReader.readLine();
...
}
private boolean handleParentProc(int pid,
FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs) {
if (pid > ) {
//如果傳回的pid大于0,說明子程序建立成功,此時設定子程序的pid
setChildPgid(pid);
}
//...
try {
//傳遞pid回去,最後寫入章節7.2中zygoteSendArgsAndGetResult的result.pid
mSocketOutStream.writeInt(pid);
//傳遞是否wrapped程序,此處一般都是false
mSocketOutStream.writeBoolean(usingWrapper);
}
//...
return false;
}
8. 綁定程序am_proc_bound
上一章節我們知道了Process.start用于建立程序,父程序會直接傳回子程序的pid,那麼接下去我們需要從子程序處理的内容開始分析,看看子程序是怎樣關聯到上層的application中去的,這裡講解第一步am_proc_bound
圖8.1 綁定程序
8.1 handleChildProc(ZygoteConnection.java)
1) 關閉相應的子程序Socket連結
2) 設定程序的名字,這個時候通過ps就可以看到程序名字變成應用聲明的程序(如果沒有定義
android:process
那麼預設該程序名字就是應用的包名)
3) RuntimeInit.zygoteInit子程序的初始化
private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws ZygoteInit.MethodAndArgsCaller {
//關閉自己的Socket
closeSocket();
//關閉ZygoteInit中服務端的Socket
ZygoteInit.closeServerSocket();
//...
if (parsedArgs.niceName != null) {
//自己設定自己的名字,此處設定程序名字為之前傳進來的processName
Process.setArgV0(parsedArgs.niceName);
}
//這裡是不運作的
if (parsedArgs.invokeWith != null) {
//...
//此處會進來
} else {
//運作初始化RuntimeInit中的程序(受精卵)初始化zygoteInit
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}
ps:Process.setArgV0會通過prctl(PR_SET_NAME…),裁剪後(process_name.c),隻保留processName後面15個字元(kernel實際還會裁剪到最後一個字元,其實是14個字元),設定程序名字(核心辨別程序的名字是task_struc->comm).
程序的名字在某些地方顯示不是無限長的,如在systrace顯示的程序名字就不超過15個字元。
8.2 zygoteInit(RuntimeInit.java)
1) log重定向redirectLogStreams
2) 通用設定初始化commonInit
3) 初始化zygote:nativeZygoteInit
4) 應用初始化applicationInit
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
//重新定向log的輸入地方,此處設定log輸出到Android log中
redirectLogStreams();
//一些通用設定的初始化
commonInit();
//初始化zygote,這裡AppRuntime繼承的是AndroidRuntime,運作的是啟動線程池startThreadPool
nativeZygoteInit();
//應用初始化,此處是接下來運作的地方
applicationInit(targetSdkVersion, argv, classLoader);
}
private static final void commonInit() {
//...
//設定預設的異常捕獲
Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());
TimezoneGetter.setInstance(new TimezoneGetter() {
@Override
public String getId() {
//設定時區id
return SystemProperties.get("persist.sys.timezone");
}
});
//設定時區
TimeZone.setDefault(null);
LogManager.getLogManager().reset();
//Android log相關初始化
new AndroidConfig();
String userAgent = getDefaultUserAgent();
//網絡使用者代理初始化
System.setProperty("http.agent", userAgent);
//網絡Socket相關
NetworkManagementSocketTagger.install();
//...
initialized = true;
}
8.3 applicationInit
1) 設定虛拟機GC回收比例,正在使用的對象/堆棧大小 = 0.75
2) 設定虛拟機sdk的版本号
3) 擷取相應的參數,如args.startClass就是在章節7.2 startViaZygote設定的processClass(ActivityThread)
4) 通過反射查找ActivityThread的main函數,并将其作為MethodAndArgsCaller異常的參數
private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
//設定退出時不調用onExit()函數
nativeSetExitWithoutCleanup(true);
//設定GC回收後的比例,正在使用的對象/堆棧大小 = 0.75,對應于dalvik.vm.heaptargetutilization
VMRuntime.getRuntime().setTargetHeapUtilization(f);
//設定sdk的版本号,這個是程序啟動Process.start時就傳遞過來的
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
//擷取相應的參數,如args.startClass就是第一個非"--"開頭的參數
final Arguments args;
try {
args = new Arguments(argv);
}
//...
//反射調用main函數,注意startClass是Process.start時傳遞進來的android.app.ActivityThread
invokeStaticMain(args.startClass, args.startArgs, classLoader);
}
private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
//...
//查找android.app.ActivityThread類
cl = Class.forName(className, true, classLoader);
//...
//查找其中的main函數
m = cl.getMethod("main", new Class[] { String[].class });
//...
//擷取函數的調用屬性
int modifiers = m.getModifiers();
//必須是靜态而且是public的方法,否則抛出RuntimeException異常
if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
throw new RuntimeException(
"Main method is not public and static on " + className);
}
//抛出MethodAndArgsCaller異常
throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}
在章節7.3 ZygoteInit.main方法裡面有捕獲MethodAndArgsCaller異常,并調用MethodAndArgsCaller的run方法。
8.4 MethodAndArgsCaller.run()
反射調用ActivityThread的main靜态函數
public static class MethodAndArgsCaller extends Exception
implements Runnable {
//...
public MethodAndArgsCaller(Method method, String[] args) {
//mMethod是ActivityThread的main方法
mMethod = method;
//mArgs一般都是null
mArgs = args;
}
public void run() {
try {
//調用方法method,傳遞的是args參數,傳遞第一個參數是類對象為null,代表靜态函數
mMethod.invoke(null, new Object[] { mArgs });
//...
到這裡程序已經啟動完成,将進入應用相關流程
8.5 MethodAndArgsCaller.run()
1) 消息隊列初始化Looper.prepareMainLooper
2) 建立ActivityThread并附着thread.attach
3) 進入消息隊列的循環Looper.loop
public static void main(String[] args) {
//預設是沒有用到SamplingProfilerIntegration的,
//該類用于監聽性能資料,包含程序名字、應用資訊、線程啟動與關閉,
//還有預設persist.sys.profiler_ms毫秒dump一次該程序堆棧資訊
SamplingProfilerIntegration.start();
//在嚴格模式或者調試的時候打開,預設不打卡
CloseGuard.setEnabled(false);
//初始化環境(這裡主要是儲存設備的環境,用user id初始化)
Environment.initForCurrentUser();
//主要是libcore中使用event log的方法,Reporter的report類似于EventLog.writeEvent
EventLogger.setReporter(new EventLoggingReporter());
//配置檔案目錄在/data/misc/user/1000
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
//設定認證相關的目錄cacerts-added,cacerts-removed
TrustedCertificateStore.setDefaultUserDirectory(configDir);
//設定程序名字為<pre-initialized>,這個很快在handleBindApplication時就會給修改
Process.setArgV0("<pre-initialized>");
//消息隊列初始化,主程序是不允許退出的,無法調用MessageQueue.quit退出
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
//建立一個ActivityThread并attach附着,這個跟接下去的attachApplication相關
thread.attach(false);
if (sMainThreadHandler == null) {
//擷取thread的handler,将其作為應用的主線程
sMainThreadHandler = thread.getHandler();
}
if (false) {
//使用者調試log,用于消息隊列Message的事件分發log輸出,
//調試消息隊列的時候可以打開
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
//Looper.loop()裡面是個for (;;)死循環,隻要Message不為null,會一直運作
//Looper.loop() -> MessageQueue.next()
//-> nativePollOnce(android_os_MessageQueue.cpp)
//->(pollOnce/pollInner/epoll_wait) Looper.cpp,
//這個Message==null情況隻有調用MessageQueue.quit才會發生,
//目前沒有看到主動調用MessageQueue.quit,故這個消息隊列循環是不會退出的
Looper.loop();
//如果進入到這裡代表程式出錯了,這裡程式正常運作是不會進來的
throw new RuntimeException("Main thread loop unexpectedly exited");
}
在調用靜态方法ActivityThread.main之後會建立一個ActivityThread對象,相當于該程序的主線程(UI線程),建立之後首先跑的就是ActivityThread的attach函數
8.6 attach
這裡我們主要關注attachApplication,也就是AMS的應用附着即可
private void attach(boolean system) {
//...
//是否system,應用啟動肯定不是system,會進入此處
if (!system) {
//...
//設定ddms中的程序名字為"<pre-initialized>",臨時的
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>", UserHandle.myUserId());
//設定ApplicationObject為ActivityThread
RuntimeInit.setApplicationObject(mAppThread.asBinder());
final IActivityManager mgr = ActivityManagerNative.getDefault();
try {
//此處就是attachApplication
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
//Java允許在類中定義一個名為finalize()的方法。
//它的工作原理是:一旦垃圾回收器準備好釋放對象占用的存儲空間,将首先調用其finalize()方法。
//并且在下一次垃圾回收動作發生時,才會真正回收對象占用的記憶體
//BinderInternal裡面實作的是Object finalize,
//當資源釋放的時候會調用finalize,然後會調用
BinderInternal.addGcWatcher(new Runnable() {
//ActivityThread對象沒有再使用時會進行回收
@Override public void run() {
if (!mSomeActivitiesChanged) {
return;
}
Runtime runtime = Runtime.getRuntime();
//這個是HeapGrowthLimit,正常應用虛拟機記憶體最大值dalvik.vm.heapgrowthlimit,
//AndroidRuntime.cpp/runtime.cc/heap.cc
long dalvikMax = runtime.maxMemory();
long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
//目前使用記憶體,如果最大記憶體的3/4将進行activity的釋放操作
if (dalvikUsed > ((*dalvikMax)/)) {
//...
mSomeActivitiesChanged = false;
try {
//此處釋放指的是activity的ondestroy,
//目前可以destroy的activity是處于onstop狀态的activity
mgr.releaseSomeActivities(mAppThread);
//...
//讓DropBox在libcore可用
DropBox.setReporter(new DropBoxReporter());
}
8.7 attachApplication/attachApplicationLocked
1) 首先是ActivityManagerNative.java的attachApplication會傳遞ActivityThread和調用者的pid給到AMS的attachApplicationLocked
2) eventlog中設定服務綁定程序am_proc_bound,說明程序啟動完成,而且該程序的主線程ActivityThread已經建立,并且通知到AMS中
3) ActivityThread的綁定應用bindApplication, 這個會在下面章節講解
4) 由于我們這個例子是桌面啟動應用,那麼最後mStackSupervisor.attachApplicationLocked堆棧中的綁定應用會真正啟動activity活動對象,這個會在下面章節講解
//ActivityManagerNative.java
public final void attachApplication(IApplicationThread thread) {
...
attachApplicationLocked(thread, callingPid);
...
//ActivityManagerService.java
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
//...
ProcessRecord app;
//調用者非系統程序,且調用者的pid大于0
if (pid != MY_PID && pid >= ) {
synchronized (mPidsSelfLocked) {
//在程序啟動Process.start後就将pid添加進入mPidsSelfLocked了(父程序調用)
//現在是子程序調用,這個時候已經添加
app = mPidsSelfLocked.get(pid);
//...
//app.thread還沒有設定過,下面makeActive将進行設定,會将app.thread設定成
//IApplicationThread(在ActivityThread中),app.thread不為null了
if (app.thread != null) {
//...
}
//...
try {
AppDeathRecipient adr = new AppDeathRecipient(
app, pid, thread);
//設定binder died掉之後的的回調地方是binderDied
thread.asBinder().linkToDeath(adr, );
//設定目前誰在監控死亡狀态
app.deathRecipient = adr;
//...
//eventlog中設定服務綁定am_proc_bound
EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);
//設定ProcessRecord的IApplicationThread(在ActivityThread中)
app.makeActive(thread, mProcessStats);
//預設設定一個adj
app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
//...
//使用者更新電量估算mBatteryStatsService的FOREGROUND時間
updateProcessForegroundLocked(app, false, false);
//...
//判斷是否解鎖
app.unlocked = StorageManager.isUserKeyUnlocked(app.userId);
//去除程序啟動逾時的msg PROC_START_TIMEOUT_MSG,
//此處有ActivityThread回傳,代表程序啟動完成
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
//一般情況normalMode都是true
boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
//generateApplicationProvidersLocked是開始建立應用的ContentProvider對象
List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
//...
//一般不會進入這裡,這裡是自動化測試的時候會進來
if (app.instrumentationClass != null) {
//...
}
//...
//應用相容性相關,該參數會傳入AcitiviyThread中
app.compat = compatibilityInfoForPackageLocked(appInfo);
//一般profilerInfo==null
ProfilerInfo profilerInfo = profileFile == null ? null
: new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);
//回到AcitiviyThread中的bindApplication,processName==test2,
//instrument相關都等于null,mBinderTransactionTrackingEnabled/
//enableTrackAllocation/isRestrictedBackupMode預設等于false,
//normalMode預設是true,persistent代表是否常駐記憶體,compat是相容性相關,
//isolated==false,getCommonServicesLocked是将PMS、WMS、ALARM相關服務傳入,
//mCoreSettingsObserver用于監聽一些參數變化(長按逾時,12/24小時顯示時間變化,
//調試界面屬性),bindApplication是異步的
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked());
//将程序添加進入mLruProcesses中
//mLruProcesses儲存的是正在運作應用的清單,第一個是最近使用的
updateLruProcessLocked(app, false, null);
//觸發GC的時間重新計算
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
//...
//一般normalMode都是true
if (normalMode) {
try {
//如果是activity導緻的程序啟動,activity從這裡開始啟動
//此處用于am_restart_activity,此處設定了didSomething = true
if (mStackSupervisor.attachApplicationLocked(app)) {
didSomething = true;
}
//...
//一般badApp==false
if (!badApp) {
try {
//如果之前該程序有需要啟動的服務,此處開始啟動服務
//啟動程序了之後才會去啟動服務
didSomething |= mServices.attachApplicationLocked(app, processName);
//...
if (!badApp && isPendingBroadcastProcessLocked(pid)) {
try {
//如果該程序之前有挂起的廣播,現在可以開始發送了
didSomething |= sendPendingBroadcastsLocked(app);
// ...
到目前為止綁定程序的邏輯已經講解完了,接下去我們僅需要關注thread.bindApplication和mStackSupervisor.attachApplicationLocked這2個函數
9 建立application
這一章節将會講到application的執行個體化、application程序上下文context的建立、application的OnCreate
圖9.1 建立application
9.1 bindApplication(ActivityThread.java)
我們關注的重點:
1) getPackageInfoNoCheck建立new LoadedApk,該類用于加載apk
2) makeApplication建立一個Application對象new newApplication(這裡面會createAppContext建立application的程序上下文context)
3) callApplicationOnCreate調用Application的OnCreate
private void handleBindApplication(AppBindData data) {
//設定art實時編譯更加敏感,更新art配置相關資訊的計數count會乘10=((10000/500)/2),
//會讓art更容易更新配置(如做實時編譯還是解釋執行等)
VMRuntime.registerSensitiveThread();
//...
//設定process的啟動時間,這個主要是給上層調用的
Process.setStartTimes(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
//AMS傳遞進來的參數全部放在data上
mBoundApplication = data;
//程序啟動時如果你沒有設定固定方向或者手動改變方向,這個config就是AMS中的mConfiguration
mConfiguration = new Configuration(data.config);
mCompatConfiguration = new Configuration(data.config);
mProfiler = new Profiler();
//一般情況initProfilerInfo都是null,除了使用instrumentation(如自動化測試相關會使用到)
if (data.initProfilerInfo != null) {
...
}
//此處會通過prctl(PR_SET_NAME...),裁剪後(process_name.c)
//隻保留processName後面15個字元(kernel實際還會裁剪到最後一個字元,其實是14個字元),
//設定程序名字(核心辨別程序的名字是task_struc->comm).
Process.setArgV0(data.processName);
//此處設定的是ddms調試使用的名字
android.ddm.DdmHandleAppName.setAppName(data.processName,
UserHandle.myUserId());
//常駐記憶體的程序
if (data.persistent) {
//如果在不能使用GPU加速(如低記憶體裝置
//或者顯示定義config_avoidGfxAccel為ture的情況都會進來)
if (!ActivityManager.isHighEndGfx()) {
//目前程序停止使用硬體渲染,這裡的作用主要是為了減少運存RAM的消耗,
//對于低記憶體手機,這個是有幫助的
ThreadedRenderer.disable(false);
}
}
//...
//回複系統預設時區
TimeZone.setDefault(null);
//設定預設的語言
LocaleList.setDefault(data.config.getLocales());
//...
//建立new LoadedApk,該類用于加載apk
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
//...
//可以通過config對分辨率進行設定,預設是沒有設定的
updateDefaultDensity();
//設定是否24小時
final boolean is24Hr = "24".equals(mCoreSettings.getString(Settings.System.TIME_12_24));
DateFormat.set24HourTimePref(is24Hr);
//...
//網絡代理相關設定
final IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
if (b != null) {
final IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
try {
final ProxyInfo proxyInfo = service.getProxyForNetwork(null);
Proxy.setHttpProxySystemProperty(proxyInfo);
//...
//建立一個appContext
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
//...
//應用一般是isIsolated == false,這裡講的不是系統程序,是普通app的程序的啟動,故會進入此處
if (!Process.isIsolated() && !"android".equals(appContext.getPackageName())) {
//擷取應用緩存目錄,如("/data/user_de/0/com.android.settings/cache")
final File cacheDir = appContext.getCacheDir();
//...
//擷取應用代碼緩存目錄,"/data/user_de/0/com.android.settings/code_cache"
//此處主要是存放的opengl和renderscript部分的緩存代碼
//類似于com.android.opengl.shaders_cache、com.android.renderscript.cache這樣的資料
final File codeCacheDir = deviceContext.getCodeCacheDir();
}
//...
//ii非自動化測試一般都是null
if (ii != null) {
...
} else {
//一般情況下走的是這裡
mInstrumentation = new Instrumentation();
}
//設定虛拟機堆棧最大能增長到的記憶體是多少,根據largeHeap屬性判斷是否大應用
if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != ) {
//如果是大應用的話,應用虛拟機記憶體可以增長到堆棧大小dalvik.vm.heapsize
dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
} else {
//預設隻能增長到dalvik.vm.heapgrowthlimit受限制的堆棧大小
dalvik.system.VMRuntime.getRuntime().clampGrowthLimit();
}
// allowThreadDiskWrites在應用oncreate的時候允許寫的操作,
//傳回的值是就得政策,此處僅用于臨時修改
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
try {
//restrictedBackupMode是flase,data.info是上面new的LoadedApk,
//這裡面的createAppContext和上面的createAppContext傳遞的參數是一樣的
//此處會建立一個Application對象new newApplication,此處是Application的執行個體化
//此處傳遞的第二個參數instrumentation==null,故application不會在此處OnCreate
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
//儲存目前的Application對象
mInitialApplication = app;
//一般沒有限制備份模式,restrictedBackupMode == false
if (!data.restrictedBackupMode) {
//如果apk有provider就會進入這裡(如靜态注冊的providers)
if (!ArrayUtils.isEmpty(data.providers)) {
//初始化app中的所有provider
installContentProviders(app, data.providers);
//...
}
}
try {
//如果沒有複寫Instrumentation,一般此處沒有做任何事情
mInstrumentation.onCreate(data.instrumentationArgs);
}
//...
try {
//此處調用的就是Application的OnCreate方法,
//activity的OnCreate後面會講到,這裡先調用的是Application的OnCreate
mInstrumentation.callApplicationOnCreate(app);
//...
}
9.2 getPackageInfoNoCheck/getPackageInfo
getPackageInfoNoCheck/getPackageInfo傳回的是LoadedApk,用于加載apk
public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai,
CompatibilityInfo compatInfo) {
return getPackageInfo(ai, compatInfo, null, false, true, false);
}
//(ai, compatInfo, null, false, true, false);
private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
ClassLoader baseLoader, boolean securityViolation, boolean includeCode,
boolean registerPackage) {
//...
//此處apk是包含代碼的,故是從mPackages取,第一次進來此處是null
ref = mPackages.get(aInfo.packageName);
LoadedApk packageInfo = ref != null ? ref.get() : null;
//建立LoadedApk加載apk的類
packageInfo =
new LoadedApk(this, aInfo, compatInfo, baseLoader,
securityViolation, includeCode &&
(aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != , registerPackage);
//...
//将建立的LoadedApk放到mPackages中
mPackages.put(aInfo.packageName,
new WeakReference<LoadedApk>(packageInfo));
//...
return packageInfo;
}
9.3 makeApplication(LoadedApk.java)
1) 建立Application的程序上下文
2) 調用代理Instrumentation建立Application
3) Application執行個體化、Application設定程序上下文context
//LoadedApk.java
//forceDefaultAppClass==false,instrumentation==null
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
//...
Application app = null;
//如果應用沒有重載Application類的話,直接使用預設的"android.app.Application"
String appClass = mApplicationInfo.className;
if (forceDefaultAppClass || (appClass == null)) {
appClass = "android.app.Application";
}
try {
java.lang.ClassLoader cl = getClassLoader();
//...
//建立Application的程序上下文
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
//調用代理Instrumentation建立Application
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
}
//...
return app;
}
//Instrumentation.java
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return newApplication(cl.loadClass(className), context);
}
static public Application newApplication(Class<?> clazz, Context context)
... {
//Application類的執行個體化,如類非靜态變量等會在此處生成
Application app = (Application)clazz.newInstance();
//調用Application的attach附着,用于設定程序上下文context
app.attach(context);
return app;
}
//Application.java
final void attach(Context context) {
//設定base應用基本的程序上下文
attachBaseContext(context);
//設定類的加載器
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
現在有了Application這個對象,下面接着會進行Application的OnCreate
9.4 callApplicationOnCreate(Instrumentation.java)
callApplicationOnCreate這個函數通過代理調用Application的OnCreate
//Instrumentation.java
public void callApplicationOnCreate(Application app) {
app.onCreate();
}
//Application.java
public void onCreate() {
}
程序啟動會先調用Application的OnCreate,這個也是算在應用啟動生命周期内的。
目前Application建立了,Application的OnCreate也調用了,接下去就是Activity相關的邏輯。