Android四大组件源码实现详解系列博客目录:
Android应用进程创建流程大揭秘
[Android四大组件之bindService源码实现详解
Android四大组件之Activity启动流程源码实现详解概要
Activity启动流程(一)发起端进程请求启动目标Activity
Activity启动流程(二)system_server进程处理启动Activity请求
Activity启动流程(三)-Activity Task调度算法复盘分析
Activity启动流程(四)-Pause前台显示Activity,Resume目标Activity
Activity启动流程(五)请求并创建目标Activity进程
Activity启动流程(六)注册目标Activity进程到system_server进程以及创建目标Activity进程Application
Activity启动流程(七)初始化目标Activity并执行相关生命周期流程
还记得大明湖畔的夏雨荷吗!错了,还记得我们前面章节博客Android四大组件之Activity启动流程源码实现详解(一)吗,在上述博客中我们重点分析了Activity启动的如下相关知识点:
那么在本篇博客中我们将继续分析system_server对Activity启动请求的处理流程:
system_server进程通过AMS处理启动Activity请求:
4.为目标Activity查找/分配或者创建最优Task栈以及ActivityStack栈
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,管理者这个task中的Activity
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是管理系统中所有Activity状态的一个数据结构!把我的意大利炮拿出来朝着它狠狠的开炮!
//[ActivityStack.java]
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,包括所有前面Activity的回退记录,包括可能正在运行的Activity
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;
//最近一次被启动的Activity
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)://测试终端只存在一个显示设备,所以Displayid只会存在一个
Stack #1://当前焦点的ActivtyStack id
mFullscreen=true
mBounds=null
Task id #96//当前获取焦点的Task任务栈id
mFullscreen=true
mBounds=null
mMinWidth=-1
mMinHeight=-1
mLastNonFullscreenBounds=null
* TaskRecord{56df812 #96 A=com.cyanogenmod.filemanager U=0 StackId=1 sz=1}//Task任务栈具体信息
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}//启动目标Activity的intent信息
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{dac4005 u0 com.cyanogenmod.filemanager/.activities.NavigationActivity t96}]//当前获取焦点的Activity的ActivityRecord信息
askedCompatMode=false inRecents=true isAvailable=true
lastThumbnail=null lastThumbnailFile=/data/system_ce/0/recent_images/96_task_thumbnail.png
stackId=1
hasBeenVisible=true mResizeMode=RESIZE_MODE_UNRESIZEABLE isResizeable=false firstActiveTime=1601263245356 lastActiveTime=1601263245356 (inactive for 38s)
* Hist #0: ActivityRecord{dac4005 u0 com.cyanogenmod.filemanager/.activities.NavigationActivity t96}
packageName=com.cyanogenmod.filemanager processName=com.cyanogenmod.filemanager
launchedFromUid=10023 launchedFromPackage=com.android.launcher3 userId=0
app=ProcessRecord{1544be3 8312: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{56df812 #96 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=1 lastLaunchTime=-38s806ms
haveState=false icicle=null
state=RESUMED stopped=false delayedResume=false finishing=false
keysPaused=false inHistory=true visible=true sleeping=false 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=true lastVisibleTime=-37s955ms
resizeMode=RESIZE_MODE_UNRESIZEABLE
Task id #95//Stack id为1中另外的Taask
mFullscreen=true
mBounds=null
mMinWidth=-1
mMinHeight=-1
mLastNonFullscreenBounds=null
* TaskRecord{495a9e0 #95 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{1c174fa u0 org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity t95}]
askedCompatMode=false inRecents=true isAvailable=true
lastThumbnail=android.graphics.Bitmap@bbc499 lastThumbnailFile=/data/system_ce/0/recent_images/95_task_thumbnail.png
stackId=1
hasBeenVisible=true mResizeMode=RESIZE_MODE_FORCE_RESIZEABLE isResizeable=true firstActiveTime=1601263244132 lastActiveTime=1601263244132 (inactive for 40s)
* Hist #0: ActivityRecord{1c174fa u0 org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity t95}
packageName=org.codeaurora.gallery processName=org.codeaurora.gallery
launchedFromUid=10023 launchedFromPackage=com.android.launcher3 userId=0
app=ProcessRecord{ff4ff7f 8258: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{495a9e0 #95 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=-41s697ms
haveState=true icicle=Bundle[mParcelledData.dataSize=1556]
state=STOPPED stopped=true delayedResume=false finishing=false
keysPaused=false inHistory=true visible=false sleeping=false 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=-41s87ms
connections=[ConnectionRecord{d694795 u0 CR org.codeaurora.gallery/com.android.gallery3d.app.BatchService:@c63ab4c}]
resizeMode=RESIZE_MODE_FORCE_RESIZEABLE
Running activities (most recent first):
TaskRecord{56df812 #96 A=com.cyanogenmod.filemanager U=0 StackId=1 sz=1}
Run #1: ActivityRecord{dac4005 u0 com.cyanogenmod.filemanager/.activities.NavigationActivity t96}
TaskRecord{495a9e0 #95 A=org.codeaurora.gallery U=0 StackId=1 sz=1}
Run #0: ActivityRecord{1c174fa u0 org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity t95}
mResumedActivity: ActivityRecord{dac4005 u0 com.cyanogenmod.filemanager/.activities.NavigationActivity t96}
Stack #0://Launcher所属的ActivityStack
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=1601263245268 lastActiveTime=1601263245268 (inactive for 38s)
* 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=-1h27m5s112ms
haveState=true icicle=Bundle[mParcelledData.dataSize=3940]
state=STOPPED stopped=true delayedResume=false finishing=false
keysPaused=false inHistory=true visible=false sleeping=false 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=-39s442ms
resizeMode=RESIZE_MODE_FORCE_RESIZEABLE
Task id #94//Task对应的ID
mFullscreen=true
mBounds=null
mMinWidth=-1
mMinHeight=-1
mLastNonFullscreenBounds=null
* TaskRecord{ca4459f #94 A=com.android.systemui U=0 StackId=0 sz=1}
userId=0 effectiveUid=u0a14 mCallingUid=u0a14 mUserSetupComplete=true mCallingPackage=com.android.systemui
affinity=com.android.systemui
intent={flg=0x10804000 cmp=com.android.systemui/.recents.RecentsActivity bnds=[32,1024][688,1840]}
realActivity=com.android.systemui/.recents.RecentsActivity
autoRemoveRecents=false isPersistable=false numFullscreen=1 taskType=2 mTaskToReturnTo=1
rootWasReset=false mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
Activities=[ActivityRecord{f344048 u0 com.android.systemui/.recents.RecentsActivity t94}]
askedCompatMode=false inRecents=true isAvailable=true
lastThumbnail=null lastThumbnailFile=/data/system_ce/0/recent_images/94_task_thumbnail.png
stackId=0
hasBeenVisible=true mResizeMode=RESIZE_MODE_RESIZEABLE isResizeable=true firstActiveTime=1601263239735 lastActiveTime=1601263239735 (inactive for 44s)
* Hist #0: ActivityRecord{f344048 u0 com.android.systemui/.recents.RecentsActivity t94}
packageName=com.android.systemui processName=com.android.systemui
launchedFromUid=10014 launchedFromPackage=com.android.systemui userId=0
app=ProcessRecord{3142ae0 4683:com.android.systemui/u0a14}
Intent { flg=0x10804000 cmp=com.android.systemui/.recents.RecentsActivity bnds=[32,1024][688,1840] }
frontOfTask=true task=TaskRecord{ca4459f #94 A=com.android.systemui U=0 StackId=0 sz=1}
taskAffinity=com.android.systemui
realActivity=com.android.systemui/.recents.RecentsActivity
baseDir=/system/priv-app/SystemUI/SystemUI.apk
dataDir=/data/user_de/0/com.android.systemui
stateNotNeeded=true componentSpecified=true mActivityType=2
compat={320dpi} labelRes=0x7f0f0257 icon=0x7f020159 theme=0x7f1301e3
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=ff212121
launchFailed=false launchCount=0 lastLaunchTime=-1m32s445ms
haveState=true icicle=Bundle[mParcelledData.dataSize=500]
state=STOPPED stopped=true delayedResume=false finishing=false
keysPaused=false inHistory=true visible=false sleeping=false idle=true mStartingWindowState=STARTING_WINDOW_NOT_SHOWN
fullscreen=true noDisplay=false immersive=false launchMode=3
frozenBeforeDestroy=false forceNewConfig=false
mActivityType=RECENTS_ACTIVITY_TYPE
waitingVisible=false nowVisible=false lastVisibleTime=-46s419ms
resizeMode=RESIZE_MODE_RESIZEABLE
Running activities (most recent first):
TaskRecord{a9ad0b9 #88 A=com.android.launcher3 U=0 StackId=0 sz=1}
Run #1: ActivityRecord{9997f10 u0 com.android.launcher3/.Launcher t88}
TaskRecord{ca4459f #94 A=com.android.systemui U=0 StackId=0 sz=1}
Run #0: ActivityRecord{f344048 u0 com.android.systemui/.recents.RecentsActivity t94}
mLastPausedActivity: ActivityRecord{9997f10 u0 com.android.launcher3/.Launcher t88}
//当前持有焦点的Activity
mFocusedActivity: ActivityRecord{dac4005 u0 com.cyanogenmod.filemanager/.activities.NavigationActivity t96}
//持有焦点的ActivityStack
mFocusedStack=ActivityStack{d2f835e stackId=1, 2 tasks} mLastFocusedStack=ActivityStack{d2f835e stackId=1, 2 tasks}
mSleepTimeout=false
mCurTaskIdForUser={0=96}
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待启动的ActivityRecord,这是是在前面创建的一个ActivityRecord对象
startFlags表示启动目标Activity的flag,取值为0,
doResume表示是否要将Activity推入Resume状态,从上一个方法传入进来的参数值为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);
//如果被启动的对象和调用者是同一个,什么都不用做,只要正确恢复顶层的Activity
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;
}
该部分代码很长,很长!但是没有办法,阅读源码就是这么操蛋,我们只能一步步分解,强行分析了!在对该方法startActivityUnchecked刨丁解牛,我们先看看该方法牵涉到的返回值,以及意义!
返回值定义 | 返回值含义 |
---|---|
START_CLASS_NOT_FOUND(-2) | 无法找到目标Activity的类 |
START_SUCCESS(0) | 启动成功 |
START_RETURN_INTENT_TO_CALLER(1) | 当启动参数中带有START_FLAG_ONLY_IF_NEEDED标志时,如果目标Activity就是当前的调用者,则返回该值,启动结束 |
START_TASK_TO_FRONT(2) | 在已有任务中找到了目标Activity,则只需要把目标Activity挪到前台即可,启动结束 |
START_DELIVERED_TO_TOP(3) | 目标Activity位于任务栈顶,则只需要将Intent派送到栈顶的Activity即可,启动结束 |
START_RETURN_LOCK_TASK_MODE_VIOLATION(5) | 目标Activity的宿主任务处于LockTaskMode模式,且目标Activity的启动方式违背了LockTaskMode的规则,则不能启动目标Activity |
//[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的启动模式,这些值是从标签中读取的,即目标Activity所定义的启动方式
// 除了目标Activity定义的启动模式外,调用者也可以设置Activity的启动模式
// 这些参数都体现在Intent的Flags中
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和intent携带的flags对目标Activity的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;
}
//将启动将要涉及的相关变量都进行初始化
private void reset() {
mStartActivity = null;
mIntent = null;
mCallingUid = -1;
mOptions = null;
mLaunchSingleTop = false;
mLaunchSingleInstance = false;
mLaunchSingleTask = false;
mLaunchTaskBehind = false;
mLaunchFlags = 0;
mLaunchBounds = null;
mNotTop = null;
mDoResume = false;
mStartFlags = 0;
mSourceRecord = null;
mInTask = null;
mAddingToTask = false;// 表示是否在传入的inTask中启动Actiivty,后面会根据实际情况重新设置该变量
mReuseTask = null;
mNewTaskInfo = null;
mNewTaskIntent = null;
mSourceStack = null;
mTargetStack = null;
mMovedOtherTask = false;
mMovedToFront = false;
mNoAnimation = false;
mKeepCurTransition = false;
mAvoidMoveToFront = false;
mVoiceSession = null;
mVoiceInteractor = null;
}
在正式开始掰持掰持上述源码前,我们先来捣鼓捣鼓几个概念,因为源码中会有涉及到,当然这部分知识我在博客中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);
启动Activity常用Flag值 | 对应特点 |
---|---|
FLAG_ACTIVITY_NEW_TASK | 将Activity放入一个新启动的Task |
FLAG_ACTIVITY_CLEAR_TASK | 启动Activity时,将目标Activity关联的Task清除,再启动该Task,将该Activity放入该Task,也就是说,这个新启动的activity变为了这个空Tas的根activity.所有老的activity都结束掉。该flags跟FLAG_ACTIVITY_NEW_TASK配合使用 |
FLAG_ACTIVITY_CLEAR_TOP | 启动非栈顶Activity时,先清除该Activity之上的Activity。例如Task已有A、B、C三个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) {//可以放入一个已经存在的Task栈
if (mLaunchSingleInstance) {//启动模式是LAUNCH_SINGLE_INSTANCE,那么因为其是一种全局唯一的,需要进行搜索遍历
/*
findActivityLocked方法根据传入的Intent和ActivityInfo这两个参数可以获取一个Activity的包名,
该方法会从栈顶至栈底遍历ActivityStack中的所有Activity,如果包名匹配成功,就返回
*/
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
/*
该方法的功能是找到目标ActivityRecord(target)所在的任务栈(TaskRecord),如果找到,则返回栈顶的ActivityRecord,否则,返回null
*/
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所属TaskRecord移动到顶端,必要时会进行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;
}
//根据intent情况设置TaskRecord
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已经移动到了栈顶了。
到现在为止,我们已经可以复用的ActivityRecord的TaskRecord移动到交互栈顶。这时候还没有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所在的TaskRecord处理已经完全完结了,此时已经将TaskRecord移动到栈顶位置了,这其中的各种切换逻辑真的是眼花缭乱啊,让人搞得晕头转向!
存在复用ActivityRecord处理的处理已经分析完毕了,各位小伙们真的理解了吗!我想没有,因为我也么有绕出来,其中涉及的各种场景太多了,看来还是得带入实际情况进行分析,但是这个就脱离我们本篇的范畴了,因为我们本篇重点讲解Activity的启动主流程!我们这里还是简单的对存在复用ActivityRecord处理小结一下,经过上述繁琐的处理对于可复用的的Activity所在的TaskRecord已经移动到栈顶位置了,其基本的调用流程如下:
AS.startActivityUnchecked(...)
mReusedActivity.task.performClearTaskForReuseLocked(...)//清除task中复用的activity上面的activity
AS.setTargetStackAndMoveToFrontIfNeeded(...)// 将复用ActivityRecord所属TaskRecordy和ActivityStack移动到顶端,必要时会进行task的清理工作
AS.setTaskFromIntentActivity(...)//根据intent的情况对复用的Task进行调整
如果读者朋友们,只想从整理上了解Activity的启动流程,那么第二大章节阅读过程中如果有问题也没有用关系,因为这个并不牵涉到整体流程的分析。
当存在复用ActivityRecord时,经过前面章节一系列的处理此时已将将可复用activty替换成现在的目标activty,也就不用新建task了。那么生活还得继续,让我们跳出reusedActivity不为空的情况,接着继续后续的分析。
//[ActivityStarter.java]
/* 这里的sourceRecord是指发起调用者
r是指本次的将要启动的Activity
startFlags为启动目标Activity设置的flag值
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) {
// 该类情况表示要在一个新的任务中启动Activity
newTask = true;
// 重用或者新建task
setTaskFromReuseOrCreateNewTask(taskToAffiliate);//详见章节2.10.1
...
}
/*
当mSourceRecord不为空,把新的ActivityRecord绑定到启动者的TaskRecord上。
一般情况下,mSourceRecord就是调用者,譬如通常的Launcher启动或者发起端的启动
但也有特殊情况,举个例子,如果启动模式为singleTask,栈中又不存在相同的Activity时,
mSourceRecord就是栈顶的Activity
*/
else if (mSourceRecord != null) {
...
// 不是新建task的,重用原activity的task
// 该类情况下,宿主栈就是调用者Activity所在的ActivityStack。
// 处理方式也大同小异,把宿主任务挪到栈顶,针对launchFlags做一些调整
final int result = setTaskFromSourceRecord();//详见章节2.10.2
if (result != START_SUCCESS) {
return result;
}
} else if (mInTask != null) {//启动时指定了目标栈(mInTask),ActivityRecord绑定到mInTask,在指定的任务栈中启动Activity
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 {
//该类情况表示既不是从一个Activity启动,也不是在新的任务中启动,都不是则直接找焦点的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;
//此时的发起端Actiivty所在的TaskRecord就是处于sourceStack栈顶,所以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, //待启动的ActivityRecord
boolean newTask, //是否需要在新的任务中启动Activity
boolean keepCurTransition,//是否需要立即显示Activity。有些需要Pending的Activity,该值为false;对于初次对于此处而言,该值为true
ActivityOptions options
) {
//rTask即之前创建的TaskRecord,或者为查找到的可复用的TaskRecord
TaskRecord rTask = r.task;
final int taskId = rTask.taskId;//获取taskid
//表示宿主栈ActivityStack中没有历史任务,或者强制要求在新的任务中启动Activity
// 既然是一个新任务,那么就需要需要将任务插入宿主栈顶
if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
insertTaskAtTop(rTask, r);//插入新创建或复用的TaskRecord到栈顶
mWindowManager.moveTaskToTop(taskId);//同时在Windowmanager中也移动到栈顶
}
TaskRecord task = null;
// 进入该条件,表示需要在一个已有的任务中启动Activity
// 先设置一个标志位,表示是否需要启动Activity,默认当然是要显示;
// 但是当目标任务之上有全屏的Activity时,该标志位被置为false
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) {
// 如果目标任务之上的某个任务包含全屏显示的Activity,则不需要显示目标Activity
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");
}
// 以上完成的操作就是将待显示的任务放到了宿主栈的栈顶位置,
// 接下来,需要将待显示的ActivityRecord放到任务的栈顶
task = r.task;
//当前启动的Activity加到所属Task栈顶中
task.addActivityToTop(r);
// 将一个新的ActivityRecord添加到任务栈顶后,需要重新调整FrontOfTask
task.setFrontOfTask();
r.putInHistory();// 标记目标ActivityRecord已经放置到目标栈中
/*
如果当前ActivityStack不为 HomeStack,或者该ActivityStack中activity个数不为0,即宿主栈中已经有Activity
*/
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 {
// 进入该分支,表示当前的ActivityStack中还没有任何Activity,则不需要设置任何Activity启动相关的动画
// 只是将待启动的Activity绑定到窗口上
addConfigOverride(r, task);
ActivityOptions.abort(options);
options = null;
}
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
}
void addConfigOverride(ActivityRecord r, TaskRecord task) {
final Rect bounds = task.updateOverrideConfigurationFromLaunchBounds();
// 将待启动的Activity绑定到窗口上
mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId, r.info.configChanges,
task.voiceSession != null, r.mLaunchTaskBehind, bounds, task.mOverrideConfig,
task.mResizeMode, r.isAlwaysFocusable(), task.isHomeTask(),
r.appInfo.targetSdkVersion);
r.taskConfigOverride = task.mOverrideConfig;
}
该方法的主要主要执行如下的两大逻辑:
将ActivityRecord放到目标任务的栈顶位置。注意,这里有两个栈顶位置:一个是ActivityRecord在TaskRecord中的位置,另一个是TaskRecord在ActivityStack中的位置。前一个是肯定的,但后一个,还得根据实际的情况决定
将待启动的ActivityRecord绑定到了一个窗口。与此同时,Activity启动的动画也在此设置。为了省略分之细节,所以与WMS交互的窗口操作逻辑就不放出来了
总之经过以上的重重步骤,此时目标Activity对应的Task也创建了,也把当前启动的Activity加入到Task正确的位置,ActivityStack也移动到了正确位置。此时本章节就分析到这里了!
阅读源码是很操蛋的事情,同样的如果将太多的逻辑放在一篇中我想小伙们也会阅读起来也会操蛋,失去耐心的的,所以本篇章就先到这里了。分析至此我们对前面的篇章做一个小结,我们前面主要干了如下相关的事情:
并且通过前面的博文分析,小伙们心里应该有了如下的知识图谱:
好了本篇博客真的只能到此了,虽然本人耗费了很多的时间来对Activity启动涉及的Task和ActivityStack等调度相关的知识点来进行分析和讲解,但是这其中牵涉的东西太多了,并且由于个人能力有限,自我感觉依然分析的不是很清晰,只能大伙见谅了。如果小伙们喜欢欢迎点赞或者能和我讨论关于本篇的知识点!如果小伙们对Activity的启动过程中Task和Stack还有疑问的,可以参见博客Activity启动流程(三)-Activity Task调度算法复盘分析,在该篇中会以实际案例出发来阐述Task和Stack相关的调度情况!
参考博客:
https://www.lizenghai.com/archives/94931.html#getReusableIntentActivity_Activity