Android四大元件原始碼實現詳解系列部落格目錄:
Android應用程序建立流程大揭祕
Android四大元件之bindService原始碼實現詳解
Android四大元件之Activity啟動流程原始碼實現詳解概要
Android四大元件之Activity啟動流程原始碼實現詳解(一)
Android四大元件之Activity啟動流程原始碼實現詳解(二)
還記得大明湖畔的夏雨荷嗎!錯了,還記得我們前面章節部落格Android四大元件之Activity啟動流程原始碼實現詳解(一)嗎,在上述部落格中我們重點分析了Activity啟動的如下相關知識點:
那麼在本篇部落格中我們將繼續分析system_server對Activity啟動請求的處理流程:
system_server程序通過AMS處理啟動Activity請求:
4.為目標Activity查詢/分配或者建立最優Task棧
5.Pause前臺Activity
6.Resume請求的目標Activity
7.AMS請求zygote程序為目標Activity建立所屬程序
注意:本篇的介紹是基於Android 7.xx平臺為基礎的,其中涉及的程式碼路徑如下:
frameworks/base/services/core/java/com/android/server/am/
--- ActivityManagerService.java
--- ProcessRecord.java
--- ActivityRecord.java
--- ActivityResult.java
--- ActivityStack.java
--- ActivityStackSupervisor.java
--- ActivityStarter.java
--- TaskRecord.java
frameworks/base/services/core/java/com/android/server/pm/
--- PackageManagerService.java
frameworks/base/core/java/android/content/pm/
--- ActivityInfo.java
frameworks/base/core/java/android/app/
--- IActivityManager.java
--- ActivityManagerNative.java (內部包含AMP)
--- ActivityManager.java
--- AppGlobals.java
--- Activity.java
--- ActivityThread.java(內含AT)
--- LoadedApk.java
--- AppGlobals.java
--- Application.java
--- Instrumentation.java
--- IApplicationThread.java
--- ApplicationThreadNative.java (內部包含ATP)
--- ActivityThread.java (內含ApplicationThread)
--- ContextImpl.java
在正式開始今天部落格相關原始碼分析前,還是先奉上呼叫的時序圖以便小夥們先從整體上有個清晰的概括,然後再從細節開擼!
說實話,此處章節是我在將第二大章節寫了一大半情況下回過頭來撰寫的,因為如果這裡不將此處的知識點闡述清楚的話,感覺後面的章節沒有辦法進行!還記得我們在前面部落格Android四大元件之Activity啟動流程原始碼實現詳解概要的章節2.7中我們分析了ActivityRecord、TaskRecord、ActivityStack、ProcessRecord、ActivityStackSupervisor在整個Activity啟動的中的關係檢視,但是該示意圖是從整個AMS框架來說的,並且也只是介紹了一個大概。
今天我們先拋開AMS的整體不談,先談談ActivityRecord、TaskRecord、ActivityStack這三個類之間的關聯,因為本篇的原始碼分析將會重點涉及到這三者,所以要先弄明白幾個重要的類及概念(ActivityRecord在前面的部落格Android四大元件之Activity啟動流程原始碼實現詳解(一)已經有分析過了),所以在正式原始碼前我們先來看看另外兩者!
TaskRecord是用來管理ActivityRecord的容器資料結構,用於記錄該任務棧的activity開啟的先後順序,而TaskRecord對這些ActivityRecord的管理是以棧的形式來管理的,既然是棧那就肯定滿足後進先出的原則!TaskRecord管理的ActivityRecord不一定都屬於同一個App程序,這個需要根據實際情況來判定(這個從我們的最上面的示意圖也可以看到)!
//[TaskRecord.java]
final class TaskRecord {
final int taskId; // 任務ID
String affinity; // 是指root activity的affinity,即該Task中第一個Activity
String rootAffinity; //
Intent intent; // 最開始建立該Task的intent
int userId; // 記錄建立該Task的使用者id
final ArrayList<ActivityRecord> mActivities;//使用一個ArrayList來儲存所有的管理的ActivityRecord
String mCallingPackage;//呼叫者包名
ActivityStack stack;//TaskRecord所在的ActivityStack
final ActivityManagerService mService;//AMS的
//新增Activity到Task棧頂部
void addActivityToTop(ActivityRecord r) {
addActivityAtIndex(mActivities.size(), r);
}
//新增Activity到指定的索引位置
void addActivityAtIndex(int index, ActivityRecord r) {
...
}
//獲取根ActivityRecord的intent資訊
Intent getBaseIntent() {
return intent != null ? intent : affinityIntent;
}
//獲取根ActivityRecord,即Task棧底的ActivityRecord(因為它是後進先出)
ActivityRecord getRootActivity() {
for (int i = 0; i < mActivities.size(); i++) {
final ActivityRecord r = mActivities.get(i);
if (r.finishing) {
continue;
}
return r;
}
return null;
}
//獲取棧頂ActivityRecord
ActivityRecord getTopActivity() {
for (int i = mActivities.size() - 1; i >= 0; --i) {
final ActivityRecord r = mActivities.get(i);
if (r.finishing) {
continue;
}
return r;
}
return null;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(128);
if (stringName != null) {
sb.append(stringName);
sb.append(" U=");
sb.append(userId);
sb.append(" StackId=");
sb.append(stack != null ? stack.mStackId : INVALID_STACK_ID);
sb.append(" sz=");
sb.append(mActivities.size());
sb.append('}');
return sb.toString();
}
sb.append("TaskRecord{");
sb.append(Integer.toHexString(System.identityHashCode(this)));
sb.append(" #");
sb.append(taskId);
if (affinity != null) {
sb.append(" A=");
sb.append(affinity);
} else if (intent != null) {
sb.append(" I=");
sb.append(intent.getComponent().flattenToShortString());
} else if (affinityIntent != null) {
sb.append(" aI=");
sb.append(affinityIntent.getComponent().flattenToShortString());
} else {
sb.append(" ??");
}
stringName = sb.toString();
return toString();
}
}
有了前面的分析,我們來實際看看TaskRecord的資料情況,而恰好Android為我們提供了一個很好的命令dumpsy可以讓我們洞察一切,通過dump可以看到此時存在有八個TaskRecord!
XXX:/ # dumpsys activity | grep TaskRecord
* Recent #0: TaskRecord{b80c4da #80 A=com.android.launcher3 U=0 StackId=0 sz=1}
* Recent #1: TaskRecord{c6a6d0b #1 I=com.android.settings/.FallbackHome U=0 StackId=-1 sz=0}
* Recent #2: TaskRecord{80bf7e8 #79 A=com.android.settings U=0 StackId=-1 sz=0}
* Recent #3: TaskRecord{8116e01 #77 A=com.android.calculator2 U=0 StackId=-1 sz=0}
* Recent #4: TaskRecord{4b654a6 #76 A=com.cyanogenmod.filemanager U=0 StackId=-1 sz=0}
* Recent #5: TaskRecord{dd0cee7 #75 A=org.codeaurora.gallery U=0 StackId=-1 sz=0}
* Recent #6: TaskRecord{e9caa94 #74 A=com.xxx.printtest U=0 StackId=-1 sz=0}
* Recent #7: TaskRecord{725e93d #44 I=com.android.settings/.Settings$DataUsageSummaryActivity U=0 StackId=-1 sz=0}
TaskRecord{b80c4da #80 A=com.android.launcher3 U=0 StackId=0 sz=1}
TaskRecord{b80c4da #80 A=com.android.launcher3 U=0 StackId=0 sz=1}
如果說TaskRecord是ActivityRecord的大管家,那麼ActivityStack則是TaskRecord大管家,即ActivityStack是用來管理TaskRecord一種結構容器。ActivityStack也是我們通常意義上所說的Activity棧,它存在如下的幾種的StackId(即我們可以把ActivityStack歸納為幾種情況),這個也可以通過前面1.1章節最後的列印看出來!
//【ActivityManager.java StackId]
public static class StackId {
public static final int INVALID_STACK_ID = -1;//非法stack ID.
public static final int FIRST_STATIC_STACK_ID = 0;
//Launcher的Activity以及recentsAPP
public static final int HOME_STACK_ID = FIRST_STATIC_STACK_ID;
//正常啟動Activity的所處的ActivityStack
public static final int FULLSCREEN_WORKSPACE_STACK_ID = 1;
public static final int FREEFORM_WORKSPACE_STACK_ID = FULLSCREEN_WORKSPACE_STACK_ID + 1;
public static final int DOCKED_STACK_ID = FREEFORM_WORKSPACE_STACK_ID + 1;//這個是分屏應用所處於的ActivityStack
public static final int PINNED_STACK_ID = DOCKED_STACK_ID + 1;//畫中畫模式
public static final int LAST_STATIC_STACK_ID = PINNED_STACK_ID;
public static final int FIRST_DYNAMIC_STACK_ID = LAST_STATIC_STACK_ID + 1;
}
接著繼續修理ActivityStack,把我的義大利炮拿出來朝著它狠狠的開炮!
//
final class ActivityStack {
...
//Activity狀態值,和Activity生命週期對應
enum ActivityState {
INITIALIZING,
RESUMED,
PAUSING,
PAUSED,
STOPPING,
STOPPED,
FINISHING,
DESTROYING,
DESTROYED
}
...
final ActivityManagerService mService;//AMS服務的參照
final WindowManagerService mWindowManager;//WMS服務的參照
//使用一個ArrayList來儲存TaskRecord
private final ArrayList<TaskRecord>mTaskHistory = new ArrayList<>();
//該Stack中正在pause的ActivityRecord
ActivityRecord mPausingActivity = null;
//個表示當前ActivityStack處於已經resumed的activity
ActivityRecord mResumedActivity = null;
//表示該Stack中最後被paused過程的activity
ActivityRecord mLastPausedActivity = null;
ActivityRecord mLastStartedActivity = null;
final int mStackId;//該Stack的身份ID
...
//在每個ActivityStack中儲存著一份所有的ActivityStack
ArrayList<ActivityStack> mStacks;
int mDisplayId;
//管理ActivityStack的的ASS的參照
final ActivityStackSupervisor mStackSupervisor;
//建立TakRecord,這個會在後面的部落格中呼叫到
TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
boolean toTop) {
//建立一個task
TaskRecord task = new TaskRecord(mService, taskId, info, intent, voiceSession,
voiceInteractor);
// add the task to stack first, mTaskPositioner might need the stack association
//將task新增到ActivityStack中去
addTask(task, toTop, "createTaskRecord");
final boolean isLockscreenShown = mService.mLockScreenShown == LOCK_SCREEN_SHOWN;
if (!layoutTaskInStack(task, info.windowLayout) && mBounds != null && task.isResizeable()
&& !isLockscreenShown) {
task.updateOverrideConfiguration(mBounds);
}
return task;
}
//新增TaskRecord
void addTask(final TaskRecord task, final boolean toTop, String reason) {
final ActivityStack prevStack = preAddTask(task, reason, toTop);
task.stack = this;
if (toTop) {
insertTaskAtTop(task, null);
} else {
mTaskHistory.add(0, task);
updateTaskMovement(task, false);
}
postAddTask(task, prevStack);
}
@Override
public String toString() {
return "ActivityStack{" + Integer.toHexString(System.identityHashCode(this))
+ " stackId=" + mStackId + ", " + mTaskHistory.size() + " tasks}";
}
..
}
通過前面的原始碼我們可以看到ActivityStack使用了一個ArrayList來儲存TaskRecord,另外,ActivityStack中還持有ActivityStackSupervisor物件的參照,這個是用來管理ActivityStacks的這裡就不過多介紹了,章節1.3會簡單介紹一下,後面會開闢一個專門的章節來分析這塊!
有了前面的分析,我們來實際看看ActivityStack的資料情況,而恰好Android為我們提供了一個很好的命令dumpsy可以讓我們洞察一切,通過dump可以看到此時存在一個ActivityStack!
XXX:/ # dumpsys activity | grep ActivityStack
mFocusedStack=ActivityStack{55a06c8 stackId=1, 5 tasks} mLastFocusedStack=ActivityStack{55a06c8 stackId=1, 5 tasks}
如果說ActivityStack則是TaskRecord大管家,那麼ActivityStackSupervisor則是ActivityStack大管家,即ActivityStackSupervisor是用來管理ActivityStack一種結構容器。
public final class ActivityStackSupervisor implements DisplayListener {
...
final ActivityManagerService mService;//AMS 範例物件的參照
private RecentTasks mRecentTasks;//管理RecentTasks
int mCurrentUser;//當前使用者
ActivityStack mHomeStack;//Home所屬Stack
ActivityStack mFocusedStack;//當前持有焦點的Stack
private ActivityStack mLastFocusedStack;//最後獲取焦點的stack,此時表示正在切換
//ActivityDisplay列表,以當前的displayid為key這個可以對應多種顯示裝置,我們這裡只考慮一種),以ActivityDisplay為value
private final SparseArray<ActivityDisplay> mActivityDisplays = new SparseArray<>();
private SparseArray<ActivityContainer> mActivityContainers = new SparseArray<>();//以mStackId為key
class ActivityDisplay {
int mDisplayId;
Display mDisplay;
DisplayInfo mDisplayInfo = new DisplayInfo();
final ArrayList<ActivityStack> mStacks = new ArrayList<>();
ActivityRecord mVisibleBehindActivity;
ActivityDisplay() {
}
...
}
...
}
這裡我們重點關注一下mHomeStack和mFocusedStack以及mLastFocusedStack,並且mActivityDisplays是通過displayid來區分當前顯示的ActivityStack的。
有了前面知識的鋪墊,我們這裡對AMS中牽涉的各種棧結構體的組成關係來簡單總結一下:
上述幾個之間的管理非常緊湊,可以通過正向連結串列和反向連結串列通過其中的一個點切入獲取到其它對應的關聯的結構,這個從後續分析的查詢複用ActivityRecord和Task以及Stack可以看出來
ActivityStackSupervisor.mActivityDisplays
---> ActivityDisplay.mStacks
---> ActivityStack.mTaskHistory
---> TaskRecord.mActivities
---> ActivityRecord
ActivityRecord.task
---> TaskRecord.stack
---> ActivityStack.mStackSupervisor
---> ActivityStackSupervisor
關於上述之間的關聯,小夥們可以使用命令dumpsys activity activities進行檢視,雖然這裡將貼出來會顯得很囉嗦,但是為了小夥們的學習我這裡也是拼了,因為這樣會更加的清晰明瞭!
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
Stack #1://非Launcher 所屬stack
mFullscreen=true
mBounds=null
Task id #93
mFullscreen=true
mBounds=null
mMinWidth=-1
mMinHeight=-1
mLastNonFullscreenBounds=null
* TaskRecord{8ff8ca9 #93 A=com.xxx.printtest U=0 StackId=1 sz=2}
userId=0 effectiveUid=1000 mCallingUid=u0a23 mUserSetupComplete=true mCallingPackage=com.android.launcher3
affinity=com.xxx.printtest
intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.xxx.printtest/com.example.api.aidl.AidlActivity}
realActivity=com.xxx.printtest/com.example.api.aidl.AidlActivity
autoRemoveRecents=false isPersistable=true numFullscreen=2 taskType=0 mTaskToReturnTo=1
rootWasReset=true mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
Activities=[ActivityRecord{7fdb96 u0 com.xxx.printtest/com.example.api.aidl.AidlActivity t93}, ActivityRecord{1e413b8 u0 com.android.settings/.Settings$WifiSettingsActivity t93}]
askedCompatMode=false inRecents=true isAvailable=true
lastThumbnail=null lastThumbnailFile=/data/system_ce/0/recent_images/93_task_thumbnail.png
stackId=1
hasBeenVisible=true mResizeMode=RESIZE_MODE_FORCE_RESIZEABLE isResizeable=true firstActiveTime=1601259811494 lastActiveTime=1601259811494 (inactive for 146s)
* Hist #1: ActivityRecord{1e413b8 u0 com.android.settings/.Settings$WifiSettingsActivity t93}
packageName=com.android.settings processName=com.android.settings
launchedFromUid=1000 launchedFromPackage=com.xxx.printtest userId=0
app=ProcessRecord{dff00ef 5009:com.android.settings/1000}
Intent { cmp=com.android.settings/.Settings$WifiSettingsActivity }
frontOfTask=false task=TaskRecord{8ff8ca9 #93 A=com.xxx.printtest U=0 StackId=1 sz=2}
taskAffinity=null
realActivity=com.android.settings/.Settings$WifiSettingsActivity
baseDir=/system/priv-app/xxxSettings/xxxSettings.apk
dataDir=/data/user_de/0/com.android.settings
stateNotNeeded=false componentSpecified=true mActivityType=0
compat={320dpi} labelRes=0x7f0e03bc icon=0x7f02010f theme=0x7f1001fc
config={1.0 ?mcc?mnc [zh_CN] ldltr sw360dp w360dp h568dp 320dpi nrml port finger -keyb/v/h -nav/h s.5}
taskConfigOverride={1.0 ?mcc?mnc ?localeList ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/?}
taskDescription: iconFilename=null label="null" color=ff263238
launchFailed=false launchCount=0 lastLaunchTime=-3m26s393ms
haveState=true icicle=Bundle[mParcelledData.dataSize=3884]
state=STOPPED stopped=true delayedResume=false finishing=false
keysPaused=false inHistory=true visible=true sleeping=true idle=true mStartingWindowState=STARTING_WINDOW_SHOWN
fullscreen=true noDisplay=false immersive=false launchMode=0
frozenBeforeDestroy=false forceNewConfig=false
mActivityType=APPLICATION_ACTIVITY_TYPE
waitingVisible=false nowVisible=true lastVisibleTime=-3m25s977ms
resizeMode=RESIZE_MODE_RESIZEABLE
* Hist #0: ActivityRecord{7fdb96 u0 com.xxx.printtest/com.example.api.aidl.AidlActivity t93}
packageName=com.xxx.printtest processName=com.xxx.printtest
launchedFromUid=10023 launchedFromPackage=com.android.launcher3 userId=0
app=ProcessRecord{560922e 5935:com.xxx.printtest/1000}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.xxx.printtest/com.example.api.aidl.AidlActivity bnds=[536,356][712,544] }
frontOfTask=true task=TaskRecord{8ff8ca9 #93 A=com.xxx.printtest U=0 StackId=1 sz=2}
taskAffinity=com.xxx.printtest
realActivity=com.xxx.printtest/com.example.api.aidl.AidlActivity
baseDir=/data/app/com.xxx.printtest-1/base.apk
dataDir=/data/user/0/com.xxx.printtest
stateNotNeeded=false componentSpecified=true mActivityType=0
compat={320dpi} labelRes=0x7f060000 icon=0x7f020003 theme=0x7f070001
config={1.0 ?mcc?mnc [zh_CN] ldltr sw360dp w360dp h568dp 320dpi nrml port finger -keyb/v/h -nav/h s.5}
taskConfigOverride={1.0 ?mcc?mnc ?localeList ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/?}
taskDescription: iconFilename=null label="null" color=ffe6e6e6
launchFailed=false launchCount=0 lastLaunchTime=-3m26s707ms
haveState=true icicle=Bundle[mParcelledData.dataSize=1904]
state=STOPPED stopped=true delayedResume=false finishing=false
keysPaused=false inHistory=true visible=false sleeping=true idle=true mStartingWindowState=STARTING_WINDOW_SHOWN
fullscreen=true noDisplay=false immersive=false launchMode=2
frozenBeforeDestroy=false forceNewConfig=false
mActivityType=APPLICATION_ACTIVITY_TYPE
resizeMode=RESIZE_MODE_FORCE_RESIZEABLE
Task id #92
mFullscreen=true
mBounds=null
mMinWidth=-1
mMinHeight=-1
mLastNonFullscreenBounds=null
* TaskRecord{43c71cf #92 A=com.android.calculator2 U=0 StackId=1 sz=1}
userId=0 effectiveUid=1000 mCallingUid=u0a23 mUserSetupComplete=true mCallingPackage=com.android.launcher3
affinity=com.android.calculator2
intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.android.calculator2/.Calculator}
realActivity=com.android.calculator2/.Calculator
autoRemoveRecents=false isPersistable=true numFullscreen=1 taskType=0 mTaskToReturnTo=1
rootWasReset=true mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
Activities=[ActivityRecord{95535d3 u0 com.android.calculator2/.Calculator t92}]
askedCompatMode=false inRecents=true isAvailable=true
lastThumbnail=android.graphics.Bitmap@d83b75c lastThumbnailFile=/data/system_ce/0/recent_images/92_task_thumbnail.png
stackId=1
hasBeenVisible=true mResizeMode=RESIZE_MODE_RESIZEABLE isResizeable=true firstActiveTime=1601259750045 lastActiveTime=1601259750045 (inactive for 207s)
* Hist #0: ActivityRecord{95535d3 u0 com.android.calculator2/.Calculator t92}
packageName=com.android.calculator2 processName=com.android.calculator2
launchedFromUid=10023 launchedFromPackage=com.android.launcher3 userId=0
app=ProcessRecord{1b4a65 6710:com.android.calculator2/1000}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.android.calculator2/.Calculator bnds=[8,168][184,356] }
frontOfTask=true task=TaskRecord{43c71cf #92 A=com.android.calculator2 U=0 StackId=1 sz=1}
taskAffinity=com.android.calculator2
realActivity=com.android.calculator2/.Calculator
baseDir=/system/app/Calculator/Calculator.apk
dataDir=/data/user/0/com.android.calculator2
stateNotNeeded=false componentSpecified=true mActivityType=0
compat={320dpi} labelRes=0x7f08000d icon=0x7f030000 theme=0x7f090000
config={1.0 ?mcc?mnc [zh_CN] ldltr sw360dp w360dp h568dp 320dpi nrml port finger -keyb/v/h -nav/h s.5}
taskConfigOverride={1.0 ?mcc?mnc ?localeList ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/?}
taskDescription: iconFilename=null label="null" color=ff00bcd4
launchFailed=false launchCount=0 lastLaunchTime=-3m29s475ms
haveState=true icicle=Bundle[mParcelledData.dataSize=3248]
state=STOPPED stopped=true delayedResume=false finishing=false
keysPaused=false inHistory=true visible=false sleeping=true idle=true mStartingWindowState=STARTING_WINDOW_SHOWN
fullscreen=true noDisplay=false immersive=false launchMode=0
frozenBeforeDestroy=false forceNewConfig=false
mActivityType=APPLICATION_ACTIVITY_TYPE
waitingVisible=false nowVisible=false lastVisibleTime=-3m28s736ms
resizeMode=RESIZE_MODE_RESIZEABLE
Task id #91
mFullscreen=true
mBounds=null
mMinWidth=-1
mMinHeight=-1
mLastNonFullscreenBounds=null
* TaskRecord{b67a33a #91 A=com.cyanogenmod.filemanager U=0 StackId=1 sz=1}
userId=0 effectiveUid=u0a21 mCallingUid=u0a23 mUserSetupComplete=true mCallingPackage=com.android.launcher3
affinity=com.cyanogenmod.filemanager
intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.cyanogenmod.filemanager/.activities.NavigationActivity}
realActivity=com.cyanogenmod.filemanager/.activities.NavigationActivity
autoRemoveRecents=false isPersistable=true numFullscreen=1 taskType=0 mTaskToReturnTo=1
rootWasReset=true mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
Activities=[ActivityRecord{fb787b9 u0 com.cyanogenmod.filemanager/.activities.NavigationActivity t91}]
askedCompatMode=false inRecents=true isAvailable=true
lastThumbnail=android.graphics.Bitmap@7b85beb lastThumbnailFile=/data/system_ce/0/recent_images/91_task_thumbnail.png
stackId=1
hasBeenVisible=true mResizeMode=RESIZE_MODE_UNRESIZEABLE isResizeable=false firstActiveTime=1601259747267 lastActiveTime=1601259747267 (inactive for 210s)
* Hist #0: ActivityRecord{fb787b9 u0 com.cyanogenmod.filemanager/.activities.NavigationActivity t91}
packageName=com.cyanogenmod.filemanager processName=com.cyanogenmod.filemanager
launchedFromUid=10023 launchedFromPackage=com.android.launcher3 userId=0
app=ProcessRecord{842ed48 6669:com.cyanogenmod.filemanager/u0a21}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.cyanogenmod.filemanager/.activities.NavigationActivity bnds=[536,168][712,356] }
frontOfTask=true task=TaskRecord{b67a33a #91 A=com.cyanogenmod.filemanager U=0 StackId=1 sz=1}
taskAffinity=com.cyanogenmod.filemanager
realActivity=com.cyanogenmod.filemanager/.activities.NavigationActivity
baseDir=/system/app/CMFileManager/CMFileManager.apk
dataDir=/data/user/0/com.cyanogenmod.filemanager
stateNotNeeded=false componentSpecified=true mActivityType=0
compat={320dpi} labelRes=0x7f0c0008 icon=0x7f020062 theme=0x7f0e0000
config={1.0 ?mcc?mnc [zh_CN] ldltr sw360dp w360dp h568dp 320dpi nrml port finger -keyb/v/h -nav/h s.5}
taskConfigOverride={1.0 ?mcc?mnc ?localeList ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/?}
taskDescription: iconFilename=null label="null" color=ff1e88e5
launchFailed=false launchCount=0 lastLaunchTime=-3m32s523ms
haveState=true icicle=Bundle[mParcelledData.dataSize=5784]
state=STOPPED stopped=true delayedResume=false finishing=false
keysPaused=false inHistory=true visible=false sleeping=true idle=true mStartingWindowState=STARTING_WINDOW_SHOWN
fullscreen=true noDisplay=false immersive=false launchMode=1
frozenBeforeDestroy=false forceNewConfig=false
mActivityType=APPLICATION_ACTIVITY_TYPE
waitingVisible=false nowVisible=false lastVisibleTime=-3m31s514ms
resizeMode=RESIZE_MODE_UNRESIZEABLE
Task id #90
mFullscreen=true
mBounds=null
mMinWidth=-1
mMinHeight=-1
mLastNonFullscreenBounds=null
* TaskRecord{67b27e1 #90 A=org.codeaurora.gallery U=0 StackId=1 sz=1}
userId=0 effectiveUid=u0a13 mCallingUid=u0a23 mUserSetupComplete=true mCallingPackage=com.android.launcher3
affinity=org.codeaurora.gallery
intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity}
realActivity=org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity
autoRemoveRecents=false isPersistable=true numFullscreen=1 taskType=0 mTaskToReturnTo=1
rootWasReset=true mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
Activities=[ActivityRecord{5b27720 u0 org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity t90}]
askedCompatMode=false inRecents=true isAvailable=true
lastThumbnail=android.graphics.Bitmap@19cb906 lastThumbnailFile=/data/system_ce/0/recent_images/90_task_thumbnail.png
stackId=1
hasBeenVisible=true mResizeMode=RESIZE_MODE_FORCE_RESIZEABLE isResizeable=true firstActiveTime=1601259744095 lastActiveTime=1601259744095 (inactive for 213s)
* Hist #0: ActivityRecord{5b27720 u0 org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity t90}
packageName=org.codeaurora.gallery processName=org.codeaurora.gallery
launchedFromUid=10023 launchedFromPackage=com.android.launcher3 userId=0
app=ProcessRecord{638c64d 6614:org.codeaurora.gallery/u0a13}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity bnds=[360,168][536,356] }
frontOfTask=true task=TaskRecord{67b27e1 #90 A=org.codeaurora.gallery U=0 StackId=1 sz=1}
taskAffinity=org.codeaurora.gallery
realActivity=org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity
baseDir=/system/priv-app/SnapdragonGallery/SnapdragonGallery.apk
dataDir=/data/user/0/org.codeaurora.gallery
stateNotNeeded=false componentSpecified=true mActivityType=0
compat={320dpi} labelRes=0x7f0b00f1 icon=0x7f030001 theme=0x7f100035
config={1.0 ?mcc?mnc [zh_CN] ldltr sw360dp w360dp h568dp 320dpi nrml port finger -keyb/v/h -nav/h s.5}
taskConfigOverride={1.0 ?mcc?mnc ?localeList ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/?}
taskDescription: iconFilename=null label="null" color=fff5f5f5
launchFailed=false launchCount=0 lastLaunchTime=-3m35s517ms
haveState=true icicle=Bundle[mParcelledData.dataSize=1556]
state=STOPPED stopped=true delayedResume=false finishing=false
keysPaused=false inHistory=true visible=false sleeping=true idle=true mStartingWindowState=STARTING_WINDOW_SHOWN
fullscreen=true noDisplay=false immersive=false launchMode=0
frozenBeforeDestroy=false forceNewConfig=false
mActivityType=APPLICATION_ACTIVITY_TYPE
waitingVisible=false nowVisible=false lastVisibleTime=-3m34s781ms
connections=[ConnectionRecord{f29be13 u0 CR org.codeaurora.gallery/com.android.gallery3d.app.BatchService:@f261502}]
resizeMode=RESIZE_MODE_FORCE_RESIZEABLE
Running activities (most recent first):
TaskRecord{8ff8ca9 #93 A=com.xxx.printtest U=0 StackId=1 sz=2}
Run #4: ActivityRecord{1e413b8 u0 com.android.settings/.Settings$WifiSettingsActivity t93}
Run #3: ActivityRecord{7fdb96 u0 com.xxx.printtest/com.example.api.aidl.AidlActivity t93}
TaskRecord{43c71cf #92 A=com.android.calculator2 U=0 StackId=1 sz=1}
Run #2: ActivityRecord{95535d3 u0 com.android.calculator2/.Calculator t92}
TaskRecord{b67a33a #91 A=com.cyanogenmod.filemanager U=0 StackId=1 sz=1}
Run #1: ActivityRecord{fb787b9 u0 com.cyanogenmod.filemanager/.activities.NavigationActivity t91}
TaskRecord{67b27e1 #90 A=org.codeaurora.gallery U=0 StackId=1 sz=1}
Run #0: ActivityRecord{5b27720 u0 org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity t90}
mLastPausedActivity: ActivityRecord{1e413b8 u0 com.android.settings/.Settings$WifiSettingsActivity t93}
Stack #0://表示的是Launcher所屬的Stack
mFullscreen=true
mBounds=null
Task id #88
mFullscreen=true
mBounds=null
mMinWidth=-1
mMinHeight=-1
mLastNonFullscreenBounds=null
* TaskRecord{a9ad0b9 #88 A=com.android.launcher3 U=0 StackId=0 sz=1}
userId=0 effectiveUid=u0a23 mCallingUid=1000 mUserSetupComplete=true mCallingPackage=android
affinity=com.android.launcher3
intent={act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.launcher3/.Launcher}
realActivity=com.android.launcher3/.Launcher
autoRemoveRecents=false isPersistable=true numFullscreen=1 taskType=1 mTaskToReturnTo=0
rootWasReset=false mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
Activities=[ActivityRecord{9997f10 u0 com.android.launcher3/.Launcher t88}]
askedCompatMode=false inRecents=true isAvailable=true
lastThumbnail=null lastThumbnailFile=/data/system_ce/0/recent_images/88_task_thumbnail.png
stackId=0
hasBeenVisible=true mResizeMode=RESIZE_MODE_FORCE_RESIZEABLE isResizeable=false firstActiveTime=1601259751033 lastActiveTime=1601259751033 (inactive for 206s)
* Hist #0: ActivityRecord{9997f10 u0 com.android.launcher3/.Launcher t88}
packageName=com.android.launcher3 processName=com.android.launcher3
launchedFromUid=0 launchedFromPackage=null userId=0
app=ProcessRecord{7996cfe 5669:com.android.launcher3/u0a23}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.launcher3/.Launcher }
frontOfTask=true task=TaskRecord{a9ad0b9 #88 A=com.android.launcher3 U=0 StackId=0 sz=1}
taskAffinity=com.android.launcher3
realActivity=com.android.launcher3/.Launcher
baseDir=/system/app/xxxLauncher3/xxxLauncher3.apk
dataDir=/data/user/0/com.android.launcher3
stateNotNeeded=true componentSpecified=false mActivityType=1
compat={320dpi} labelRes=0x7f0a0001 icon=0x7f030001 theme=0x7f0d0002
config={1.0 ?mcc?mnc [zh_CN] ldltr sw360dp w360dp h568dp 320dpi nrml port finger -keyb/v/h -nav/h s.5}
taskConfigOverride={1.0 ?mcc?mnc ?localeList ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/?}
taskDescription: iconFilename=null label="null" color=ff222222
launchFailed=false launchCount=0 lastLaunchTime=-42m49s20ms
haveState=true icicle=Bundle[mParcelledData.dataSize=3940]
state=STOPPED stopped=true delayedResume=false finishing=false
keysPaused=false inHistory=true visible=false sleeping=true idle=true mStartingWindowState=STARTING_WINDOW_NOT_SHOWN
fullscreen=true noDisplay=false immersive=false launchMode=2
frozenBeforeDestroy=false forceNewConfig=false
mActivityType=HOME_ACTIVITY_TYPE
waitingVisible=false nowVisible=false lastVisibleTime=-3m27s126ms
resizeMode=RESIZE_MODE_FORCE_RESIZEABLE
Running activities (most recent first):
TaskRecord{a9ad0b9 #88 A=com.android.launcher3 U=0 StackId=0 sz=1}
Run #0: ActivityRecord{9997f10 u0 com.android.launcher3/.Launcher t88}
mLastPausedActivity: ActivityRecord{9997f10 u0 com.android.launcher3/.Launcher t88}
mFocusedActivity: ActivityRecord{1e413b8 u0 com.android.settings/.Settings$WifiSettingsActivity t93}
mFocusedStack=ActivityStack{becbc7 stackId=1, 4 tasks} mLastFocusedStack=ActivityStack{becbc7 stackId=1, 4 tasks}
mSleepTimeout=false
mCurTaskIdForUser={0=93}
mUserStackInFront={}
mActivityContainers={0=ActivtyContainer{0}A, 1=ActivtyContainer{1}A}
mLockTaskModeState=NONE mLockTaskPackages (userId:packages)=
0:[]
mLockTaskModeTasks[]
接著我們前面部落格Android四大元件之Activity啟動流程原始碼實現詳解(一)未完成之使命,繼續分析AS.startActivityLocked方法。在正式分析之前,我要在此提前打一個預防針,這是因為該方法涉及的知識點非常多,並且程式碼也很多,所以各位小夥們一定打起精神一鼓作氣的將其拿下來(當然小夥們也可以拋開此章節,直接進入第三大章節分析後面的流程,因為這個並不影響Activity啟動的整體流程分析)!
startActivityLocked方法主要從程式碼邏輯上可以分為兩大部分來闡述:
本大章節將重點分析第一大部分內容,不要問我有多少,我只能說很多很多!
//[ActivityStarter.java]
/* 這裡的sourceRecord是指發起呼叫者
r是指本次的將要啟動的Activity,startFlags取值為0,
doResume的值為true
*/
private int startActivityUnchecked(final ActivityRecord r,
ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession,
IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume,
ActivityOptions options,
TaskRecord inTask) {
//初始化Activity啟動的一些狀態,這裡主要是根據啟動模式的相關設定進行了一些變數的處理。比如newtask,document等等
//初始化Activity啟動狀態,獲取launchmode flag 同時解決一些falg和launchmode的衝突
setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
voiceInteractor);//詳見章節2.1
//計算目標Activity的launchMode模式
computeLaunchingTaskFlags();//詳見章節2.2
//確定發起端的ActivityStack情況
computeSourceStack();//詳見章節1.3
mIntent.setFlags(mLaunchFlags);//把前面解析得到的mLaunchFlags,設定目標Activity的launchMode啟動模式
// 根據mLaunchFlags來查詢是否有可重用的activity
/**
* 這邊主要是判斷當前啟動的Activity是否存在可以利用的Task
* 當啟動模式launchMode為singleTask、singleInstance,或者啟動時
* Flag設定為FLAG_ACTIVITY_NEW_TASK並沒設定FLAG_ACTIVITY_MULTIPLE_TASK
* 並且當前啟動的Activity不是以startActivityForResult啟動的,
* 滿足以上情況才會尋找是否存在有複用的Task。
* 匹配規則:
* 1、對於啟動模式為singleInstance,遍歷所有ActivityStack和Task的堆疊中查詢
*是否存在以當前啟動Activity相同的Activity。
* 2、其它情況下,遍歷所有ActivityStack和Task的堆疊,查詢Task中intent變數
*是否當前啟動Activity相匹配,如果不存在,則去匹配task的親和性(即
*在AndroidManifest中android:taskAffinity定義的。
*/
mReusedActivity = getReusableIntentActivity();//詳見2.4
final int preferredLaunchStackId =
(mOptions != null) ? mOptions.getLaunchStackId() : INVALID_STACK_ID;//此時mOptions為null
//如果找到了可重用的activity,需要清理掉原來的資訊,並把當前啟動的activity的資訊拷貝進去
//做清理和拷貝工作...
if (mReusedActivity != null) {//詳見章節2.5
...
//設定當前啟動Activity的Task為複用的Task
if (mStartActivity.task == null) {
mStartActivity.task = mReusedActivity.task;
}
if (mReusedActivity.task.intent == null) {
mReusedActivity.task.setIntent(mStartActivity);
}
/*
*這邊處理啟動時設定FLAG_ACTIVITY_CLEAR_TOP時,要清除複用Task中存在與當前啟動
*Activity相同的Activity之上的Activity
*舉個例子:比如複用Task1中存在有Activity A,B,C,D,此時正在啟動的Activity B,那麼C**和D也要finish,另外此時如果B *為標準啟動模式,並且沒有設定FLAG_ACTIVITY_SINGLE_TOP,那麼B也會finish。具體的讀者可以跟進
*mReusedActivity.task.performClearTaskForReuseLocked看下。
*/
if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| mLaunchSingleInstance || mLaunchSingleTask) {
final ActivityRecord top = mReusedActivity.task.performClearTaskForReuseLocked(
mStartActivity, mLaunchFlags);
if (top != null) {
if (top.frontOfTask) {
top.task.setIntent(mStartActivity);
}
ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task);
// 沒必要新建範例,回撥onNewIntent並將top移至前臺
top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
mStartActivity.launchedFromPackage);
}
}
// 計算哪個task和activity要移至前臺,必要時會進行task的清理工作
mReusedActivity = setTargetStackAndMoveToFrontIfNeeded(mReusedActivity);
if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
resumeTargetStackIfNeeded();
return START_RETURN_INTENT_TO_CALLER;
}
//根據複用情況設定task
setTaskFromIntentActivity(mReusedActivity);
//mAddingToTask為true表示要新建,mReuseTask為空表示task被清除了
if (!mAddingToTask && mReuseTask == null) {
resumeTargetStackIfNeeded();
return START_TASK_TO_FRONT;
}
}
if (mStartActivity.packageName == null) {
if (mStartActivity.resultTo != null && mStartActivity.resultTo.task.stack != null) {
mStartActivity.resultTo.task.stack.sendActivityResultLocked(
-1, mStartActivity.resultTo, mStartActivity.resultWho,
mStartActivity.requestCode, RESULT_CANCELED, null);
}
ActivityOptions.abort(mOptions);
return START_CLASS_NOT_FOUND;
}
final ActivityStack topStack = mSupervisor.mFocusedStack;
final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
final boolean dontStart = top != null && mStartActivity.resultTo == null
&& top.realActivity.equals(mStartActivity.realActivity)
&& top.userId == mStartActivity.userId
&& top.app != null && top.app.thread != null
&& ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
|| mLaunchSingleTop || mLaunchSingleTask);
if (dontStart) {
ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
topStack.mLastPausedActivity = null;
if (mDoResume) {
mSupervisor.resumeFocusedStackTopActivityLocked();
}
ActivityOptions.abort(mOptions);
if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
return START_RETURN_INTENT_TO_CALLER;
}
top.deliverNewIntentLocked(
mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
mSupervisor.handleNonResizableTaskIfNeeded(
top.task, preferredLaunchStackId, topStack.mStackId);
return START_DELIVERED_TO_TOP;
}
boolean newTask = false;
final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
? mSourceRecord.task : null;
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
newTask = true;
// 重用或者新建task
setTaskFromReuseOrCreateNewTask(taskToAffiliate);
if (mSupervisor.isLockTaskModeViolation(mStartActivity.task)) {
Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
return START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
if (!mMovedOtherTask) {
updateTaskReturnToType(mStartActivity.task, mLaunchFlags, topStack);
}
} else if (mSourceRecord != null) {
if (mSupervisor.isLockTaskModeViolation(mSourceRecord.task)) {
Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
return START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
// 不是新建task的,重用原activity的task
final int result = setTaskFromSourceRecord();
if (result != START_SUCCESS) {
return result;
}
} else if (mInTask != null) {
if (mSupervisor.isLockTaskModeViolation(mInTask)) {
Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
return START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
final int result = setTaskFromInTask();
if (result != START_SUCCESS) {
return result;
}
} else {
setTaskToCurrentTopOrCreateNewTask();
}
mService.grantUriPermissionFromIntentLocked(mCallingUid, mStartActivity.packageName,
mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId);
if (mSourceRecord != null && mSourceRecord.isRecentsActivity()) {
mStartActivity.task.setTaskToReturnTo(RECENTS_ACTIVITY_TYPE);
}
if (newTask) {
EventLog.writeEvent(
EventLogTags.AM_CREATE_TASK, mStartActivity.userId, mStartActivity.task.taskId);
}
ActivityStack.logStartActivity(
EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.task);
mTargetStack.mLastPausedActivity = null;
/*把當前啟動的Activity加入TaskRecord以及繫結WindowManagerService*/
mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);
...
return START_SUCCESS;
}
該部分程式碼很長,很長!但是沒有辦法,閱讀原始碼就是這麼操蛋,我們只能一步步分解,強行分析了!
//[ActivityStarter.java]
private void setInitialState(ActivityRecord r,//表示要啟動的目標Activity資訊
ActivityOptions options, //options是附件資訊,此時為null
TaskRecord inTask,
boolean doResume, //此處的doResume的值為true
int startFlags, //這裡傳入的startFlags為0
ActivityRecord sourceRecord,//發起端的Activity資訊
IVoiceInteractionSession voiceSession,
IVoiceInteractor voiceInteractor) {
reset();//對所有變數進行重置
mStartActivity = r;//將要啟動的目標Activiyt資訊賦值給mStartActivity
mIntent = r.intent;
mOptions = options;
mCallingUid = r.launchedFromUid;
mSourceRecord = sourceRecord;
mVoiceSession = voiceSession;
mVoiceInteractor = voiceInteractor;
mLaunchBounds = getOverrideBounds(r, options, inTask);
//讀取目標Activity的launchMode資訊
mLaunchSingleTop = r.launchMode == LAUNCH_SINGLE_TOP;
mLaunchSingleInstance = r.launchMode == LAUNCH_SINGLE_INSTANCE;
mLaunchSingleTask = r.launchMode == LAUNCH_SINGLE_TASK;
/*這裡會根據啟動模式來調整flag到NEW_DOCUMEN 如果intent中的和mainfest中的衝突,那麼manfest的啟動模式優先
*FLAG_ACTIVITY_NEW_DOCUMENT是開啟一個檔案的標識
*其處理流程遵循如下邏輯:
*1、如果此Activity是由singleInstance或者singleTask的話且flag帶了NEW_DOCUMENT,則需要去掉
*NEW_DOCUMENT和MULTIPLE_TASK的flag
*2、如果不屬於第一種情況則讀取ActivityInfo中的documentLaunchMode來對flag賦值
*/
mLaunchFlags = adjustLaunchFlagsToDocumentMode(
r, mLaunchSingleInstance, mLaunchSingleTask, mIntent.getFlags());
mLaunchTaskBehind = r.mLaunchTaskBehind
&& !mLaunchSingleTask && !mLaunchSingleInstance
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0;
/*如果是newTask的啟動模式,那麼會將resultTo設定為null。
*這裡做了一個處理。這個活動被啟動到一個新的任務中,而且還需要得到請求結果。
*那麼,這是相當混亂的,因此,立即傳送回一個取消,讓新的任務繼續啟動像往常一樣,不依賴於它的發起者
*也就是newTask的啟動模式,是無法獲取到請求結果的*/
sendNewTaskResultRequestIfNeeded();
//如果設定了NEW_DOCUMENT標誌同時此Activity不是其他Activity啟動的
//則在加上NEW_TASK的標誌
if ((mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}
if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
if (mLaunchTaskBehind
|| r.info.documentLaunchMode == DOCUMENT_LAUNCH_ALWAYS) {
mLaunchFlags |= FLAG_ACTIVITY_MULTIPLE_TASK;
}
}
mSupervisor.mUserLeaving = (mLaunchFlags & FLAG_ACTIVITY_NO_USER_ACTION) == 0;
mDoResume = doResume;//此時的doReume為true所以不會走入此分支
//當本次不需要resume時,則設定為延遲resume的狀態
if (!doResume || !mSupervisor.okToShowLocked(r)) {
r.delayedResume = true;
mDoResume = false;
}
//此時mOptions為null不會走入此分支
if (mOptions != null && mOptions.getLaunchTaskId() != -1 && mOptions.getTaskOverlay()) {
r.mTaskOverlay = true;
final TaskRecord task = mSupervisor.anyTaskForIdLocked(mOptions.getLaunchTaskId());
final ActivityRecord top = task != null ? task.getTopActivity() : null;
if (top != null && !top.visible) {
mDoResume = false;
mAvoidMoveToFront = true;
}
}
/**FLAG_ACTIVITY_PREVIOUS_IS_TOP:
*如果給Intent物件設定了這個標記,這個Intent物件被用於從一個存在的Activity中啟動一個新的Activity,
*那麼新的這個 Activity不能用於接受傳送給頂層activity的intent,這個新的activity的前一個activity被作為頂部activity
*如果設定FLAG_ACTIVITY_PREVIOUS_IS_TOP,當前Activity不會作為棧頂來啟動新的Activity而是把當前Activity的前一個作為棧頂.簡而言之,棧ABC啟動D則棧變成ABD。所以sourceRecord設定為null
*/
mNotTop = (mLaunchFlags & FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
mInTask = inTask;
if (inTask != null && !inTask.inRecents) {
Slog.w(TAG, "Starting activity in task not in recents: " + inTask);
mInTask = null;
}
mStartFlags = startFlags;
//我們傳入的startFlags為0不會走入此分支
if ((startFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
ActivityRecord checkedCaller = sourceRecord;
if (checkedCaller == null) {
checkedCaller = mSupervisor.mFocusedStack.topRunningNonDelayedActivityLocked(
mNotTop);
}
if (!checkedCaller.realActivity.equals(r.realActivity)) {
//呼叫者 與將要啟動的Activity不相同時,進入該分支
mStartFlags &= ~START_FLAG_ONLY_IF_NEEDED;
}
}
//是否有動畫
mNoAnimation = (mLaunchFlags & FLAG_ACTIVITY_NO_ANIMATION) != 0;
}
在正式開始掰持掰持上述原始碼前,我們先來搗鼓搗鼓幾個概念,因為原始碼中會有涉及到,當然這部分知識我在部落格中Android四大元件之Activity啟動流程原始碼實現詳解概要也有提到過:
//[ActivityInfo.java]
public class ActivityInfo extends ComponentInfo
implements Parcelable {
...
public static final int LAUNCH_MULTIPLE = 0;
public static final int LAUNCH_SINGLE_TOP = 1;
public static final int LAUNCH_SINGLE_TASK = 2;
public static final int LAUNCH_SINGLE_INSTANCE = 3;
...
}
- LAUNCH_MULTIPLE(standard):每次啟動新Activity,都會建立新的Activity,這是最常見標準情形。
- LAUNCH_SINGLE_TOP(singleTop): 當啟動新Acitity,在棧頂存在相同Activity,則不會建立新Activity;其餘情況同上。
- LAUNCH_SINGLE_TASK(singleTask):當啟動新Acitity,在棧中存在相同Activity(可以是不在棧頂),則不會建立新Activity,而是移除該Activity之上的所有Activity;其餘情況同上。
- LAUNCH_SINGLE_INSTANCE(singleInstance):每個Task棧只有一個Activity,其餘情況同上。
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- FLAG_ACTIVITY_NEW_TASK:將Activity放入一個新啟動的Task。
- FLAG_ACTIVITY_CLEAR_TASK:啟動Activity時,將目標Activity關聯的Task清除,再啟動新Task,將該Activity放入該Task。該flags跟FLAG_ACTIVITY_NEW_TASK配合使用。
- FLAG_ACTIVITY_CLEAR_TOP:啟動非棧頂Activity時,先清除該Activity之上的Activity。例如Task已有A、B、C3個Activity,啟動A,則清除B,C。類似於SingleTop。
- FLAG_ACTIVITY_PREVIOUS_IS_TOP:如果給Intent物件設定了這個標記,這個Intent物件被用於從一個存在的Activity中啟動一個新的Activity,那麼新的這個 Activity不能用於接受傳送給頂層activity的intent,這個新的activity的前一個activity被作為頂部activity。
- START_FLAG_ONLY_IF_NEEDED:該flag表示只有在需要的時候才啟動目標Activity。也就是說如果呼叫者和被啟動的是一個,那麼就沒有必要去進行重複的步驟了
好了,讓我們來開始分析原始碼setInitialState方法的業務邏輯,主要就是進行一些初始化,如下:
是不是被1.1章節涉及到的概念整懵了,這還沒有完呢,又要開始了!這就是我所說的為啥說本大章節是Activity中最難突破的點,那也啥辦法呢只能一點點突破了!在正式開始該部分的原始碼分析前是時候放出看家法寶了(Android四大元件之Activity啟動流程原始碼實現詳解概要有簡單掰扯過)!
//[ActivityStarter.java]
/**
根據launchMode和Intent中的FLAG_ACTIVITY_NEW_TASK等flag綜合計算activity的啟動模式,
結果儲存在mLaunchFlags中。計算的過程不僅要考慮目標activity的launchMode,
也要考慮原來activity的launchMode和Intent中所帶著的flag
*/
private void computeLaunchingTaskFlags() {
//當呼叫者不是來自Activity,但是又明確指定指定了目標task執行該Activity的話,這個情況比較少見
if (mSourceRecord == null && mInTask != null && mInTask.stack != null) {
//查詢任務棧mInTask的intent資訊,
final Intent baseIntent = mInTask.getBaseIntent();
/*
TaskRecord由多個activityRecord組成,是我們平時所說的任務棧,
裡面包含著它所管理的activity列表(其中的關係詳見上述圖示)
這裡返回第一個沒有結束的activity
*/
final ActivityRecord root = mInTask.getRootActivity();
if (baseIntent == null) {
ActivityOptions.abort(mOptions);
throw new IllegalArgumentException("Launching into task without base intent: "
+ mInTask);
}
if (mLaunchSingleInstance || mLaunchSingleTask) {
/*
如果啟動模式是LAUNCH_SINGLE_INSTANCE或者LAUNCH_SINGLE_TASK,
那麼必須保證堆疊是他們所執行的堆疊,否則就丟擲異常
*/
if (!baseIntent.getComponent().equals(mStartActivity.intent.getComponent())) {
ActivityOptions.abort(mOptions);
throw new IllegalArgumentException("Trying to launch singleInstance/Task "
+ mStartActivity + " into different task " + mInTask);
}
if (root != null) {
ActivityOptions.abort(mOptions);
throw new IllegalArgumentException("Caller with mInTask " + mInTask
+ " has root " + root + " but target is singleInstance/Task");
}
}
/*
如果根部為空,說明裡面還沒有activity,可以把我們要啟動的activity作為它的rootTask啟動,
所以會對這個task做初始化操作
*/
if (root == null) {
final int flagsOfInterest = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK
| FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS;
mLaunchFlags = (mLaunchFlags & ~flagsOfInterest)
| (baseIntent.getFlags() & flagsOfInterest);
mIntent.setFlags(mLaunchFlags);
mInTask.setIntent(mStartActivity);
//mAddingToTask這個變數表示已經找到某個task來放置Activity,
//有可能是啟動時指定的task還有可能是啟動的sourceTask,反正就是不用再去遍歷尋找task
mAddingToTask = true;//標記是否增加到棧中
} else if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
//當前棧根部不為空,但是啟動模式是FLAG_ACTIVITY_NEW_TASK,那麼不需要新增新的activity,
//只要直接把當前task帶到前臺顯示即可,這個地方需要重點關注一下
mAddingToTask = false;
} else {
//不是一個空的task,並且也沒有設定FLAG_ACTIVITY_NEW_TASK啟動引數,所以需要新增一個activity到這個task中,設定 mAddingToTask = true
mAddingToTask = true;
}
//說明使用者指定的task是可用的,設定mReuseTask = mInTask
mReuseTask = mInTask;
} else {
mInTask = null;
/*
此時sourceRecord不為空或者使用者沒有指定mInTask。這種情況就需要設定mInTask為null,因為sourceRecord優先順序大於mInTask. 這個條件還對特殊情況做了處理,保證要啟動的activity儘量放到SourceRecord 之上
*/
if ((mStartActivity.isResolverActivity() || mStartActivity.noDisplay) && mSourceRecord != null
&& mSourceRecord.isFreeform()) {
mAddingToTask = true;
}
}
if (mInTask == null) {
if (mSourceRecord == null) {//未指定Task且沒有sourceRecord,//根據呼叫方和要啟動的activty的啟動模式來進行調整。將acitivty啟動模式調整為為newTask
//呼叫者並不是Activity context,則強制建立新task
if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && mInTask == null) {//如果其源任務棧也不存在,無法附加要啟動的activity到sourceRecord的task中,則強制新建Task
Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
"Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}
} else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
//發起呼叫者的Activity帶有single instance,這種activity只能自己獨自在一個task上,
//所以新啟動的activity也要新增FLAG_ACTIVITY_NEW_TASK引數,在新的task上啟動activity
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
} else if (mLaunchSingleInstance || mLaunchSingleTask) {
//目標Activity帶有single instance或者single task,則建立新task
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}
}
}
這細節分析起來的太操蛋了,太多細枝末節的東西了,看來Activity的TaskRecord的處理真的是一個難點啊!在computeLaunchingTaskFlags方法中根據發起端/目的端的launchMode和以及Intent中的FLAG_ACTIVITY_NEW_TASK等flag綜合計算activity的啟動模式,並且主要分了兩個大類情況來處理:
發起端的ActivityRecord資訊記錄為空,但是明確指定要啟動的Activity所在的任務棧
剩下的情況就是發起端的ActivityRecord資訊記錄不為空或者沒有指定mInTask。這種情況直接將指定的mInTask清空
上述操作猛如虎工資2500!當上述兩種情況處理完成以後,上述方法會進行一次判斷處理,如果指定執行的任務棧mInTask為空(包括沒有設定,或者後來清空),那麼會分情況對啟動標識進行調整:
分析至此我們可以得出一個結論就是computeLaunchingTaskFlags的主要功能就是根據發起端/目的端的launchMode和以及Intent中的攜帶的FLAG_ACTIVITY_NEW_TASK等flag綜合計算activity的啟動模式或者說調整啟動目標Activiyt的啟動模式。
//[ActivityStarter.java]
//確定發起端的Stack情況
private void computeSourceStack() {
if (mSourceRecord == null) {
mSourceStack = null;
return;
}
if (!mSourceRecord.finishing) {
//當呼叫者Activity不為空,且不處於finishing狀態,則其所在棧賦於sourceStack
mSourceStack = mSourceRecord.task.stack;
return;
}
//如果呼叫方已經finish了,那麼就無法將其作為我們的源任務棧了,這時候,要強行新增FLAG_ACTIVITY_NEW_TASK標誌使activity啟動到一個新的task中
if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0) {
Slog.w(TAG, "startActivity called from finishing " + mSourceRecord
+ "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
//儲存task的intent資訊和taskinfo資訊是為了新建task的時候嘗試恢復這個task
mNewTaskInfo = mSourceRecord.info;
mNewTaskIntent = mSourceRecord.task.intent;
}
mSourceRecord = null;
mSourceStack = null;
}
好傢伙嘛!終於來了一個簡單點的邏輯了,分為三部分處理:
//[ActivityStarter.java]
private ActivityRecord getReusableIntentActivity() {
/*
標識是否可以放入一個已經存在的棧
該條件成立的前提是:
1.判斷方法是設定了FLAG_ACTIVITY_NEW_TASK,但是並非MULTIPLE_TASK
2.或者LAUNCH_SINGLE_INSTANCE或者LAUNCH_SINGLE_TASK模式
*/
boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
(mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| mLaunchSingleInstance || mLaunchSingleTask;
//還要根據目標Activiyt任務棧是否為空來進行判斷
putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
ActivityRecord intentActivity = null;
if (mOptions != null && mOptions.getLaunchTaskId() != -1) {//跳過此處
...
} else if (putIntoExistingTask) {//可以複用
if (mLaunchSingleInstance) {//啟動模式是LAUNCH_SINGLE_INSTANCE,那麼因為其是一種全域性唯一的,需要進行搜尋遍
intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info, false);
} else if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info,
!mLaunchSingleTask);
} else {
//這裡是最常見的形式,mStartActivity是需要啟動的Activity,intentActivity是找到的可用的Task中頂部的Activity
intentActivity = mSupervisor.findTaskLocked(mStartActivity);
}
}
return intentActivity;
}
getReusableIntentActivity方法主要是來查詢是否有可以重用的activity,這個只對啟動模式為LAUNCH_SINGLE_INSTANCE和LAUNCH_SINGLE_TASK或者FLAG_ACTIVITY_NEW_ TASK不為0的Activity才有用,對於standard的activity,該方法永遠返回null。
如果putIntoExistingTask為true表示可以進行復用,那麼就根據情況進行不同的遍歷查詢:
對於以上的查詢就不分析了,這個牽涉的東西太多了,後面打算開闢專門章節來分析。
假如此時我們找到了複用的ActivityRecord,我們看看Android是怎麼對其進行相關處理的。
//[ActivityStarter.java]
private void startActivityUnchecked(ActivityRecord r,//表示要啟動的目標Activity資訊
ActivityOptions options, //options是附件資訊,此時為null
TaskRecord inTask,
boolean doResume, //此處的doResume的值為true
int startFlags, //這裡傳入的startFlags為0
ActivityRecord sourceRecord,//發起端的Activity資訊
IVoiceInteractionSession voiceSession,
IVoiceInteractor voiceInteractor) {
...
//如果找到了可重用的activity,需要清理掉原來的資訊,並把當前啟動的activity的資訊拷貝進去
//做清理和拷貝工作...
/*
此時當前的Task列表中存在有複用的Activity
可能為相同的Activity或者具有相同的affinity的task
如果是第一次啟動某個應用或者從adb am中啟動以及第一次啟動Launcher
那麼複用的TaskRecord為null
*/
if (mReusedActivity != null) {
...
//設定當前啟動Activity的Task為複用的Task
if (mStartActivity.task == null) {
mStartActivity.task = mReusedActivity.task;
}
//設定可以複用Activity所屬的TaskRecord的初始intent為目標Activity的ActivityRecord
if (mReusedActivity.task.intent == null) {
mReusedActivity.task.setIntent(mStartActivity);
}
//清除task中複用的activity上面的activity
if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| mLaunchSingleInstance || mLaunchSingleTask) {
/*
這邊處理啟動時設定FLAG_ACTIVITY_CLEAR_TOP時,要清除複用activity所屬TaskRecord之上的activity
舉個例子:比如複用Task1中存在有Activity A,B,C,D,此時正在啟動的Activity B,那麼C和D也要finish
如果找到的可複用的activity的launchMode為LAUNCH_MULTIPLE,並且目標Activity沒有設定為FLAG_ACTIVITY_SINGLE_TOP那麼此時也會將可複用activity清除
對於要啟動的activity的啟動模式為LAUNCH_MULTIPLE的,performClearTaskForReuseLocked返回值top肯定是空的
*/
final ActivityRecord top = mReusedActivity.task.performClearTaskForReuseLocked(
mStartActivity, mLaunchFlags); //[詳見章節2.6]
if (top != null) {
if (top.frontOfTask) {//如果該ActivityRecord是所屬任務棧的root activity,那麼將目標activity設定為棧頂的Activity
top.task.setIntent(mStartActivity);
}
ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task);
// 沒必要新建範例,回撥onNewIntent並將top移至前臺
top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
mStartActivity.launchedFromPackage);
}
}
// 將複用ActivityRecord所屬TaskRecordy和ActivityStack移動到頂端,必要時會進行task的清理工作
mReusedActivity = setTargetStackAndMoveToFrontIfNeeded(mReusedActivity); //詳見章節[2.7]
//對於複用Task情況下START_FLAG_ONLY_IF_NEEDED這個FLAG只是resumed
//該flag表示只有在需要的時候才啟動目標Activity。也就是說如果呼叫者和被啟動的是一個,那麼就沒有必要去進行重複的步驟了
if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
//resume顯示到前臺
resumeTargetStackIfNeeded();
return START_RETURN_INTENT_TO_CALLER;
}
//根據複用情況設定task
setTaskFromIntentActivity(mReusedActivity);//[詳見章節2.8]
//如果不需要把當前啟動的Activity增加到Task並且不存在複用Task
//那麼僅僅進行resumed過程
//mAddingToTask為true表示要新建,mReuseTask為空表示task被清除了
if (!mAddingToTask && mReuseTask == null) {
//呼叫顯示到前臺
resumeTargetStackIfNeeded();
return START_TASK_TO_FRONT;
}
}
...
}
在找到可以複用的ActivityRecord以後,startActivityUnchecked方法的處理邏輯遠遠還沒有結束,依舊會繼續著相關邏輯的處理:
本來想給上述標題新增一箇中文註解,但是嗎有時候真的是隻可意會不可言傳啊,上面的英文原文反而更覺貼切!
//[TaskRecord.java]
ActivityRecord performClearTaskForReuseLocked(
ActivityRecord newR,//目標Activity
int launchFlags//啟動目標Activity的flag
) {
mReuseTask = true;
final ActivityRecord result = performClearTaskLocked(newR, launchFlags);
mReuseTask = false;
return result;
}
final ArrayList<ActivityRecord> mActivities;//儲存TaskRecord管理的ActivityRecord
final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
int numActivities = mActivities.size();
//注意,此處是從TaskRecord的棧定開始遍歷
for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
ActivityRecord r = mActivities.get(activityNdx);
if (r.finishing) {
continue;
}
//找到了合適的activity,那麼所有位於它上面的目標都需要結束
//注意此處的equal有被重寫,主要通過判斷報名和類名是否一直
if (r.realActivity.equals(newR.realActivity)) {
final ActivityRecord ret = r;
for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
r = mActivities.get(activityNdx);
if (r.finishing) {
continue;
}
ActivityOptions opts = r.takeOptionsLocked();
if (opts != null) {
ret.updateOptionsLocked(opts);
}
if (stack != null && stack.finishActivityLocked(
r, Activity.RESULT_CANCELED, null, "clear-task-stack", false)) {
--activityNdx;
--numActivities;
}
}
//如果要複用的activity是multi模式,並且目標Activity沒有設定FLAG_ACTIVITY_SINGLE_TOP啟動模式那麼也會呼叫finish結束掉
if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
&& (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
if (!ret.finishing) {
if (stack != null) {
stack.finishActivityLocked(
ret, Activity.RESULT_CANCELED, null, "clear-task-top", false);
}
return null;
}
}
return ret;
}
}
return null;
}
performClearTaskForReuseLocked方法不是特別複雜,主要是遍歷TaskRecord物件範例中的ActivityRecord列表mActivities,然後依據一定的規則清除可複用TaskRecord棧中的ActivityRecord,其遍歷清除遵循的邏輯如下:
經過上面的步驟以後,不管是否進行了棧頂資料的清除,接下來就要將我們可以複用的Activity所在的TaskRecord移動到其所在的ActivityStack的頂部。
說實話這個部落格中的各種Stack和Task的分析,我自己都要吐了,太殘暴了這些個東西。尼瑪,有啥辦法只能硬啃了。我們接著分析setTargetStackAndMoveToFrontIfNeeded看看它是怎麼處理我們將要啟動Activity的Stack以及Task的,又是各種的一頓操作啊!
//[TaskRecord.java]
//這裡的入參引數為可複用ActivityRecord
private ActivityRecord setTargetStackAndMoveToFrontIfNeeded(ActivityRecord intentActivity) {
//獲取可複用ActivityRecord所屬ActivityStack
mTargetStack = intentActivity.task.stack;
mTargetStack.mLastPausedActivity = null;
//獲取當前前臺的ActivityStack,ASS中儲存著所有的ActivityStack
final ActivityStack focusStack = mSupervisor.getFocusedStack();
//獲取當前前臺ActivityStack棧頂的ActivityRecord
ActivityRecord curTop = (focusStack == null)
? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
//判斷頂部的棧是否符合要求(即判斷現在棧頂的棧是否為能夠複用的activityrecord所在的棧)
if (curTop != null
&& (curTop.task != intentActivity.task || curTop.task != focusStack.topTask())
&& !mAvoidMoveToFront) {
//增加一個標記,標識這個task是從任務棧的後面移動上來的
mStartActivity.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
//這裡的mSourceRecord表示的是發起端,此處是判斷合法性
if (mSourceRecord == null || (mSourceStack.topActivity() != null &&
mSourceStack.topActivity().task == mSourceRecord.task)) {
if (mLaunchTaskBehind && mSourceRecord != null) {
intentActivity.setTaskToAffiliateWith(mSourceRecord.task);
}
mMovedOtherTask = true;
//willclearTask表明是否同時使用了NEW_TASK 和 CLEAR_TASK的flag
final boolean willClearTask =
(mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
if (!willClearTask) {//不需要清空,那麼就需要將複用的task移至棧頂
//根據規則獲取當前要啟動activity所屬的ActivityStack棧
final ActivityStack launchStack = getLaunchStack(
mStartActivity, mLaunchFlags, mStartActivity.task, mOptions);
//當要啟動的棧與目標一致或者要啟動的棧為空。這是我們一般的標準流程。會呼叫moveTaskToFrontLocked方法,將當前棧移動到與使用者互動的棧頂
if (launchStack == null || launchStack == mTargetStack) {
mTargetStack.moveTaskToFrontLocked(
intentActivity.task, mNoAnimation, mOptions,
mStartActivity.appTimeTracker, "bringingFoundTaskToFront");
mMovedToFront = true;
//其它情況
} else if (launchStack.mStackId == DOCKED_STACK_ID
|| launchStack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
//這邊是把複用的Task移動到其它的ActivityStack
mSupervisor.moveTaskToStackLocked(intentActivity.task.taskId,
launchStack.mStackId, ON_TOP, FORCE_FOCUS, "launchToSide",
ANIMATE);
} else {
mTargetStack.moveTaskToFrontLocked(intentActivity.task, mNoAnimation,
mOptions, mStartActivity.appTimeTracker,
"bringToFrontInsteadOfAdjacentLaunch");
}
mMovedToFront = true;
}
mOptions = null;
}
updateTaskReturnToType(intentActivity.task, mLaunchFlags, focusStack);
}
}
//這邊表示如果不需要Task移動,移動targetStack到前臺
if (!mMovedToFront && mDoResume) {
mTargetStack.moveToFront("intentActivityFound");
}
mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.task, INVALID_STACK_ID,
mTargetStack.mStackId);
if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
return mTargetStack.resetTaskIfNeededLocked(intentActivity, mStartActivity);
}
return intentActivity;
}
感覺分析這塊的程式碼,每次都是對我腦細胞和精神的一次摧殘啊!我們來看看這個方法的大致流程:
從ASS中找到當前和使用者互動ActivityStack,然後從ActivityStack中找到正在和使用者互動的ActivityRecord。同時找到其所在的任務棧(TaskRecord)(此處這幾者之間牽涉的關係詳見章節一)
當發現當前棧頂的TaskRecord和我們要啟動的Activity所使用的TaskRecord不是同一個時,這時候如果設定的標誌位不會清空棧頂的資訊的話,需要將要目標TaskRecord移動到棧頂位置。但是這個移動也需要分情況來進行
1.首先通過getLaunchStack方法獲取目標ActivityStcak資訊intentTask。
2.這時候會比較我們要啟動的ActivityStack和當前複用的ActivityRecord所對應的ActivityStack作比較,然後根據不同情況走不同的分支
//[ActivityStack.java]
//此處的入參TaskRecord為可以複用的TaskRecord
final void moveTaskToFrontLocked(TaskRecord tr, boolean noAnimation, ActivityOptions options,
AppTimeTracker timeTracker, String reason) {
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr);
final int numTasks = mTaskHistory.size();//獲取AS中有多少TaskRecord
final int index = mTaskHistory.indexOf(tr);//獲取入參的tr在當前的AS中的位置
if (numTasks == 0 || index < 0) {//異常情況處理
if (noAnimation) {
ActivityOptions.abort(options);
} else {
updateTransitLocked(TRANSIT_TASK_TO_FRONT, options);
}
return;
}
if (timeTracker != null) {
for (int i = tr.mActivities.size() - 1; i >= 0; i--) {
tr.mActivities.get(i).appTimeTracker = timeTracker;
}
}
//將Task移動到ActivityStack的棧頂端
insertTaskAtTop(tr, null);
//獲取到TaskRecord的棧頂activity
ActivityRecord top = tr.getTopActivity();
if (!okToShowLocked(top)) {//判斷是否可見
addRecentActivityLocked(top);
ActivityOptions.abort(options);
return;
}
//獲取到ActivityStack中頂部正在執行的Activity
//這時候stack的topActivity應該是上一步已經移到棧複用的Task
ActivityRecord r = topRunningActivityLocked();
/*
更新AMS中的focusedActivity
這邊會把當前Activity所屬的Stack移到棧頂,
並且會更新ActivityStackSupervisor中的
mLastFocusedStack、mFocusedStack這兩個變數
*/
mService.setFocusedActivityLocked(r, reason);
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr);
if (noAnimation) {
mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
if (r != null) {
mNoAnimActivities.add(r);
}
ActivityOptions.abort(options);
} else {
updateTransitLocked(TRANSIT_TASK_TO_FRONT, options);
}
//呼叫持有焦點的任務棧的頂部Activity的onResume()方法
mStackSupervisor.resumeFocusedStackTopActivityLocked();
EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, tr.taskId);
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
}
前面我們簡單的總結了moveTaskToFrontLocked的功能就是將TaskRecord移動到ActivityStack,其執行該流程的主要步驟如下:
讓我們回過頭來繼續重看一下setTargetStackAndMoveToFrontIfNeeded方法,可以看到經過我們的分析可知此時當前啟動Activity可以複用的Task、以它所屬的ActivityStack均已經移動到了棧頂了。
到現在為止,我們已經可以複用的ActivityRecord的TaskRecord和ActivityStack的移動到互動棧頂。這時候還沒有over戰鬥依然在進行,我們回到章節2.5看到此時會根據實際的情況對可複用的Activity資訊,進行一些整理工作。
//[ActivityStarter.java]
//注意此時傳入的引數為複用ActivityRecord
private void setTaskFromIntentActivity(ActivityRecord intentActivity) {
//設定了FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK標誌位的複用的Task會finish所有的Activity,並且重新
//更新複用Task資訊的當前啟動的Activit
if ((mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
mReuseTask = intentActivity.task;
mReuseTask.performClearTaskLocked();
mReuseTask.setIntent(mStartActivity);
mMovedOtherTask = true;
} else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| mLaunchSingleInstance || mLaunchSingleTask) {
//清空棧,這裡跟之前的2.6章節棧頂資料的清除操作相似,但是那裡處理的是top不為空,這裡處理的是top為空的情況,也就是launchMode == ActivityInfo.LAUNCH_MULTIPLE
ActivityRecord top = intentActivity.task.performClearTaskLocked(mStartActivity,
mLaunchFlags);
if (top == null) {
mAddingToTask = true;
mSourceRecord = intentActivity;
final TaskRecord task = mSourceRecord.task;
if (task != null && task.stack == null) {
mTargetStack = computeStackFocus(mSourceRecord, false /* newTask */,
null /* bounds */, mLaunchFlags, mOptions);
mTargetStack.addTask(task,
!mLaunchTaskBehind /* toTop */, "startActivityUnchecked");
}
}
}
任務棧頂部的activity和要啟動的activity是同一個
else if (mStartActivity.realActivity.equals(intentActivity.task.realActivity)) {
//如果是sigleTop,那麼就呼叫deliverNewIntent
if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 || mLaunchSingleTop)
&& intentActivity.realActivity.equals(mStartActivity.realActivity)) {
ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity,
intentActivity.task);
if (intentActivity.frontOfTask) {//如果是棧的根activity,那麼設定
intentActivity.task.setIntent(mStartActivity);
}
intentActivity.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
mStartActivity.launchedFromPackage);
} else if (!intentActivity.task.isSameIntentFilter(mStartActivity)) {
//如果不是singleTop,那麼認為是需要啟動一個新的activity
mAddingToTask = true;
mSourceRecord = intentActivity;
}
} else if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
// 對FLAG_ACTIVITY_RESET_TASK_IF_NEEDED標誌出處理,這個主要用於快捷圖示和或者從通知啟動,這種情況需要替換task最上面的activity,所以需要新增activity到task中
mAddingToTask = true;
mSourceRecord = intentActivity;
} else if (!intentActivity.task.rootWasReset) {
intentActivity.task.setIntent(mStartActivity);
}
}
再接再厲繼續分析,讓我們看看此方法中會對可複用的Activity所在的ActivityStack和TaskRecord做怎麼樣的處理:
此時對於可複用的的Activity所在的ActivityStack和TaskRecord已經移動到棧頂位置了,這其中的各種切換邏輯真的是眼花繚亂啊,讓人搞得暈頭轉向!
存在複用ActivityRecord處理的處理已經分析完畢了,各位小夥們真的理解了嗎!我想沒有,因為我也麼有繞出來,其中涉及的各種場景太多了,看來還是得帶入實際情況進行分析,但是這個就脫離我們本篇的範疇了,因為我們本篇重點講解Activity的啟動主流程!我們這裡還是簡單的對存在複用ActivityRecord處理小結一下,經過上述繁瑣的處理對於可複用的的Activity所在的ActivityStack和TaskRecord已經移動到棧頂位置了,其基本的呼叫流程如下:
AS.startActivityUnchecked(...)
mReusedActivity.task.performClearTaskForReuseLocked(...)//清除task中複用的activity上面的activity
AS.setTargetStackAndMoveToFrontIfNeeded(...)// 將複用ActivityRecord所屬TaskRecordy和ActivityStack移動到頂端,必要時會進行task的清理工作
AS.setTaskFromIntentActivity(...)//根據複用情況設定task
如果讀者朋友們,只想從整理上了解Activity的啟動流程,那麼第二大章節閱讀過程中如果有問題也沒有用關係,因為這個並不牽涉到整體流程的分析。
當存在複用ActivityRecord時,經過前面章節一系列的處理此時已將將可複用activty替換成現在的目標activty,也就不用新建task了。那麼生活還得繼續,讓我們跳出reusedActivity不為空的情況,接著繼續後續的分析。
//[ActivityStarter.java]
/* 這裡的sourceRecord是指發起呼叫者
r是指本次的將要啟動的Activity,startFlags取值為0,
doResume的值為true
*/
private int startActivityUnchecked(final ActivityRecord r,
ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession,
IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume,
ActivityOptions options,
TaskRecord inTask) {
...
//如果找到了可重用的activity,需要清理掉原來的資訊,並把當前啟動的activity的資訊拷貝進去
//做清理和拷貝工作...
if (mReusedActivity != null) {
...
}
if (mStartActivity.packageName == null) {//例外處理
if (mStartActivity.resultTo != null && mStartActivity.resultTo.task.stack != null) {
mStartActivity.resultTo.task.stack.sendActivityResultLocked(
-1, mStartActivity.resultTo, mStartActivity.resultWho,
mStartActivity.requestCode, RESULT_CANCELED, null);
}
ActivityOptions.abort(mOptions);
return START_CLASS_NOT_FOUND;
}
//獲取當前前臺的ActivityStack 以及ActivityRecord
final ActivityStack topStack = mSupervisor.mFocusedStack;
final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
//是否需要啟動新的Activity標記,一長串的判斷
final boolean dontStart = top != null && mStartActivity.resultTo == null
&& top.realActivity.equals(mStartActivity.realActivity)
&& top.userId == mStartActivity.userId
&& top.app != null && top.app.thread != null
&& ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
|| mLaunchSingleTop || mLaunchSingleTask);
if (dontStart) {//不需要重新啟動,那麼使用複用邏輯,將當前activity顯示到前端即可
ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
topStack.mLastPausedActivity = null;
if (mDoResume) {//此時為true
mSupervisor.resumeFocusedStackTopActivityLocked();
}
ActivityOptions.abort(mOptions);
if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
return START_RETURN_INTENT_TO_CALLER;
}
//呼叫NewIntent方法
top.deliverNewIntentLocked(
mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
mSupervisor.handleNonResizableTaskIfNeeded(
top.task, preferredLaunchStackId, topStack.mStackId);
return START_DELIVERED_TO_TOP;
}
}
通過程式碼分析我們可知此時判斷當前頂部執行的Activity是否是我們所要啟動的Activity,並且啟動模式是singTop或者singleTask。如果是的話,則不會新建Activity,而是呼叫onResume和newIntent方法。因為這兩種模式下,如果頂層是當前Activity的話,都不會啟動新的Activity。這也就是我們常說的 A->B->C ,此時如果C的模式是singleTop,這時候再啟動C的話,棧內仍然是A->B->C。
革命仍未成功還需繼續努力,讓我們接著對startActivityUnchecked後續原始碼繼續分析
//[ActivityStarter.java]
//表示是否需要建立新的任務棧
boolean newTask = false;
final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
? mSourceRecord.task : null;
/*
如果要啟動的目標Activity沒有對應的resultTo,
並且也沒有新增到對應棧中
而且設定了FLAG_ACTIVITY_NEW_TASK。
mAddingToTask為false說明沒有找到對應的棧來啟動我們的Activity。
所以會通過建立或者複用一個棧來存放Activity
*/
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
newTask = true;
// 重用或者新建task
setTaskFromReuseOrCreateNewTask(taskToAffiliate);//詳見章節2.10.1
...
}
/*
當mSourceRecord不為空,把新的ActivityRecord繫結到啟動者的TaskRecord上。
一般情況下,mSourceRecord就是呼叫者,如本例中的Launcher;
但也有特殊情況,舉個例子,如果啟動模式為singleTask,棧中又不存在相同的Activity時,
mSourceRecord就是棧頂的Activity
*/
else if (mSourceRecord != null) {
...
// 不是新建task的,重用原activity的task
final int result = setTaskFromSourceRecord();//詳見章節2.10.2
if (result != START_SUCCESS) {
return result;
}
} else if (mInTask != null) {//啟動時指定了目標棧(mInTask),ActivityRecord繫結到mInTask
if (mSupervisor.isLockTaskModeViolation(mInTask)) {
Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
return START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
final int result = setTaskFromInTask();//詳見2.10.3
if (result != START_SUCCESS) {
return result;
}
} else {
//都不是則直接找焦點的ActivityStack上棧頂的Task,直接繫結
setTaskToCurrentTopOrCreateNewTask();//詳見章節2.10.4
}
說實話這種邏輯性的程式碼分析起來很操蛋,也很容易讓人陷入其中不能自拔,但是生活還得繼續著,程式碼也得分析!上述的原始碼主要根據實際情況來繼續進行要啟動的Activity棧資訊的處理,這裡的處理邏輯又分為如下幾種情況:
依然還沒有完,Activity啟動中的生命週期一個也沒有看到!尼瑪,還是對上述每種情況下是如何尋找任務棧的方式來簡單來進行一下分析!
//[ActivityStarter.java]
private void setTaskFromReuseOrCreateNewTask(TaskRecord taskToAffiliate) {
//獲取當前持有焦點的ActivityStack
mTargetStack = computeStackFocus(mStartActivity, true, mLaunchBounds, mLaunchFlags,
mOptions);
//如果複用的任務棧(TaskRecord)為空,說明沒有可以讓我們用來使用的任務棧
if (mReuseTask == null) {
//建立任務棧
final TaskRecord task = mTargetStack.createTaskRecord(
mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId),
mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
mNewTaskIntent != null ? mNewTaskIntent : mIntent,
mVoiceSession, mVoiceInteractor, !mLaunchTaskBehind /* toTop */);
//設定目標Activity的任務棧為新建的task
mStartActivity.setTask(task, taskToAffiliate);
if (mLaunchBounds != null) {
final int stackId = mTargetStack.mStackId;
if (StackId.resizeStackWithLaunchBounds(stackId)) {
mService.resizeStack(
stackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE, -1);
} else {
mStartActivity.task.updateOverrideConfiguration(mLaunchBounds);
}
}
if (DEBUG_TASKS) Slog.v(TAG_TASKS,
"Starting new activity " +
mStartActivity + " in new task " + mStartActivity.task);
} else {
//設定目標Activity的任務棧為新建的task
mStartActivity.setTask(mReuseTask, taskToAffiliate);
}
}
setTaskFromReuseOrCreateNewTask方法的處理邏輯比較簡單,總結歸納起來如下:
進入此分支的前提是mSourceRecord不為null,即發起端為Activity,此時會直接把目標ActivityRecord繫結到啟動者的TaskRecord上
//[ActivityStarter.java]
private int setTaskFromSourceRecord() {
//獲取啟動著的任務棧
final TaskRecord sourceTask = mSourceRecord.task;
//我們在前面已經將要啟動的Activity所在的Activity棧移動到前臺了,所以sourceStack.topTask就是要啟動的Activity所在的棧
//如果目標Activity不允許在螢幕上顯示或者源任務棧和目標任務不在同一個棧
final boolean moveStackAllowed = sourceTask.stack.topTask() != sourceTask;
if (moveStackAllowed) {
//獲取當前要啟動activity所屬的ActivityStack棧
mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.task,
mOptions);
}
if (mTargetStack == null) {//目標ActivityStack為空
mTargetStack = sourceTask.stack;
} else if (mTargetStack != sourceTask.stack) {
//把啟動方的任務棧繫結到目標ActivityStack上
mSupervisor.moveTaskToStackLocked(sourceTask.taskId, mTargetStack.mStackId,
ON_TOP, FORCE_FOCUS, "launchToSide", !ANIMATE);
}
if (mDoResume) {
mTargetStack.moveToFront("sourceStackToFront");
}
//獲取目標ActivityStack的頂部task
final TaskRecord topTask = mTargetStack.topTask();
//目標任務棧移動到ActivityStack的頂部,也就是設定為焦點
if (topTask != sourceTask && !mAvoidMoveToFront) {
mTargetStack.moveTaskToFrontLocked(sourceTask, mNoAnimation, mOptions,
mStartActivity.appTimeTracker, "sourceTaskToFront");
}
//如果目標activity還沒有加入到棧中,而且啟動標誌設定了CLEAR_TOP,那麼我們將Activity新增到已經存在的任務棧中,並呼叫clear方法清空對應的activity
if (!mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0) {
// In this case, we are adding the activity to an existing task, but the caller has
ActivityRecord top = sourceTask.performClearTaskLocked(mStartActivity, mLaunchFlags);
mKeepCurTransition = true;
if (top != null) {
ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task);
top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
mTargetStack.mLastPausedActivity = null;
if (mDoResume) {
mSupervisor.resumeFocusedStackTopActivityLocked();
}
ActivityOptions.abort(mOptions);
return START_DELIVERED_TO_TOP;
}
} else if (!mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
final ActivityRecord top = sourceTask.findActivityInHistoryLocked(mStartActivity);
if (top != null) {
final TaskRecord task = top.task;
task.moveActivityToFrontLocked(top);
top.updateOptionsLocked(mOptions);
ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, task);
top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
mTargetStack.mLastPausedActivity = null;
if (mDoResume) {
mSupervisor.resumeFocusedStackTopActivityLocked();
}
return START_DELIVERED_TO_TOP;
}
}
//將Activity新增到相應的Task
mStartActivity.setTask(sourceTask, null);
if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
+ " in existing task " + mStartActivity.task + " from source " + mSourceRecord);
return START_SUCCESS;
}
我們對該流程簡單的分析一下,感覺這來來回回的繞著圈好難啊!
對於上述的各種流程,小夥們能搞懂是最好了,搞不懂也沒有關係,不影響Activity的整體啟動。
進入此分支的前提是mInTask不為null,即指定了目標Task
//[ActivityStarter.java]
//將目標Activity的任務棧設定為mInTask
private int setTaskFromInTask() {
if (mLaunchBounds != null) {
mInTask.updateOverrideConfiguration(mLaunchBounds);
int stackId = mInTask.getLaunchStackId();
if (stackId != mInTask.stack.mStackId) {
final ActivityStack stack = mSupervisor.moveTaskToStackUncheckedLocked(
mInTask, stackId, ON_TOP, !FORCE_FOCUS, "inTaskToFront");
stackId = stack.mStackId;
}
if (StackId.resizeStackWithLaunchBounds(stackId)) {
mService.resizeStack(stackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE, -1);
}
}
//根據實際情況檢查是需要建立新的activity還是重新使用任務棧頂部的activity
mTargetStack = mInTask.stack;
//將mInTask移動到頂部
mTargetStack.moveTaskToFrontLocked(
mInTask, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "inTaskToFront");
//獲取指定任務棧頂Activity
ActivityRecord top = mInTask.getTopActivity();
if (top != null && top.realActivity.equals(mStartActivity.realActivity) && top.userId == mStartActivity.userId) {
//如果設定了singleTop或者啟動模式為singleTop或者singleTask,那麼呼叫newIntent方法
if ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
|| mLaunchSingleTop || mLaunchSingleTask) {
ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
return START_RETURN_INTENT_TO_CALLER;
}
top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
return START_DELIVERED_TO_TOP;
}
}
//mAddingToTask是標記位,標記著是否需要將Activity新增到TaskRecord中,
// 在之前進行如果已經將目標Activity放入到任務棧的話,這裡就不需要再次放入了,
//只需要把TaskRecord移動ActivityStack頂部即可
if (!mAddingToTask) {
// We don't actually want to have this activity added to the task, so just
// stop here but still tell the caller that we consumed the intent.
ActivityOptions.abort(mOptions);
return START_TASK_TO_FRONT;
}
//將Activity新增到mInTask任務棧中
mStartActivity.setTask(mInTask, null);
if (DEBUG_TASKS) Slog.v(TAG_TASKS,
"Starting new activity " + mStartActivity + " in explicit task " + mStartActivity.task);
return START_SUCCESS;
}
好嗎,這裡的setTaskFromInTask方法也針對不同的情況分別進行了處理:
尼瑪終於只有最好的一種情況了
//查詢當前焦點的ActivityStack上棧頂的Task,或者建立一個新的任務棧
private void setTaskToCurrentTopOrCreateNewTask() {
//獲取持有焦點的ActivityStack
mTargetStack = computeStackFocus(mStartActivity, false, null /* bounds */, mLaunchFlags,
mOptions);
if (mDoResume) {
mTargetStack.moveToFront("addingToTopTask");
}
//獲取棧頂的ActivityRecord,也就是會被我們覆蓋的那個Activity
final ActivityRecord prev = mTargetStack.topActivity();
//嘗試從持有焦點的ActivityRecord獲取其頂部的任務棧,如果獲取不到的話,則建立一個
final TaskRecord task = (prev != null) ? prev.task : mTargetStack.createTaskRecord(
mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId),
mStartActivity.info, mIntent, null, null, true);
//將activity新增到任務棧中
mStartActivity.setTask(task, null);
mWindowManager.moveTaskToTop(mStartActivity.task.taskId);
if (DEBUG_TASKS) Slog.v(TAG_TASKS,
"Starting new activity " + mStartActivity + " in new guessed " + mStartActivity.task);
}
尼瑪此時此刻,actvity及其對應的task位置已經安排妥當,現在可以準備讓這個activity開始工作了,真不容易啊!不容易啊!
//[ActivityStarter.java]
/* 這裡的sourceRecord是指發起呼叫者
r是指本次的將要啟動的Activity,startFlags取值為0,
doResume的值為true
*/
private int startActivityUnchecked(final ActivityRecord r,
ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession,
IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume,
ActivityOptions options,
TaskRecord inTask) {
...
//把當前啟動的Activity加入TaskRecord以及繫結WindowManagerService
mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);
...
}
本來是打算將前面第二章節涉及的兩大部分都講述完畢,但是一看現在的這個文字量看來只能將第一大部分分析完成了,我們接著繼續
//[ActivityStack.java]
final void startActivityLocked(ActivityRecord r, boolean newTask, boolean keepCurTransition,
ActivityOptions options) {
//rTask即之前建立的TaskRecord,或者為查詢到的可複用的TaskRecord
TaskRecord rTask = r.task;
final int taskId = rTask.taskId;//獲取taskid
if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
insertTaskAtTop(rTask, r);//插入新建立或複用的TaskRecord到棧頂
mWindowManager.moveTaskToTop(taskId);//同時在Windowmanager中也移動到棧頂
}
TaskRecord task = null;
if (!newTask) {//這是表示存在複用的TaskRecord
boolean startIt = true;
//遍歷TaskRecord從這兒也可以得出TaskRecord在ActivityStack是以棧的方式管理的
//因為此時是倒序遍歷的
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
task = mTaskHistory.get(taskNdx);
if (task.getTopActivity() == null) {
continue;
}
if (task == r.task) {//在Task堆疊中找到了複用的Task
if (!startIt) {
task.addActivityToTop(r);//把當前啟動的Activity加入到複用的Task棧頂
r.putInHistory();
addConfigOverride(r, task);//繫結到windowmanager中,此處很重要,但是不會在此分析
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
ActivityOptions.abort(options);
return;
}
break;
} else if (task.numFullscreen > 0) {
startIt = false;
}
}
}
if (task == r.task && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) {
mStackSupervisor.mUserLeaving = false;
if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
"startActivity() behind front, mUserLeaving=false");
}
task = r.task;
//當前啟動的Activity加到所屬Task棧頂中
task.addActivityToTop(r);
//這個是標記Task中Activity堆疊的堆底Activity元素
task.setFrontOfTask();
r.putInHistory();
/*
如果當前ActivityStack不為 HomeStack,或者該ActivityStack中activity個數不為0
*/
if (!isHomeStack() || numActivities() > 0) {
boolean showStartingIcon = newTask;
ProcessRecord proc = r.app;
if (proc == null) {
proc = mService.mProcessNames.get(r.processName, r.info.applicationInfo.uid);
}
//對於剛啟動HOME應用時,表示程序ProcessReocrd還為空
if (proc == null || proc.thread == null) {
showStartingIcon = true;
}
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
mWindowManager.prepareAppTransition(TRANSIT_NONE, keepCurTransition);
mNoAnimActivities.add(r);
} else {
//動畫相關
mWindowManager.prepareAppTransition(newTask
? r.mLaunchTaskBehind
? TRANSIT_TASK_OPEN_BEHIND
: TRANSIT_TASK_OPEN
: TRANSIT_ACTIVITY_OPEN, keepCurTransition);
mNoAnimActivities.remove(r);
}
//當前啟動的Activity繫結到WIndowManagerService當中
addConfigOverride(r, task);
boolean doShow = true;
if (newTask) {
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
resetTaskIfNeededLocked(r, r);
doShow = topRunningNonDelayedActivityLocked(null) == r;
}
} else if (options != null && options.getAnimationType()
== ActivityOptions.ANIM_SCENE_TRANSITION) {
doShow = false;
}
if (r.mLaunchTaskBehind) {
mWindowManager.setAppVisibility(r.appToken, true);
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
} else if (SHOW_APP_STARTING_PREVIEW && doShow) {
ActivityRecord prev = r.task.topRunningActivityWithStartingWindowLocked();
if (prev != null) {
if (prev.task != r.task) {
prev = null;
}
// (2) The current activity is already displayed.
else if (prev.nowVisible) {
prev = null;
}
}
r.showStartingWindow(prev, showStartingIcon);
}
} else {
//當前啟動的Activity繫結到WIndowManagerService當中*
addConfigOverride(r, task);
ActivityOptions.abort(options);
options = null;
}
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
}
經過以上的重重步驟,此時目標Activity對應的Task也建立了,也把當前啟動的Activity加入到Task正確的位置,ActivityStack也移動到了正確位置。此時本章節就分析到這裡了!
閱讀原始碼是很操蛋的事情,同樣的如果將太多的邏輯放在一篇中我想小夥們也會閱讀起來也會操蛋,失去耐心的的,所以本篇章就先到這裡了。分析至此我們對前面的篇章做一個小結,我們前面主要乾了如下相關的事情:
並且通過前面的博文分析,小夥們心裡應該有了如下的知識圖譜:
好了本篇部落格真的只能到此了,雖然本人耗費了很多的時間來對Activity啟動涉及的Task和ActivityStack等排程相關的知識點來進行分析和講解,但是這其中牽涉的東西太多了,並且由於個人能力有限,自我感覺依然分析的不是很清晰,只能大夥見諒了。如果小夥們喜歡歡迎點贊或者能和我討論關於本篇的知識點!