Android應用程式啟動過程原始碼分析(2)
Step 9. ActivityStack.startActivityUncheckedLocked
這個函式定義在frameworks/base/services/java/com/android/server/am/ActivityStack.java檔案中:
view plain
public class ActivityStack {
......
final int startActivityUncheckedLocked(ActivityRecord r,
ActivityRecord sourceRecord, Uri[] grantedUriPermissions,
int grantedMode, boolean onlyIfNeeded, boolean doResume) {
final Intent intent = r.intent;
final int callingUid = r.launchedFromUid;
int launchFlags = intent.getFlags();
// We'll invoke onUserLeaving before onPause only if the launching
// activity did not explicitly state that this is an automated launch.
mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
......
ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
!= 0 ? r : null;
// If the onlyIfNeeded flag is set, then we can do this if the activity
// being launched is the same as the one making the call... or, as
// a special case, if we do not know the caller then we count the
// current top activity as the caller.
if (onlyIfNeeded) {
......
}
if (sourceRecord == null) {
......
} else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
......
} else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
......
}
if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
......
}
boolean addingToTask = false;
if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
(launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
// If bring to front is requested, and no result is requested, and
// we can find a task that was started with this same
// component, then instead of launching bring that one to the front.
if (r.resultTo == null) {
// See if there is a task to bring to the front. If this is
// a SINGLE_INSTANCE activity, there can be one and only one
// instance of it in the history, and it is always in its own
// unique task, so we do a special search.
ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
? findTaskLocked(intent, r.info)
: findActivityLocked(intent, r.info);
if (taskTop != null) {
......
}
}
}
......
if (r.packageName != null) {
// If the activity being launched is the same as the one currently
// at the top, then we need to check if it should only be launched
// once.
ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
if (top != null && r.resultTo == null) {
if (top.realActivity.equals(r.realActivity)) {
......
}
}
} else {
......
}
boolean newTask = false;
// Should this be considered a new task?
if (r.resultTo == null && !addingToTask
&& (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
// todo: should do better management of integers.
mService.mCurTask++;
if (mService.mCurTask <= 0) {
mService.mCurTask = 1;
}
r.task = new TaskRecord(mService.mCurTask, r.info, intent,
(r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
......
newTask = true;
if (mMainStack) {
mService.addRecentTaskLocked(r.task);
}
} else if (sourceRecord != null) {
......
} else {
......
}
......
startActivityLocked(r, newTask, doResume);
return START_SUCCESS;
}
......
}
函式首先獲得intent的標誌值,儲存在launchFlags變數中。
這個intent的標誌值的位Intent.FLAG_ACTIVITY_NO_USER_ACTION沒有置位,因此 ,成員變數mUserLeaving的值為true。
這個intent的標誌值的位Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP也沒有置位,因此,變數notTop的值為null。
由於在這個例子的AndroidManifest.xml檔案中,MainActivity沒有配置launchMode屬值,因此,這裡的r.launchMode為預設值0,表示以標準(Standard,或者稱為ActivityInfo.LAUNCH_MULTIPLE)的方式來啟動這個Activity。Activity的啟動方式有四種,其餘三種分別是ActivityInfo.LAUNCH_SINGLE_INSTANCE、ActivityInfo.LAUNCH_SINGLE_TASK和ActivityInfo.LAUNCH_SINGLE_TOP,具體可以參考官方網站
傳進來的引數r.resultTo為null,表示Launcher不需要等這個即將要啟動的MainActivity的執行結果。
由於這個intent的標誌值的位Intent.FLAG_ACTIVITY_NEW_TASK被置位,而且Intent.FLAG_ACTIVITY_MULTIPLE_TASK沒有置位,因此,下面的if語句會被執行:
view plain
if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
(launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
// If bring to front is requested, and no result is requested, and
// we can find a task that was started with this same
// component, then instead of launching bring that one to the front.
if (r.resultTo == null) {
// See if there is a task to bring to the front. If this is
// a SINGLE_INSTANCE activity, there can be one and only one
// instance of it in the history, and it is always in its own
// unique task, so we do a special search.
ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
? findTaskLocked(intent, r.info)
: findActivityLocked(intent, r.info);
if (taskTop != null) {
......
}
}
}
這段程式碼的邏輯是檢視一下,當前有沒有Task可以用來執行這個Activity。由於r.launchMode的值不為ActivityInfo.LAUNCH_SINGLE_INSTANCE,因此,它通過findTaskLocked函式來查詢存不存這樣的Task,這裡返回的結果是null,即taskTop為null,因此,需要建立一個新的Task來啟動這個Activity。
接著往下看:
view plain
if (r.packageName != null) {
// If the activity being launched is the same as the one currently
// at the top, then we need to check if it should only be launched
// once.
ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
if (top != null && r.resultTo == null) {
if (top.realActivity.equals(r.realActivity)) {
......
}
}
}
這段程式碼的邏輯是看一下,當前在堆疊頂端的Activity是否就是即將要啟動的Activity,有些情況下,如果即將要啟動的Activity就在堆疊的頂端,那麼,就不會重新啟動這個Activity的別一個例項了,具體可以參考官方網站http://developer.android.com/reference/android/content/pm/ActivityInfo.html。現在處理堆疊頂端的Activity是Launcher,與我們即將要啟動的MainActivity不是同一個Activity,因此,這裡不用進一步處理上述介紹的情況。
執行到這裡,我們知道,要在一個新的Task裡面來啟動這個Activity了,於是新建立一個Task:
view plain
if (r.resultTo == null && !addingToTask
&& (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
// todo: should do better management of integers.
mService.mCurTask++;
if (mService.mCurTask <= 0) {
mService.mCurTask = 1;
}
r.task = new TaskRecord(mService.mCurTask, r.info, intent,
(r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
......
newTask = true;
if (mMainStack) {
mService.addRecentTaskLocked(r.task);
}
}
新建的Task儲存在r.task域中,同時,新增到mService中去,這裡的mService就是ActivityManagerService了。
最後就進入startActivityLocked(r, newTask, doResume)進一步處理了。這個函式定義在frameworks/base/services/java/com/android/server/am/ActivityStack.java檔案中:
view plain
public class ActivityStack {
......
private final void startActivityLocked(ActivityRecord r, boolean newTask,
boolean doResume) {
final int NH = mHistory.size();
int addPos = -1;
if (!newTask) {
......
}
// Place a new activity at top of stack, so it is next to interact
// with the user.
if (addPos < 0) {
addPos = NH;
}
// If we are not placing the new activity frontmost, we do not want
// to deliver the onUserLeaving callback to the actual frontmost
// activity
if (addPos < NH) {
......
}
// Slot the activity into the history stack and proceed
mHistory.add(addPos, r);
r.inHistory = true;
r.frontOfTask = newTask;
r.task.numActivities++;
if (NH > 0) {
// We want to show the starting preview window if we are
// switching to a new task, or the next activity's process is
// not currently running.
......
} else {
// If this is the first activity, don't do any fancy animations,
// because there is nothing for it to animate on top of.
......
}
......
if (doResume) {
resumeTopActivityLocked(null);
}
}
......
}
這裡的NH表示當前系統中歷史任務的個數,這裡肯定是大於0,因為Launcher已經跑起來了。當NH>0時,並且現在要切換新任務時,要做一些任務切的介面操作,這段程式碼我們就不看了,這裡不會影響到下面啟Activity的過程,有興趣的讀取可以自己研究一下。
這裡傳進來的引數doResume為true,於是呼叫resumeTopActivityLocked進一步操作。
Step 10. Activity.resumeTopActivityLocked
這個函式定義在frameworks/base/services/java/com/android/server/am/ActivityStack.java檔案中:
view plain
public class ActivityStack {
......
/**
* Ensure that the top activity in the stack is resumed.
*
* @param prev The previously resumed activity, for when in the process
* of pausing; can be null to call from elsewhere.
*
* @return Returns true if something is being resumed, or false if
* nothing happened.
*/
final boolean resumeTopActivityLocked(ActivityRecord prev) {
// Find the first activity that is not finishing.
ActivityRecord next = topRunningActivityLocked(null);
// Remember how we'll process this pause/resume situation, and ensure
// that the state is reset however we wind up proceeding.
final boolean userLeaving = mUserLeaving;
mUserLeaving = false;
if (next == null) {
......
}
next.delayedResume = false;
// If the top activity is the resumed one, nothing to do.
if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
......
}
// If we are sleeping, and there is no resumed activity, and the top
// activity is paused, well that is the state we want.
if ((mService.mSleeping || mService.mShuttingDown)
&& mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
......
}
......
// If we are currently pausing an activity, then don't do anything
// until that is done.
if (mPausingActivity != null) {
......
}
......
// We need to start pausing the current activity so the top one
// can be resumed...
if (mResumedActivity != null) {
......
startPausingLocked(userLeaving, false);
return true;
}
......
}
......
}
函式先通過呼叫topRunningActivityLocked函式獲得堆疊頂端的Activity,這裡就是MainActivity了,這是在上面的Step 9設定好的,儲存在next變數中。
接下來把mUserLeaving的儲存在本地變數userLeaving中,然後重新設定為false,在上面的Step 9中,mUserLeaving的值為true,因此,這裡的userLeaving為true。
這裡的mResumedActivity為Launcher,因為Launcher是當前正被執行的Activity。
當我們處理休眠狀態時,mLastPausedActivity儲存堆疊頂端的Activity,因為當前不是休眠狀態,所以mLastPausedActivity為null。
有了這些資訊之後,下面的語句就容易理解了:
view plain
// If the top activity is the resumed one, nothing to do.
if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
......
}
// If we are sleeping, and there is no resumed activity, and the top
// activity is paused, well that is the state we want.
if ((mService.mSleeping || mService.mShuttingDown)
&& mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
......
}
它首先看要啟動的Activity是否就是當前處理Resumed狀態的Activity,如果是的話,那就什麼都不用做,直接返回就可以了;否則再看一下系統當前是否休眠狀態,如果是的話,再看看要啟動的Activity是否就是當前處於堆疊頂端的Activity,如果是的話,也是什麼都不用做。
上面兩個條件都不滿足,因此,在繼續往下執行之前,首先要把當處於Resumed狀態的Activity推入Paused狀態,然後才可以啟動新的Activity。但是在將當前這個Resumed狀態的Activity推入Paused狀態之前,首先要看一下當前是否有Activity正在進入Pausing狀態,如果有的話,當前這個Resumed狀態的Activity就要稍後才能進入Paused狀態了,這樣就保證了所有需要進入Paused狀態的Activity序列處理。
這裡沒有處於Pausing狀態的Activity,即mPausingActivity為null,而且mResumedActivity也不為null,於是就呼叫startPausingLocked函式把Launcher推入Paused狀態去了。
Step 11. ActivityStack.startPausingLocked
這個函式定義在frameworks/base/services/java/com/android/server/am/ActivityStack.java檔案中:
view plain
public class ActivityStack {
......
private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
if (mPausingActivity != null) {
......
}
ActivityRecord prev = mResumedActivity;
if (prev == null) {
......
}
......
mResumedActivity = null;
mPausingActivity = prev;
mLastPausedActivity = prev;
prev.state = ActivityState.PAUSING;
......
if (prev.app != null && prev.app.thread != null) {
......
try {
......
prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
prev.configChangeFlags);
......
} catch (Exception e) {
......
}
} else {
......
}
......
}
......
}
函式首先把mResumedActivity儲存在本地變數prev中。在上一步Step 10中,說到mResumedActivity就是Launcher,因此,這裡把Launcher程序中的ApplicationThread物件取出來,通過它來通知Launcher這個Activity它要進入Paused狀態了。當然,這裡的prev.app.thread是一個ApplicationThread物件的遠端介面,通過呼叫這個遠端介面的schedulePauseActivity來通知Launcher進入Paused狀態。
引數prev.finishing表示prev所代表的Activity是否正在等待結束的Activity列表中,由於Laucher這個Activity還沒結束,所以這裡為false;引數prev.configChangeFlags表示哪些config發生了變化,這裡我們不關心它的值。
Step 12. ApplicationThreadProxy.schedulePauseActivity
這個函式定義在frameworks/base/core/java/android/app/ApplicationThreadNative.java檔案中:
view plain
class ApplicationThreadProxy implements IApplicationThread {
......
public final void schedulePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeStrongBinder(token);
data.writeInt(finished ? 1 : 0);
data.writeInt(userLeaving ? 1 :0);
data.writeInt(configChanges);
mRemote.transact(SCHEDULE_PAUSE_ACTIVITY_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
}
......
}
這個函式通過Binder程序間通訊機制進入到ApplicationThread.schedulePauseActivity函式中。
Step 13. ApplicationThread.schedulePauseActivity
這個函式定義在frameworks/base/core/java/android/app/ActivityThread.java檔案中,它是ActivityThread的內部類:
view plain
public final class ActivityThread {
......
private final class ApplicationThread extends ApplicationThreadNative {
......
public final void schedulePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges) {
queueOrSendMessage(
finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
token,
(userLeaving ? 1 : 0),
configChanges);
}
......
}
......
}
這裡呼叫的函式queueOrSendMessage是ActivityThread類的成員函式。
上面說到,這裡的finished值為false,因此,queueOrSendMessage的第一個引數值為H.PAUSE_ACTIVITY,表示要暫停token所代表的Activity,即Launcher。
Step 14. ActivityThread.queueOrSendMessage
這個函式定義在frameworks/base/core/java/android/app/ActivityThread.java檔案中:
view plain
public final class ActivityThread {
......
private final void queueOrSendMessage(int what, Object obj, int arg1) {
queueOrSendMessage(what, obj, arg1, 0);
}
private final void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {
synchronized (this) {
......
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
mH.sendMessage(msg);
}
}
......
}
這裡首先將相關資訊組裝成一個msg,然後通過mH成員變數傳送出去,mH的型別是H,繼承於Handler類,是ActivityThread的內部類,因此,這個訊息最後由H.handleMessage來處理。
Step 15. H.handleMessage
這個函式定義在frameworks/base/core/java/android/app/ActivityThread.java檔案中:
view plain
public final class ActivityThread {
......
private final class H extends Handler {
......
public void handleMessage(Message msg) {
......
switch (msg.what) {
......
case PAUSE_ACTIVITY:
handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2);
maybeSnapshot();
break;
......
}
......
}
......
}
這裡呼叫ActivityThread.handlePauseActivity進一步操作,msg.obj是一個ActivityRecord物件的引用,它代表的是Launcher這個Activity。