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) != 0;
//此處判斷是否有需要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 : 0) | (dontReport ? DONT_REPORT : 0),
configChanges,
seq);
}
//handler傳遞,調用的是handlePauseActivity
case PAUSE_ACTIVITY: {
//...
//進入pause的處理
handlePauseActivity((IBinder) args.arg1, false,
(args.argi1 & USER_LEAVING) != 0, args.argi2,
(args.argi1 & DONT_REPORT) != 0, 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 = 0; 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 > 0
&& 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 = 0;
}
//有界面可視的時候mAppVisibilitiesChangedSinceLastPause==true(setVisible時設置),
//所以這裏會進來
if (mStackSupervisor.mAppVisibilitiesChangedSinceLastPause) {
//...
//launcher已經pause,設置mAppVisibilitiesChangedSinceLastPause==false
mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = false;
}
//最後是更新顯示界面,這裏是第一次調用ensureActivitiesVisibleLocked,
//遍歷所有stack的ensureActivitiesVisibleLocked
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !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, 0,
"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, 0 /* 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) != 0) {
...
} 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 > 0) {
//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 != 0) ? app : null;
}
//真正啓動進程的地方
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
//...
if (app.pid > 0 && 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[0];
}
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()), 256);
//...
}
private static ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, ArrayList<String> args)
throws ZygoteStartFailedEx {
try {
//...
//第一個先寫的是參數大小
writer.write(Integer.toString(args.size()));
writer.newLine();
for (int i = 0; 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 1 0 28524 1932 SyS_epoll_ 0000000000 S /init
root 428 1 1771768 22020 poll_sched 0000000000 S zygote64 //此處代表是64bit的
system 996 428 2086288 190084 SyS_epoll_ 0000000000 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 = 1; 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, -1);
}
//...
for (int i = pollFds.length - 1; i >= 0; --i) {
//revents域是文件描述符的操作結果事件掩碼,POLLIN代表有數據可讀
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
//i==0是就是外部有創建socket的時候,如Socket.connect,
//這個時候Os.poll中LocalServerSocket會有數據返回,
//此時LocalServerSocket會accept並創建新的ZygoteConnection
if (i == 0) {
//創建新的受精卵的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 = { -1, -1 };
FileDescriptor fd = mSocket.getFileDescriptor();
if (fd != null) {
//客戶端的文件描述符
fdsToClose[0] = fd.getInt$();
}
fd = ZygoteInit.getServerSocketFileDescriptor();
if (fd != null) {
//服務端的文件描述符
fdsToClose[1] = 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 == 0) {
//...
//處理子進程邏輯
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 = 0; i < argc; i++) {
//讀出每一個參數返回result數組中去
result[i] = mSocketReader.readLine();
...
}
private boolean handleParentProc(int pid,
FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs) {
if (pid > 0) {
//如果返回的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(0.75f);
//設置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 > ((3*dalvikMax)/4)) {
//...
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 >= 0) {
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, 0);
//設置目前誰在監控死亡狀態
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) != 0) {
//如果是大應用的話,應用虛擬機內存可以增長到堆棧大小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) != 0, 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相關的邏輯。