Android四大组件之一-Activity实现原理分析
排版:Vincent Chau
前言:
这篇文章是我花费时间最久的一篇文章,整整的两个月。整个流程繁琐是一个方面的原因,另外一个原因是我想尽可能的把整个流程的逻辑尽可能详细的一一描述出来,以及结合到我们项目中遇到的一些问题来进行解释,毕竟,我们学习Activity的启动原理的目的之一,就是为了方便我们更好的去排查解决问题,所以,这应该是网上可以搜到的关于Activity启动流程中最详细和完整的文章了。
本篇文章主要会讲以下内容:
1.Activity启动流程的基本介绍;
2.APP侧启动Activity的流程;
3.系统侧处理请求启动Activity的流程;
4.APP收到系统通知后生成Activity和执行其生命周期的完整流程;生命和唤起Activity的流程;
5.一些关于Activity的扩展性问题;
6.总结
PS:本文基于android13的源码进行讲解,推荐阅读时间1小时。
一.Activity启动流程的基本介绍
Activity启动基本流程如下:
1.APP首先通知系统侧去执行相关流程。
2.系统侧首先暂停栈顶的应用界面,如果进程不存在,还需要去尝试创建相关进程。
3.通知APP去完成Activity的创建以及执行其生命周期,
4.系统收到创建成功的回调后,通知上一个应用执行onStop或onDestory进行收尾。
所以按照以上的基本流程,同一个应用内,页面A跳转页面B的话并且调用finish的话,整个生命周期流程应该是如下这样的:
为什么流程是这样的?这样的设计又有什么合理性?以及系统又是在什么时候通知A或者B去执行对应生命周期的呢?接下来,我们就带着这些问题,一起去了解一下Activity启动的完整流程。
二.APP侧启动Activity的流程
2.1 APP侧启动简介:
2.1.1 启动主要流程
app侧启动activity,其实主要分为三个流程:
Activity或Context完成相关的启动调用; 通过代理类Instrumentation中的方法完成调用;
通过ActivityTaskManager的binder应用,完成对系统侧的通知。
2.1.2 APP侧核心类介绍
2.2 Activity或Context完成相关的启动调用;
这里的启动Activity的流程,要区分调用对象是Activity还是Context类型的。
Activity继承自Context类,虽然Context中已经有了startActivity方法的实现,但是Activity中重写了startActivity方法。所以调用者的对象不一样,执行流程是不一样的。
我们先看一下Activity中的实现:
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
@Override
public void startActivity(Intent intent, @NullableBundle options) {
...
if(options != null) {
startActivityForResult(intent, -1, options);
} else{
// Note we want to go through this call for compatibility with
// applications that may have overridden the method.
startActivityForResult(intent, -1);
}
}
public void startActivityForResult(@RequiresPermissionIntent intent, int requestCode,
@NullableBundle options) {
...
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
if(ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
}
首先,startActivity会调用到重载方法startActivity,最终都会调用到startActivityForResult方法。startActivityForResult这个方法中,会调用到Instrumentation中的execStartActivity方法,这里我们注意一下参数,等会会和ContextImpl中启动的参数相对比。
ContextImpl中的相关实现如下:
public void startActivity(Intent intent) {
warnIfCallingFromSystemProcess();
startActivity(intent, null);
}
@Override
public void startActivity(Intent intent, Bundle options) {
warnIfCallingFromSystemProcess();
...
mMainThread.getInstrumentation().execStartActivity(
getOuterContext(), mMainThread.getApplicationThread(), null,
(Activity) null, intent, -1, options);
}
@Override
ContextImp中则直接是调用了execStartActivity方法。
同样都是Instrumentation中的execStartActivity方法,我们来看下参数的区别:
所以,无论哪种形式启动,最终都是调用到Instrumentation中的execStartActivity方法。Activity和Context中的startActivity方法,穿惨两者的区别,其实就是Activity的启动时,token/target/requestCode等参数有值,而这些参数都是为forResult准备的。虽然Activity中重写了startActivity方法,但是其流程上和Context仍然是一样的,调用了Instrumentation中的execStartActivity方法。而Activity中的startActivityForResult方法,虽然也是调用了Instrumentation中的execStartActivity方法,参但是传参不一样。
2.3 Instrumentation中的相关流程
Instrumentation中的启动流程还是比较简单的,只有两个功能:
1.监控Activity启动;
2.调用AMS中方法。
我们来挨个介绍下。
2.2.1 监控Activity启动
如果我们调用Instrumentation中的addMonitor方法添加ActivityMonitor对象,则会添加观察者对象。这个观察者主要就是观察Activity的启动,甚至于这个观察者还可以通过返回值,来决定是否阻断Activity的启动流程。
if(mActivityMonitors !=null) {
synchronized(mSync) {
finalint N = mActivityMonitors.size();
for(int i=0; i<N; i++) {
finalActivityMonitor am = mActivityMonitors.get(i);
ActivityResult result =null;
if(am.ignoreMatchingSpecificIntents()) {
if(options==null) {
options=ActivityOptions.makeBasic().toBundle();
}
result = am.onStartActivity(who, intent, options);
}
if(result !=null) {
am.mHits++;
//直接返回,不启动
return result;
} elseif(am.match(who, null, intent)) {
am.mHits++;
if(am.isBlocking()) {
return requestCode >=0? am.getResult() : null;
}
break;
}
}
}
}
2.2.2 调用AMS中方法
首先,ActivityTaskManager.getService()方法中,通过ServiceManager获取到系统侧的ActivityTaskManagerService的引用binder。
然后,调用binder方法startActivity通知系统去完成Activity的启动流程。
相关代码人如下:
int result = ActivityTaskManager.getService().startActivity(whoThread,
who.getOpPackageName(), who.getAttributionTag(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()), token, target,
requestCode, 0, null, options);
checkStartActivityResult(result, intent);
publicstaticvoidcheckStartActivityResult(int res, Object intent){
if(!ActivityManager.isStartResultFatalError(res)) {
return;
}
switch(res) {
caseActivityManager.START_INTENT_NOT_RESOLVED:
thrownewActivityNotFoundException()
...
}
值得注意的是,如果调用系统方法的最终返回值result不是sucess,则会根据错误码result来抛出对应的异常,所以,我们可以根据不同的异常类型,来判断到底是何原因导致启动失败。
最后我们整理一下传递给系统侧的参数,后面系统侧会被用到。
三.系统侧处理启动的请求
系统侧的核心类介绍:
系统侧收到请求后,主要会完成以下几件事:
上面的这些主流程,我们来一一详细解释。
3.1 生成ActivityStarter开启流程
3.1.1 生成ActivityStarter对象
ActivityTaskManagerService中的startActivity方法收到请求后,会直接调用startActivityAsUser方法完成开启流程,所以下面的代码也都是startActivityAsUser方法中的。
首先,根据intent和reason通过obtainStarter方法构造生成ActivityStarter对象,这里构造ActivityStarter使用了设计模式中的享元模式和建造者模式。必要的参数是intent和reason,这两个值会添加到ActivityStarter中的Request对象上。
getActivityStartController().obtainStarter(intent, "startActivityAsUser")
3.1.2 添加参数
然后,给Request添加一些其它的参数。
.setCaller(caller)
.setCallingPackage(callingPackage)
.setCallingFeatureId(callingFeatureId)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(bOptions)
.setUserId(userId)
所以,我们理一下,Request中共有以下参数是赋值了。
最后,通过execute();方法开启整个Activity的启动流程。
总结一下,这个环节就是首先利用ActivityStartController生成ActivityStart对象,然后添加必要的启动参数,这些参数最终都会被记录到ActivityStart.Request这个对象当中,最后通过execute方法开启流程。
3.2 execute流程
该流程主要是前期的准备工作,比如成员变量resolveInfo/activityInfo赋值等,以及一些合法性校验。
主要包含完成了以下4步:
流程1:给Request中的resolveInfo和activityInfo赋值;
流程2:执行重载进程逻辑;
流程3:执行下一个启动流程;
流程4:回收ActivityStarter对象。
相关调用出代码如下:
publicclassActivityStarter{
int execute() {
try{
//1.给Request中的resolveInfo和activityInfo赋值;
if(mRequest.activityInfo ==null) {
mRequest.resolveActivity(mSupervisor);
}
...
//2.执行重载进程逻辑;
res = resolveToHeavyWeightSwitcherIfNeeded();
if(res !=START_SUCCESS) {
return res;
}
...
//3.执行下一个启动流程;
res = executeRequest(mRequest);
...
} finally{
//4.回收ActivityStarter对象;
onExecutionComplete();
}
}
}
3.2.1 resolveInfo和activityInfo赋值
Request对象中,存在resolveInfo和activityInfo两个对象,resolveInfo对应在manifest中的节点配置信息,activityInfo对应Activity的配置信息。很明显,activityInfo的范围比resolveInfo更小,因为service/broadcast的配置也都属于resolveInfo中的信息。
对这两个对象赋值,主要是通过Request中的resolveActivity方法来实现的。
int execute() {
if(mRequest.activityInfo ==null) {
mRequest.resolveActivity(mSupervisor);
}
}
//ActivityStarter.Request
void resolveActivity(ActivityTaskSupervisor supervisor) {
realCallingPid =Binder.getCallingPid();
realCallingUid =Binder.getCallingUid();
...
resolveInfo = supervisor.resolveIntent(intent, resolvedType, userId,0/* matchFlags */,computeResolveFilterUid(callingUid, realCallingUid, filterCallingUid));
if(resolveInfo ==null) {
if(profileLockedAndParentUnlockingOrUnlocked) {
resolveInfo = supervisor.resolveIntent(intent, resolvedType, userId, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,computeResolveFilterUid(callingUid, realCallingUid,filterCallingUid));
}
}
activityInfo = supervisor.resolveActivity(intent, resolveInfo, startFlags, profilerInfo);
if(activityInfo !=null) {
intentGrants = supervisor.mService.mUgmInternal.checkGrantUriPermissionFromIntent(intent, resolvedCallingUid, activityInfo.applicationInfo.packageName,UserHandle.getUserId(activityInfo.applicationInfo.uid));
}
}
//ActivityStarter
resolveInfo和activityInfo分别通过ActivityTaskSupervisor的resolveIntent和resolveActivity方法进行查询和赋值。
所以,我们先来看下resolveInfo的获取流程:
publicclassActivityTaskSupervisor{
ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId, int flags, int filterCallingUid) {
...
return mService.getPackageManagerInternalLocked().resolveIntent(intent, resolvedType, modifiedFlags, privateResolveFlags, userId, true,filterCallingUid);
}
}
//android13中是PackageManagerInternalBase,其它版本是PackageManagerService.PackageManagerInternalImpl
//PackageManagerInternalBase.hava
publicclassPackageManagerInternalBase{
publicfinalResolveInfo resolveIntent(Intent intent, String resolvedType, ...){
return getResolveIntentHelper().resolveIntentInternal(snapshot(),intent, resolvedType, flags, privateResolveFlags, userId, resolveForStart,filterCallingUid);
}
}
//ResolveIntentHelper.java
publicclassResolveIntentHelper{
publicResolveInfo resolveIntentInternal(Computer computer, Intent intent, String resolvedType,...)
...
finalList<ResolveInfo> query = computer.queryIntentActivitiesInternal(intent,resolvedType, flags, privateResolveFlags, filterCallingUid, userId,resolveForStart, true/*allowDynamicSplits*/);
...
finalResolveInfo bestChoice = chooseBestActivity(computer, intent, resolvedType, flags, privateResolveFlags, query, userId, queryMayBeFiltered);
return bestChoice;
}
}
//ComputerEngine.java
publicclassComputerEngine{
publicfinal@NonNullList<ResolveInfo> queryIntentActivitiesInternal(Intent intent,String resolvedType,...){
finalString pkgName = intent.getPackage();
ComponentNamecomp= intent.getComponent();
List<ResolveInfo> list =Collections.emptyList();
if(comp!=null) {
//显式
finalActivityInfo ai = getActivityInfo(comp, flags, userId);
finalResolveInfo ri =newResolveInfo();
ri.activityInfo = ai;
list =newArrayList<>(1);
list.add(ri);
} else{
//隐式
QueryIntentActivitiesResult lockedResult = queryIntentActivitiesInternalBody();
list = lockedResult.result;
}
return skipPostResolution ? list:...;
}
protectedActivityInfo getActivityInfoInternalBody(ComponentName component,@PackageManager.ResolveInfoFlagsBitslong flags, int filterCallingUid, int userId) {
ParsedActivity a = mComponentResolver.getActivity(component);
AndroidPackage pkg = a ==null? null: mPackages.get(a.getPackageName());
if(pkg !=null&& mSettings.isEnabledAndMatch(pkg, a, flags, userId)) {
...
returnPackageInfoUtils.generateActivityInfo(pkg, a, flags, ps.getUserStateOrDefault(userId), userId, ps);
}
if(resolveComponentName().equals(component)) {
returnPackageInfoWithoutStateUtils.generateDelegateActivityInfo(mResolveActivity, flags, PackageUserStateInternal.DEFAULT, userId);
}
returnnull;
}
public@NonNullQueryIntentActivitiesResult queryIntentActivitiesInternalBody(...){
...
}
}
//ActivityTaskSupervisor.java
我们可以看到,通过层层传递,最终通过ResolveIntentHelper中的resolveIntentInternal方法来实现的。
首先,查询出所有符合intent中条件的,返回一个List集合。queryIntentActivitiesInternal方法中我们可以得知,优先显示查找,显示不存在时,才会选择隐式的查找方式。
最后从符合条件的List中选择最合适的那个进行返回。这里具体的查找的业务逻辑就不过多描述了,有兴趣的读者可以自行查询。
接下来我们来看我们先来看resolveActivity的获取流程:
//ActivityTaskSupervisor.java
publicclassActivityTaskSupervisor{
//这里的rInfo是上面查找出来的
ActivityInfo resolveActivity(Intent intent, ResolveInfo rInfo, int startFlags, ProfilerInfo profilerInfo) {
finalActivityInfo aInfo = rInfo !=null? rInfo.activityInfo : null;
if(aInfo !=null) {
//这里添加ComponentName,后面会用到
intent.setComponent(newComponentName(aInfo.applicationInfo.packageName, aInfo.name));
...
finalString intentLaunchToken = intent.getLaunchToken();
if(aInfo.launchToken ==null&& intentLaunchToken !=null) {
aInfo.launchToken = intentLaunchToken;
}
}
return aInfo;
}
}
这里我们看到,虽然名字叫resolveActivity,但是实际上并没有执行什么解析的操作,而是直接使用上一流程中查找出来的ResolveInfo对象中的ActivityInfo,在校准launchToken属性后,就直接返回了。
至此,Request中的resolveInfo和activityInfo都已经有值了。
3.2.2 重载进行判断
通过resolveToHeavyWeightSwitcherIfNeeded方法进行重载判断。
这个流程中,根据注释中的翻译,如果当前进程是一个重载进程,而另一个不同的重载进程正在运行,则切换到另外一个进程进行启动请求。
这个逻辑不是主流程的,所以这里我们就不深入讨论了。
3.2.3 executeRequest流程
之前的传入以及查找到的值都会被添加到了ActivityStarter.Request对象上,调用executeRequest方法传入mRequest,开启下一个流程。
具体内容我们下一小节详细讲解。
3.2.4 onExecutionComplete回收
这里就是典型的享元模式了,因为上面executeRequest方法执行完,代表整个流程执行完成,则使用onExecutionComplete方法对ActivityStarter对象进行回收。
classActivityStarter{
privatevoidonExecutionComplete(){
mController.onExecutionComplete(this);
}
}
//ActivityStartController.java
publicclassActivityStartController{
voidonExecutionComplete(ActivityStarter starter){
if(mLastStarter == null) {
mLastStarter = mFactory.obtain();
}
mLastStarter.set(starter);
mFactory.recycle(starter);
}
}
//ActivityStarter.java
3.3 executeRequest环节
该流程主要是对准备数据的二次加工使之变成后面可用数据,并且做一些权限的检查,以及生成ActivityRecord对象。
主要分成以下几项:
1.入参准备
2.打印日志,代表准备工作完成,正式开始启动流程;
3.确定forResult返回对象;
4.入参校验;
5.启动权限检查
6.后台启动权限检查
7.构建ActivityRecord对象
8.进入下一阶段流程
classActivityStarter{
privateint executeRequest(Request request) {
//1.把Request中的成员变量,复制给方法内的变量,供后面使用;
mLastStartReason = request.reason;
...
finalIApplicationThreadcaller= request.caller;
...
//2.打印日志,代表准备工作完成,正式开始启动流程;
if(err ==ActivityManager.START_SUCCESS) {
Slog.i(TAG, "START u"+ userId +" {"+ intent.toShortString(true, true, true, false)+"} from uid "+ callingUid);
}
//3.
ActivityRecord sourceRecord =null;
ActivityRecord resultRecord =null;
if(resultTo !=null) {
sourceRecord =ActivityRecord.isInAnyTask(resultTo);
...
}
//4.入参校验
if(err ==ActivityManager.START_SUCCESS && intent.getComponent() ==null) {
// We couldn't find a class that can handle the given Intent.
// That's the endof that!
err =ActivityManager.START_INTENT_NOT_RESOLVED;
}
...
//5.启动权限检查
boolean abort =!mSupervisor.checkStartAnyActivityPermission(...)
//6.后台启动权限检查
restrictedBgActivity = shouldAbortBackgroundActivityStart();
//7.构建ActivityRecord对象
finalActivityRecord r =newActivityRecord.Builder(mService)....build();
mLastStartActivityRecord = r;
//8.进入下一阶段流程
mLastStartActivityResult = startActivityUnchecked(...)
return mLastStartActivityResult;
}
}
3.3.1 入参准备
privateint executeRequest(Request request) {
mLastStartReason = request.reason;
mLastStartActivityTimeMs =System.currentTimeMillis();
mLastStartActivityRecord =null;
finalIApplicationThreadcaller= request.caller;
Intent intent = request.intent;
NeededUriGrants intentGrants = request.intentGrants;
String resolvedType = request.resolvedType;
ActivityInfo aInfo = request.activityInfo;
ResolveInfo rInfo = request.resolveInfo;
finalIVoiceInteractionSession voiceSession = request.voiceSession;
finalIBinder resultTo = request.resultTo;
String resultWho = request.resultWho;
int requestCode = request.requestCode;
int callingPid = request.callingPid;
int callingUid = request.callingUid;
String callingPackage = request.callingPackage;
String callingFeatureId = request.callingFeatureId;
finalint realCallingPid = request.realCallingPid;
finalint realCallingUid = request.realCallingUid;
finalint startFlags = request.startFlags;
finalSafeActivityOptionsoptions= request.activityOptions;
Task inTask = request.inTask;
TaskFragment inTaskFragment = request.inTaskFragment;
}
把Request中的成员变量,赋值给方法内的临时变量,供后面使用,这里,我们重点记录以下几个,后面会用到。
3.3.2 打印启动日志
第二块逻辑代码如下:
WindowProcessController callerApp =null;
//进程判断
if(caller!=null) {
callerApp = mService.getProcessController(caller);
if(callerApp !=null) {
callingPid = callerApp.getPid();
callingUid = callerApp.mInfo.uid;
} else{
Slog.w(TAG, "Unable to find app for caller "+caller+" (pid="+ callingPid
+") when starting: "+ intent.toString());
err =START_PERMISSION_DENIED;
}
}
//打印启动日志
finalint userId = aInfo !=null&& aInfo.applicationInfo !=null
? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
if(err ==ActivityManager.START_SUCCESS) {
Slog.i(TAG, "START u"+ userId +" {"+ intent.toShortString(true, true, true, false)
+"} from uid "+ callingUid);
}
int err =ActivityManager.START_SUCCESS;
主要做了两块逻辑:
1.首先进行一个合法性校验,判断caller是否是正常的进程,如果是,才会继续执行。否则返回错误码:START_PERMISSION_DENIED
2.打印一条启动日志,这个日志,是一定会有的,并不需要debug环境。如果看到log中有了这条日志,就证明已经走到了系统侧的流程了。
下面的日志就是一个样例:
START u0{cmp=com.xt.client/.activitys.test.Test1Activity} from uid 10235
u0:目标Activity归属进程,如果进程还未创建,就是0;
cmp=com.xt.client/.activitys.test.Test1Activity:启动的目标Activity;
Uid 10235:调用者进程。
3.3.3 确定forResult返回对象
接下来就是给sourceRecord和resultRecord对象赋值,这两个对象,主要是通过startActivityForResult()启动时用来执行回调的。
sourceRecord代表从哪个Activity发起的启动请求,
resultRecord代表从有返回结果时通知到哪个Activity。
这两者仅在resultTo不为空时才会有值,也就是说只有调用startActivityForResult启动时,才会值。
classActivityStarter{
privateint executeRequest(Request request) {
...
ActivityRecord sourceRecord =null;
ActivityRecord resultRecord =null;
if(resultTo !=null) {
sourceRecord =ActivityRecord.isInAnyTask(resultTo);
if(sourceRecord !=null) {
if(requestCode >=0&&!sourceRecord.finishing) {
resultRecord = sourceRecord;
}
}
}
finalint launchFlags = intent.getFlags();
if((launchFlags &Intent.FLAG_ACTIVITY_FORWARD_RESULT) !=0&& sourceRecord !=null) {
if(requestCode >=0) {
returnActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
}
}
}
}
1.当requestCode>0并且sourceRecord没有被finish,就会把sourceRecord赋值给resultRecord。
2.如果是通过forResult的方式,并且requestCode>=0时,这种情况是要有返回值的。这种情况,是不能使用FLAG_ACTIVITY_FORWARD_RESULT参数的,否则返回错误START_FORWARD_AND_REQUEST_CONFLICT
3.3.4 参数校验
上一流程3.2.1中,如果找到了对应的配置,则会给对应的参数赋值。而如果没有找到,则这些参数就是空的,所以这里进行参数校验检查,看已经有值的这些参数是否满足启动的需求。
首先,检查3.2.1中赋值的intent中的ComponentName是否为空,如果为空,则代表manifest未配置。
if(err ==ActivityManager.START_SUCCESS && intent.getComponent() ==null) {
// We couldn't find a class that can handle the given Intent.
// That's the endof that!
err =ActivityManager.START_INTENT_NOT_RESOLVED;
}
然后,检查Request中的activityInfo是否为空,如果为空,返回错误码START_CLASS_NOT_FOUND,代表类不存在。
if(err ==ActivityManager.START_SUCCESS && aInfo ==null) {
// We couldn't find the specific class specified in the Intent.
// Also the end of the line.
err = ActivityManager.START_CLASS_NOT_FOUND;
}
继续做检查,如果是语音会话启动的,确保安全。如果失败,返回错误码START_NOT_VOICE_COMPATIBLE,代表不支持语音唤醒。
if(err ==ActivityManager.START_SUCCESS && sourceRecord !=null
&& sourceRecord.getTask().voiceSession !=null) {
//If this activity is being launched as part of a voice session, we need to ensure
// that it is safe to do so. If the upcoming activity will also be part of the voice
// session, we can only launch it if it has explicitly said it supports the VOICE
// category, or it is a part of the calling app.
if((launchFlags & FLAG_ACTIVITY_NEW_TASK) ==0
&& sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {
try{
intent.addCategory(Intent.CATEGORY_VOICE);
if(!mService.getPackageManager().activitySupportsIntent(
intent.getComponent(), intent, resolvedType)) {
Slog.w(TAG, "Activity being started in current voice task does not support "
+"voice: "+ intent);
err =ActivityManager.START_NOT_VOICE_COMPATIBLE;
}
} catch(RemoteException e) {
Slog.w(TAG, "Failure checking voice capabilities", e);
err =ActivityManager.START_NOT_VOICE_COMPATIBLE;
}
}
}
if(err ==ActivityManager.START_SUCCESS && voiceSession !=null) {
//If the caller is starting a new voice session, just make sure the target
//is actually allowing it torun this way.
try{
if(!mService.getPackageManager().activitySupportsIntent(intent.getComponent(),
intent, resolvedType)) {
Slog.w(TAG,
"Activity being started in new voice task does not support: "+ intent);
err =ActivityManager.START_NOT_VOICE_COMPATIBLE;
}
} catch(RemoteException e) {
Slog.w(TAG, "Failure checking voice capabilities", e);
err =ActivityManager.START_NOT_VOICE_COMPATIBLE;
}
}
最后,判断一下,如果err!=START_SUCCESS,则证明上面的检查不过,则返回启动失败。
if(err !=START_SUCCESS) {
if(resultRecord !=null) {
resultRecord.sendResult(INVALID_UID, resultWho, requestCode, RESULT_CANCELED,
null/*data*/, null/* dataGrants */);
}
SafeActivityOptions.abort(options);
return err;
}
3.3.5 启动权限检查
相关代码如下:
privateint executeRequest(Request request) {
...
boolean abort =!mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
requestCode, callingPid, callingUid, callingPackage, callingFeatureId,
request.ignoreTargetSecurity, inTask !=null, callerApp, resultRecord,
resultRootTask);
abort |=!mService.mIntentFirewall.checkStartActivity(intent, callingUid,
callingPid, resolvedType, aInfo.applicationInfo);
abort |=!mService.getPermissionPolicyInternal().checkStartActivity(intent, callingUid,
callingPackage);
...
if(abort) {
returnSTART_ABORTED;
}
}
}
classActivityStarter{
首先设置标记位abort,来记录是放弃本次启动,包括下一小节中的后台启动检查也是一样,阻断性的判断,只要有一次true,就会返回START_ABORTED的错误码。
总共有三块判断:
首先,判断应用是否具有启动Activity的权限。是的,启动Activity也需要权限,只是正常应用默认都具有;
然后,判断是否通过防火墙验证;
最后,检查某些敏感的Action类型(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER和Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT),启动者的targetSDK是否为高版本,如果是,则不允许此次操作。
3.3.6 后台启动检查
安卓13中,加入了后台应用启动的判断。如果某个后台的应用直接使用service启动Activity,默认是启动不起来的。
如果没有放弃本次启动的话,则会通过shouldAbortBackgroundActivityStart方法检查是否允许后台启动。也
就是说restrictedBgActivity=true时,最终会放弃本地启动,反之则允许。
boolean restrictedBgActivity =false;
if(!abort) {
restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid,
callingPid, callingPackage, realCallingUid, realCallingPid, callerApp,
request.originatingPendingIntent, request.allowBackgroundActivityStart,
intent, checkedOptions);
}
至于最终如何放弃本次启动的,我们后面会讲。这里我们主要讲一下shouldAbortBackgroundActivityStart方法中是如何进行判断的。
boolean shouldAbortBackgroundActivityStart(...){
finalint callingAppId =UserHandle.getAppId(callingUid);
if(useCallingUidState) {
//系统APP,允许后台启动
if(callingUid ==Process.ROOT_UID || callingAppId ==Process.SYSTEM_UID || callingAppId ==Process.NFC_UID) {
returnfalse;
}
//桌面APP,则也允许后台启动
if(isHomeApp(callingUid, callingPackage)) {
returnfalse;
}
//输入法应用
finalWindowState imeWindow = mRootWindowContainer.getCurrentInputMethodWindow();
if(imeWindow !=null&& callingAppId == imeWindow.mOwnerUid) {
returnfalse;
}
}
//应用是否处于系统豁免名单中
if(useCallingUidState && allowCallingUidStartActivity) {
returnfalse;
}
...略过一些不重要的判断
if(useCallingUidState) {
//如果应用具有START_ACTIVITIES_FROM_BACKGROUND权限,则允许后台启动
if(mService.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid) == PERMISSION_GRANTED) {
returnfalse;
}
//如果最近有活动,则允许。
if(mSupervisor.mRecentTasks.isCallerRecents(callingUid)) {
returnfalse;
}
//设备所有者,则允许
if(mService.isDeviceOwner(callingUid)) {
returnfalse;
}
//如果应用具有系统弹窗权限,则允许
if(mService.hasSystemAlertWindowPermission(callingUid,callingPid, callingPackage)) {
returnfalse;
}
}
//如果应用配置允许后台启动,则允许
if(callerApp !=null&& useCallingUidState) {
if(callerApp.areBackgroundActivityStartsAllowed(appSwitchState)) {
returnfalse;
}
finalArraySet<WindowProcessController> uidProcesses = mService.mProcessMap.getProcesses(callerAppUid);
if(uidProcesses !=null) {
for(int i = uidProcesses.size()- 1; i >=0; i--) {
finalWindowProcessController proc = uidProcesses.valueAt(i);
if(proc != callerApp&& proc.areBackgroundActivityStartsAllowed(appSwitchState)) {
...
returnfalse;
}
}
}
}
Slog.w(TAG, "Background activity start [callingPackage: ");
returntrue;
}
所以我们总结一下,有如下场景,当然,本文中省略了很多场景,实际要比这个更多。
第一类:系统应用/桌面应用/输入法应用;
第二类:应用处于系统豁免白名单中;
第三类:最近有活动,或者设备拥有者。实际上,最近活动这个很难定义,往往可以认为是否。
第四类:具有START_ACTIVITIES_FROM_BACKGROUND/系统弹窗权限。这一类也是我们最常用的,通过应用申请相应的权限,来实现后台弹出Activity的效果。
第五类:看后台进程控制器中的判断,具体实现方法是:BackgroundLaunchProcessController.areBackgroundActivityStartsAllowed()方法。这里就不扩展了。
如果满足以上条件,则restrictedBgActivity=false,否则则为true。最终restrictedBgActivity传递到后面流程,来影响Activity启动流程。
3.3.7 构建ActivityRecord对象
前面所有的检查都做完了,那么接下来就可以准备开始启动了,这里先做一个准备工作,通过建造者模式构建ActivityRecord对象,ActivityRecord对象和APP一侧的Activity一一对应,是Activity的在系统侧的代表。
最后,把新构建的ActivityRecord对象赋值给mLastStartActivityRecord,代表最近一个正在启动的Activity
finalActivityRecord r =newActivityRecord.Builder(mService)
.setCaller(callerApp)
.setLaunchedFromPid(callingPid)
.setLaunchedFromUid(callingUid)
.setLaunchedFromPackage(callingPackage)
.setLaunchedFromFeature(callingFeatureId)
.setIntent(intent)
.setResolvedType(resolvedType)
.setActivityInfo(aInfo)
.setConfiguration(mService.getGlobalConfiguration())
.setResultTo(resultRecord)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setComponentSpecified(request.componentSpecified)
.setRootVoiceInteraction(voiceSession !=null)
.setActivityOptions(checkedOptions)
.setSourceRecord(sourceRecord)
.build();
mLastStartActivityRecord = r;
3.3.8 进入下一个流程
//1.延迟布局
mService.deferWindowLayout();
//2.进入下一环节
result = startActivityInner()
//3.
tartedActivityRootTask = handleStartResult()
//4.
postStartActivityProcessing()
}
privateint startActivityUnchecked(finalActivityRecord r, ActivityRecord sourceRecord,...) {
调用startActivityUnchecked方法,进入下一阶段的启动流程。
startActivityUnchecked返回的错误码,则直接抛给上层,返回给应用层对应的错误码。
3.3 startActivityUnchecked环节
这个环节中,逻辑比较简单,主要有以下几块逻辑,代码如下:
privateint startActivityUnchecked(finalActivityRecord r, ActivityRecord sourceRecord,...) {
//1.延迟布局
mService.deferWindowLayout();
//2.进入下一环节
result = startActivityInner()
//3.
tartedActivityRootTask = handleStartResult()
//4.
postStartActivityProcessing()
}
1.调用mService.deferWindowLayout方法,延迟当前进行的布局。因为页面即将要刷新,继续进行布局没有意义。
2.调用startActivityInner方法,进入下一环节;
3.通过handleStartResult方法,二次检查被拉起的targetActivity处于前台显示;
4.通过postStartActivityProcessing方法,向外发送通知,告之启动完成。
3.4 startActivityInner环节
startActivityInner中,主要负责的工作是给Activity安排一个适合的栈,然后使这个栈显示到前台。
介绍栈,我们先普及一下必备的知识,栈分为子栈和根栈。子栈的话,是必须归属同一个应用的,但是根栈是可以跨应用的。那么什么是子栈还是根栈呢?
在某个页面不断点击返回按钮返回上一界面,只要能够返回到达的页面,都属于同一个根栈。而子栈只是一个应用中,对若干个Activity记录的分组封装。
简单来说,A应用的a页面跳转B应用的b页面,那么a和b页面归属两个子栈,但是同属一个根栈,所以根栈其实是和Affiliate相对应的。
然后我们回到正题,继续看启动流程的代码,如下:
classActivityStarter{
...
int startActivityInner(finalActivityRecord r, ActivityRecord sourceRecord,...) {
//1.初始化ActivityStart的成员变量
setInitialState()
//2.校正mLaunchFlags值
computeLaunchingTaskFlags();
//3.校正sourceRecord
computeSourceRootTask();
//4.计算dreamStopping
boolean dreamStopping =false;
for(ActivityRecord stoppingActivity : mSupervisor.mStoppingActivities) {
if(stoppingActivity.getActivityType()
==WindowConfiguration.ACTIVITY_TYPE_DREAM) {
dreamStopping =true;
break;
}
}
//5.四个Task
finalTask prevTopRootTask = mPreferredTaskDisplayArea.getFocusedRootTask();
finalTask prevTopTask = prevTopRootTask !=null? prevTopRootTask.getTopLeafTask() : null;
finalTask reusedTask = getReusableTask();
...
computeLaunchParams(r, sourceRecord, targetTask);
//6.task权限检查
int startResult = isAllowedToStart(r, newTask, targetTask);
//7.新建或复用Task
finalActivityRecord targetTaskTop = newTask ? null: targetTask.getTopNonFinishingActivity();
if(targetTaskTop !=null) {
startResult = recycleTask(targetTask, targetTaskTop, reusedTask, intentGrants);
if(startResult !=START_SUCCESS) {
return startResult;
}
} else{
mAddingToTask =true;
}
...
if(mTargetRootTask ==null) {
mTargetRootTask = getOrCreateRootTask(mStartActivity, mLaunchFlags, targetTask, mOptions);
}
if(newTask) {
finalTask taskToAffiliate =(mLaunchTaskBehind && mSourceRecord !=null)
? mSourceRecord.getTask() : null;
setNewTask(taskToAffiliate);
} elseif(mAddingToTask) {
addOrReparentStartingActivity(targetTask, "adding to task");
}
//8.修改栈中Activity顺序
mTargetRootTask.startActivityLocked(mStartActivity, topRootTask, newTask, isTaskSwitch, mOptions, sourceRecord);
if(mDoResume) {
//9.进入下一流程
...
}
//10.收尾工作
mSupervisor.mRecentTasks.add(startedTask);
returnSTART_SUCCESS;
}
}
主要包含以下几个环节:
1.初始化ActivityStart中的成员变量
2.校正mLaunchFlags值
3.校正sourceRecord
4.计算dreamStopping
5.四个Task
6.task权限检查
7.新建或复用Task
8.修改栈中Activity顺序
9.进入下一流程
10.收尾工作
3.4.1 初始化ActivityStart的成员变量
classActivityStart{
int startActivityInner(){
setInitialState(r, options, inTask, inTaskFragment, doResume, startFlags, sourceRecord,voiceSession, voiceInteractor, restrictedBgActivity);
...
}
privatevoid setInitialState(...){
mStartActivity = r;
mIntent = r.intent;
mOptions =options;
mCallingUid = r.launchedFromUid;
mSourceRecord = sourceRecord;
mVoiceSession = voiceSession;
mVoiceInteractor = voiceInteractor;
mRestrictedBgActivity = restrictedBgActivity;
...
mLaunchMode = r.launchMode;
...
mDoResume = doResume;
}
}
这里主要是参数的赋值,逻辑代码并不多,所以我们梳理其中参数的含义:
3.4.2 校正mLaunchFlags值
这里主要通过computeLaunchingTaskFlags方法来实现的,重新判断条件,看是否需要添加FLAG_ACTIVITY_NEW_TASK属性。这个属性值提供给后面使用,用来判断是否需要复用task。
主要是再次计算mLaunchFlags的值,如果来源Activity的启动方式是LAUNCH_SINGLE_INSTANCE,或者targetActivity的启动方式是LAUNCH_SINGLE_INSTANCE/LAUNCH_SINGLE_TASK,则给mLaunchFlags添加FLAG_ACTIVITY_NEW_TASK标记。
int startActivityInner(...){
...
computeLaunchingTaskFlags();
...
}
privatevoid computeLaunchingTaskFlags() {
...
if(mInTask ==null) {
if(mSourceRecord ==null) {
// This activity isnot being started from another... in this
// case we -always- start a new task.
if((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) ==0&& mInTask ==null) {
Slog.w(TAG, "startActivity called from non-Activity context; forcing "+
"Intent.FLAG_ACTIVITY_NEW_TASK for: "+ mIntent);
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}
} elseif(mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
// The original activity who is starting us is running as a single
// instance... this new activity it is starting must goon its
// own task.
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
} elseif(isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
// The activity being started is a single instance... it always
// gets launched into its own task.
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}
}
}
我们可以看到,如果是调用者Activity是LAUNCH_SINGLE_INSTANCE类型,或者目标Activity是LAUNCH_SINGLE_INSTANCE/LAUNCH_SINGLE_TASK类型,都会添加到FLAG_ACTIVITY_NEW_TASK属性。
这也符合我们的正常认知,调用者为singleInstance类型,自然不应该和调用者同一个栈。
而目标Activity为singleInstanc或singeTask类型,自然也不会和调用者同一个栈。疑问:singeTask为什么也不会?
至于mInTask不为空的场景,因为不是提供给正常启动流程使用的,所以这里就不扩展分析了。
3.4.3 校正sourceRecord
如果sourceRecord已经被finish了,则需要清空sourceRecord和mSourceRootTask的值。
privatevoid computeSourceRootTask() {
if(mSourceRecord ==null) {
mSourceRootTask =null;
return;
}
if(!mSourceRecord.finishing) {
mSourceRootTask = mSourceRecord.getRootTask();
return;
}
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;
finalTask sourceTask = mSourceRecord.getTask();
if(sourceTask ==null|| sourceTask.getTopNonFinishingActivity() ==null) {
mNewTaskInfo = mSourceRecord.info;
mNewTaskIntent = sourceTask !=null? sourceTask.intent : null;
}
}
mSourceRecord =null;
mSourceRootTask =null;
}
3.4.4 计算dreamStopping
首先,把校正后的mLaunchFlags赋值给intent,
然后,计算dreamStopping。dreamStopping结果在后面3.4.6中使用。
mIntent.setFlags(mLaunchFlags);
boolean dreamStopping =false;
for(ActivityRecord stoppingActivity : mSupervisor.mStoppingActivities) {
if(stoppingActivity.getActivityType()
==WindowConfiguration.ACTIVITY_TYPE_DREAM) {
dreamStopping =true;
break;
}
}
3.4.5 四个Task计算
这4个Task介绍如下:
prevTopRootTask:代表原始的获取焦点的Task。最顶层的rootTask,这个Task中有可能会包含多个子Task。
prevTopTask:获取最终显示在前台的那个Task任务,这个Task是子Task。
reusedTask:代表可重复使用的Task,如果为空则代表没有合适的Task(方法内会判断各种flag标记和启动模式),需要重新创建。
targetTask:如果reusedTask不为空,则就是reusedTask。否则重新通过computeTargetTask方法获取一个。
finalTask prevTopRootTask = mPreferredTaskDisplayArea.getFocusedRootTask();
finalTask prevTopTask = prevTopRootTask !=null? prevTopRootTask.getTopLeafTask() : null;
finalTask reusedTask = getReusableTask();
finalTask targetTask = reusedTask !=null? reusedTask : computeTargetTask();
接下来我们讲4个栈是如何获得的。
prevTopRootTask,直接通过当前显示区域,获取其根栈即可;
prevTopTask,如果prevTopRootTask不为空,则获取prevTopRootTask中的第一个即可。
reusedTask的获取逻辑稍微有一点复杂,这对应的其实也是5种启动模式的核心。这里我们简单介绍下,主要的流程就是判断如果是singeInstance的类型,则会从根容器中寻找对应的ActivityRecord对象并返回,否则从根容器中找到可复用的Task的头部ActivityRecord。
targetTask,则是最终使用的Task。如果reusedTask不为空,则说明找到了复用的栈直接使用。否则,通过computeTargetTask方法去寻找新的或者构造一个新的Task,这里仍然可能为空,比如singeInstance类型就找不到合适的Task。
classActivityStarter{
int startActivityInner(){
...
finalTask targetTask = reusedTask !=null? reusedTask : computeTargetTask();
...
}
privateTask computeTargetTask() {
if(mStartActivity.resultTo ==null&& mInTask ==null&&!mAddingToTask &&(mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) !=0) {
returnnull;
} elseif(mSourceRecord !=null){
return mSourceRecord.getTask();
} elseif(mInTask !=null) {
...
} else{
finalTask rootTask = getOrCreateRootTask(mStartActivity, mLaunchFlags, null/* task */, mOptions);
finalActivityRecordtop= rootTask.getTopNonFinishingActivity();
if(top!=null) {
returntop.getTask();
} else{
rootTask.removeIfPossible("computeTargetTask");
}
}
returnnull;
}
}
classRootWindowContainer{
Task getOrCreateRootTask(){
...
return taskDisplayArea.getOrCreateRootTask(r, options, candidateTask, sourceTask,
launchParams, launchFlags, activityType, onTop);
}
}
classTaskDisplayArea{
//此时 candidateTask =null,sourceTask =null,onTop =true,activityType应用的启动类型,有经典模型/桌面/最近任务等六种
Task getOrCreateRootTask(int windowingMode, int activityType, boolean onTop,Task candidateTask,Task sourceTask){
}
}
computeTargetTask中的逻辑我们就不细讲了,简单来说,就是去寻找匹配的可复用的targetTask,如果找不到,则返回的就是null,就代表需要创建一个的Task。
3.4.6 检查是否允许生成新Task
如果需要新建Task,则检查是否有权限检查生成新task
int startResult = isAllowedToStart(r, newTask, targetTask);
if(startResult !=START_SUCCESS) {
if(r.resultTo !=null) {
r.resultTo.sendResult(INVALID_UID, r.resultWho, r.requestCode, RESULT_CANCELED,
null/*data*/, null/* dataGrants */);
}
return startResult;
}
int isAllowedToStart(ActivityRecord r, boolean newTask, Task targetTask) {
...
}
isAllowedToStart中进行一些合法性校验,判断是否允许创建新的Task。
比如桌面类型就不允许新建Task,后台进程如果没有权限也不允许新建。
如果不允许,则startResult!=START_SUCCESS,这时候通过sendResult通知响应Activity创建失败。
而权限检查通过后,有两块不同的分支逻辑 :
finalActivityRecord targetTaskTop = newTask
? null: targetTask.getTopNonFinishingActivity();
if(targetTaskTop !=null) {
// Recycle the target task for this launch.
//第一块复用Activity逻辑
startResult = recycleTask(targetTask, targetTaskTop, reusedTask, intentGrants);
if(startResult !=START_SUCCESS) {
return startResult;
}
} else{
//第二块复用Task逻辑
mAddingToTask =true;
}
第一块,尝试寻找可复用的Task和Activity,如果找到了可复用Task和Activity,则进行复用,此时startResult!=START_SUCCESS,从而结束掉启动流程。
第二块,没有找到可复用Task和Activity,又分两种场景。如果找到了可复用Task但没有Activity,则mAddingToTask=true。否则mAddingToTask=true。具体的逻辑也是recycleTask中实现的。
3.4.7 复用Task
recycleTask中代码如下,主要有5块逻辑:
int recycleTask(Task targetTask, ActivityRecord targetTaskTop, Task reusedTask,
NeededUriGrants intentGrants) {
// Should not recycle task which isfrom a different user, just adding the starting
// activity to the task.
//逻辑1
if(targetTask.mUserId != mStartActivity.mUserId) {
mTargetRootTask = targetTask.getRootTask();
mAddingToTask =true;
returnSTART_SUCCESS;
}
//逻辑2
setTargetRootTaskIfNeeded(targetTaskTop);
...
//逻辑3
complyActivityFlags(targetTask,
reusedTask !=null? reusedTask.getTopNonFinishingActivity() : null, intentGrants);
//逻辑4
if(mAddingToTask) {
returnSTART_SUCCESS;
}
// The reusedActivity could be finishing, for example of starting an activity with
// FLAG_ACTIVITY_CLEAR_TOP flag. In that case, use the top running activity in the
// task instead.
targetTaskTop = targetTaskTop.finishing
? targetTask.getTopNonFinishingActivity()
: targetTaskTop;
...
//逻辑5
if(mMovedToFront) {
// We moved the task to front, use starting window to hide initial drawn delay.
targetTaskTop.showStartingWindow(true/* taskSwitch */);
} elseif(mDoResume) {
// Make sure the root task and its belonging displayare moved to topmost.
mTargetRootTask.moveToFront("intentActivityFound");
}
// We didn't do anything... but it was needed (a.k.a., client don't use that intent!)
//Andfor paranoia, make sure we have correctly resumed the top activity.
resumeTargetRootTaskIfNeeded();
mLastStartActivityRecord = targetTaskTop;
//逻辑6
return mMovedToFront ? START_TASK_TO_FRONT : START_DELIVERED_TO_TOP;
}
1.如果targetTask的userId和mStartActivity的不一致,说明选择的可复用Task和目标Activity不属于同一个应用,则这个Task自然是无法复用的,所以修改标记位mAddingToTask=true,并且返回;
2.明确前台应该展示哪个Task,这里会计算mMovedToFront的值,明确是否需要切换到前台。
3.complyActivityFlags方法中主要根据mLaunchFlags和启动类型,来进行判断,决定最终是否要新建Task还是复用,这块逻辑我们稍后仔细讲一讲。
4.如果complyActivityFlags方法或者更早之前判断需要创建新的Task,则直接返回。如果不需要创建新的Task,则此时targetTask的top位置的ActivityRecord一定是可复用的那个,比如singleTask的类型,上一步骤会把复用栈中更上层的其它ActivityRecord清空,则我们只需要把targetTask显示到前台。
5.如果需要把task切换到前台,则通过showStartingWindow方法显示切换动画。
6.返回START_TASK_TO_FRONT或者START_DELIVERED_TO_TOP。
接下来,我们详细介绍下complyActivityFlags中的逻辑,这一块和Activity的启动模式息息相关,相关代码如下:
privatevoid complyActivityFlags(Task targetTask, ActivityRecord reusedActivity, NeededUriGrants intentGrants) {
ActivityRecord targetTaskTop = targetTask.getTopNonFinishingActivity();
finalboolean resetTask = reusedActivity !=null&&(mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) !=0;
if(resetTask) {
targetTaskTop = mTargetRootTask.resetTaskIfNeeded(targetTaskTop, mStartActivity);
}
if((mLaunchFlags &(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
==(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
//第一个if判断
...
targetTask.performClearTaskForReuse(true/* excludingTaskOverlay*/);
targetTask.setIntent(mStartActivity);
mAddingToTask =true;
mIsTaskCleared =true;
} elseif((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) !=0
|| isDocumentLaunchesIntoExisting(mLaunchFlags)
|| isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK,
LAUNCH_SINGLE_INSTANCE_PER_TASK)) {
//第二个if判断
finalActivityRecord clearTop = targetTask.performClearTop(mStartActivity,
mLaunchFlags);
if(clearTop !=null&&!clearTop.finishing) {
if(clearTop.isRootOfTask()) {
// Activity aliases may mean we use different intents for the top activity,
// so make sure the task now has the identity of the new intent.
clearTop.getTask().setIntent(mStartActivity);
}
deliverNewIntent(clearTop, intentGrants);
} else{
// A special case: we need tostart the activity because it isnot currently
// running, and the caller has asked to clear the current task to have this
// activity at the top.
mAddingToTask =true;
// Adding the new activity to the same embedded TF of the clear-top activity if
// possible.
if(clearTop !=null&& clearTop.getTaskFragment() !=null
&& clearTop.getTaskFragment().isEmbedded()) {
mAddingToTaskFragment = clearTop.getTaskFragment();
}
if(targetTask.getRootTask() ==null) {
// Target root task got cleared when we all activities were removed above.
//Go ahead andreset it.
mTargetRootTask = getOrCreateRootTask(mStartActivity, mLaunchFlags,
null/* task */, mOptions);
mTargetRootTask.addChild(targetTask, !mLaunchTaskBehind /* toTop */,
(mStartActivity.info.flags & FLAG_SHOW_FOR_ALL_USERS) !=0);
}
}
} elseif((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) ==0&&!mAddingToTask
&&(mLaunchFlags & FLAG_ACTIVITY_REORDER_TO_FRONT) !=0) {
//第三个if判断
finalActivityRecord act = targetTask.findActivityInHistory(mStartActivity.mActivityComponent);
if(act !=null) {
finalTask task = act.getTask();
task.moveActivityToFrontLocked(act);
act.updateOptionsLocked(mOptions);
deliverNewIntent(act, intentGrants);
act.getTaskFragment().clearLastPausedActivity();
} else{
mAddingToTask =true;
}
} elseif(mStartActivity.mActivityComponent.equals(targetTask.realActivity)) {
//第四个if判断
if(targetTask == mInTask) {
//In this case we are bringing up an existing activity from a recent task. We
// dont need toadd a new activity instance ontop.
//这里对应FLAG_ACTIVITY_SINGLE_TOP类型
} elseif(((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) !=0
|| LAUNCH_SINGLE_TOP== mLaunchMode)
&& targetTaskTop.mActivityComponent.equals(mStartActivity.mActivityComponent)
&& mStartActivity.resultTo ==null) {
//In this case the top activity on the task is the sameas the one being launched,
// so we take that as a request to bring the task to the foreground. If the top
// activity in the task is the root activity, deliver this new intent to it if it
// desires.
if(targetTaskTop.isRootOfTask()) {
targetTaskTop.getTask().setIntent(mStartActivity);
}
deliverNewIntent(targetTaskTop, intentGrants);
} elseif(!targetTask.isSameIntentFilter(mStartActivity)) {
//In this case we are launching the root activity of the task, but with a
// different intent. We should start a new instance ontop.
mAddingToTask =true;
} elseif(reusedActivity ==null) {
mAddingToTask =true;
}
} elseif(!resetTask) {
//第五个if判断
//这里对应默认的standard类型
mAddingToTask =true;
} elseif(!targetTask.rootWasReset) {
//In this case we are launching into an existing task that has not yet been started
//from its front door. The current task has been brought to the front. Ideally,
// wed probably like to place this new task at the bottomof its root task, but thats a little hard to do with the current organizationof the code so for now we will just drop it.
targetTask.setIntent(mStartActivity);
}
}
输入主要参数有2个:
targetTask:之前找到的可复用的Task;
reusedActivity:可复的Task中最顶部的ActivityRecord。
第一个if判断:如果mLaunchFlags中有FLAG_ACTIVITY_NEW_TASK或FLAG_ACTIVITY_CLEAR_TASK标记,则绑定mStartActivity和targetTask,然后设置mAddingToTask = true;
第二个if判断:如果mLaunchFlags中有FLAG_ACTIVITY_CLEAR_TOP,或者属于LAUNCH_SINGLE_INSTANCE/LAUNCH_SINGLE_TASK/LAUNCH_SINGLE_INSTANCE_PER_TASK三种类型之一,这三种类型,都是要清空mStartActivity之上所有的Activity,此时mStartActivity就是顶部的ActivityRecord了,则返回此时顶部的ActivityRecord。注意,此时顶部的clearTop和mStartActivity都对应同一个Activity,但是对象是两个。
如果栈顶不为空,并且没有被finish,会去调用deliverNewIntent方法,最终通知到被复用的栈顶Activity的onNewIntent()方法,实现复用流程。
反之,则应该把当前的mStartActivity加入到这个目标Task中。
第三个if判断,如果mLaunchFlags中有FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_REORDER_TO_FRONT标记,并且mAddingToTask=false。则寻找是否有这样的ActivityRecord,如果有则把栈挪到前台。
第四个if判断,如果Task中顶部ActivityRecord就是我们的目标,并且mLaunchFlags中带有FLAG_ACTIVITY_SINGLE_TOP标记或启动模式为LAUNCH_SINGLE_TOP,并且还不是forResult方法启动的,则就可以复用此时栈顶部的ActivityRecord了。复用逻辑和2中一样。否则,设置mAddingToTask=true。
第五个if判断,就是我们最经常使用的standard类型,仅复用task,设置mAddingToTask=true。至此5种启动类型都有对应的处理。
所以,这里总结一下:
如果找到了可复用的Task和ActivityReocrd对象,就会执行newIntent的流程。这时候,返回外层的startResult就是START_TASK_TO_FRONT/START_DELIVERED_TO_TOP,从而结束掉后续的启动流程。
如果只是找到可服用的Task,则mAddingToTask=true。
如果都没找到,则mAddingToTask=false。
3.4.8 新建或复用Task
首先需要确认targetRootTask。
classActivityStarter{
int startActivityInner(){
...
if(mTargetRootTask ==null) {
//确认targetRootTask
mTargetRootTask = getOrCreateRootTask(mStartActivity, mLaunchFlags, targetTask, mOptions);
}
...
}
}
classRootWindowContainer{
...
privateTask getOrCreateRootTask(ActivityRecord r, int launchFlags, Task task,
ActivityOptions aOptions) {
finalboolean onTop =
(aOptions ==null|| !aOptions.getAvoidMoveToFront()) &&!mLaunchTaskBehind;
finalTask sourceTask = mSourceRecord !=null? mSourceRecord.getTask() : null;
return mRootWindowContainer.getOrCreateRootTask(r, aOptions, task, sourceTask, onTop,
mLaunchParams, launchFlags);
}
...
}
通过的是getOrCreateRootTask方法。
如果有sourceRecord时,一般使用的是sourceRecord的rootTask。
但是如果是singleTask/singleInstance等类型时(对应mLaunchTaskBehind标记),则不复用。
然后有两块逻辑,如果newTask=true,说明要新建Task,则执行新建的逻辑。
否则,mAddingToTask=true时,代表需要把Activity关联到当前Task上。
if(newTask) {
finalTask taskToAffiliate =(mLaunchTaskBehind && mSourceRecord !=null)
? mSourceRecord.getTask() : null;
setNewTask(taskToAffiliate);
} elseif(mAddingToTask) {
addOrReparentStartingActivity(targetTask, "adding to task");
}
我们先看第一块逻辑:mSourceRecord不为空并且mLaunchTaskBehind=true时,使用mSourceRecord的Task,传入setNewTask方法。首先,创建一个的task,如果传入值不为空的话,mStartActivity关联taskToAffiliate,其实最终是把mStartActivity归属的task和taskToAffiliate进行关联。
privatevoid setNewTask(Task taskToAffiliate) {
finalboolean toTop =!mLaunchTaskBehind &&!mAvoidMoveToFront;
finalTask task = mTargetRootTask.reuseOrCreateTask(
mNewTaskInfo !=null? mNewTaskInfo : mStartActivity.info,
mNewTaskIntent !=null? mNewTaskIntent : mIntent, mVoiceSession,
mVoiceInteractor, toTop, mStartActivity, mSourceRecord, mOptions);
task.mTransitionController.collectExistenceChange(task);
addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask");
ProtoLog.v(WM_DEBUG_TASKS, "Starting new activity %s in new task %s",
mStartActivity, mStartActivity.getTask());
if(taskToAffiliate !=null) {
mStartActivity.setTaskToAffiliateWith(taskToAffiliate);
}
}
classActivityRercord{
void setTaskToAffiliateWith(Task taskToAffiliateWith) {
if(launchMode != LAUNCH_SINGLE_INSTANCE && launchMode != LAUNCH_SINGLE_TASK) {
task.setTaskToAffiliateWith(taskToAffiliateWith);
}
}
在看第二块逻辑:
mAddingToTask=true代表要加入到当前的targetTask中。
虽然有多种if else的场景,但是其实逻辑都是一致的,都是找到可复用的那个task,赋值给newParent对象。然后把mStartActivity绑定到newParent中。
TaskFragment newParent = task;
if(mInTaskFragment !=null) {
...
} else{
TaskFragment candidateTf = mAddingToTaskFragment !=null? mAddingToTaskFragment : null;
if(candidateTf ==null) {
finalActivityRecordtop= task.topRunningActivity(false/* focusableOnly */,
false/* includingEmbeddedTask */);
if(top!=null) {
candidateTf =top.getTaskFragment();
}
}
if(candidateTf !=null&& candidateTf.isEmbedded()
&& canEmbedActivity(candidateTf, mStartActivity, task) == EMBEDDING_ALLOWED) {
//Use the embedded TaskFragment of the top activity as the new parent if the
// activity can be embedded.
newParent = candidateTf;
}
}
if(mStartActivity.getTaskFragment() ==null
|| mStartActivity.getTaskFragment() == newParent) {
newParent.addChild(mStartActivity, POSITION_TOP);
} else{
mStartActivity.reparent(newParent, newParent.getChildCount() /*top*/, reason);
}
}
privatevoid addOrReparentStartingActivity(@NonNullTask task, String reason) {
至此,目标mStartActivity一定关联到了task和rootTask。
3.4.9 修改栈位置/显示启动动画
主要是startActivityLocked方法来实现这些逻辑。
void startActivityLocked(){
Task rTask = r.getTask();
...
//!r.mLaunchTaskBehind默认为true,allowMoveToFront默认也为true,newTask=true时代表没有找到可复用的栈
if(!r.mLaunchTaskBehind && allowMoveToFront &&(!isOrhasTask || newTask)) {
positionChildAtTop(rTask);
}
/
if(!newTask && isOrhasTask &&!r.shouldBeVisible()) {
ActivityOptions.abort(options);
return;
}
...
}
首先,newTask=true时代表没有找到可复用的栈,这时把r中关联的task挪到其所归属的rootTask最上层。
其次,如果不需要创建新的Task,则后面也不需要有什么切换动画。否则后面执行切换动画的逻辑。
3.4.10 收尾工作及进入启动流程
接下来做一些日志记录以及收尾的工作
修改应用级别的RootTask
加入到最新执行Task记录中
关联到rootTask上,如果没有,则创建rootTask。
逻辑4中的代码,我们下一小节来讲。
//ActivityStarter
int startActivityInner(){
...
//逻辑4. 这里的mDoResume一定为true,这里对应的启动逻辑,我们在3.4小节来讲。
if(mDoResume){
finalActivityRecord topTaskActivity = startedTask.topRunningActivityLocked();
if(!mTargetRootTask.isTopActivityFocusable(){
mTargetRootTask.ensureActivitiesVisible(...);
mTargetRootTask.mDisplayContent.executeAppTransition();
}else{
mRootWindowContainer.resumeFocusedTasksTopActivities(
mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);
}
}
//逻辑1
mRootWindowContainer.updateUserRootTask(mStartActivity.mUserId, mTargetRootTask);
//逻辑2
mSupervisor.mRecentTasks.add(startedTask);
//逻辑3
if(mOptions !=null&& mOptions.isLaunchIntoPip()
&& sourceRecord !=null&& sourceRecord.getTask() == mStartActivity.getTask()) {
mRootWindowContainer.moveActivityToPinnedRootTask(mStartActivity, sourceRecord, "launch-into-pip");
}
}
3.5 把Activity切到前台
上面说到,startActivityUnchecked中会进行启动Activity的操作,但是其实具体来说,分为三种启动情况。
targetTask不在前台,这时候,就需要把栈切换到前台,我们3.5.2中介绍;
targetTask在前台时,Activity不需要创建,我们3.5.3中介绍;
targetTask在前台时,Activity需要创建,我们3.5.4中介绍;
我们一一来讲。
3.5.1 启动类型判断
上面有介绍,正常的启动流程中,mDoResume一定为true。
首先进行条件判断,满足以下几个条件则为true:
1.targetRootTask中栈顶的Activity是否获取到了焦点;
2.task中顶部Activity并不是mStartActivity,并且Task被覆盖。
如果以上条件不满足,则说明Task已经在前台显示了,则只需要切换mStartActivity到前台即可,则执行3.4.2的逻辑。
如果以上条件满足,说明Task并未在前台显示,则需要让rootTask显示在前台,执行3.4.3的逻辑。
相关代码如下:
if(mDoResume) {
finalActivityRecord topTaskActivity = startedTask.topRunningActivityLocked();
if(!mTargetRootTask.isTopActivityFocusable()
|| (topTaskActivity !=null&& topTaskActivity.isTaskOverlay()
&& mStartActivity != topTaskActivity)) {
//拉起目标Task,3.4.3中讲
mTargetRootTask.ensureActivitiesVisible(null);
mTargetRootTask.mDisplayContent.executeAppTransition();
} else{
if(mTargetRootTask.isTopActivityFocusable()
&&!mRootWindowContainer.isTopDisplayFocusedRootTask(mTargetRootTask)) {
mTargetRootTask.moveToFront("startActivityInner");
}
//拉起目标Activity,3.4.2中讲
mRootWindowContainer.resumeFocusedTasksTopActivities(
mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);
}
}
3.5.2 拉起目标栈
3.4.1我们讲到,拉起目标栈的话,会通过下面两行代码来执行,我们来分别解释下。
mTargetRootTask.ensureActivitiesVisible(null/* starting */, 0/* configChanges */, !PRESERVE_WINDOWS);
mTargetRootTask.mDisplayContent.executeAppTransition();
首先,通过ensureActivitiesVisible方法,确保Activity的可见性。
mTargetRootTask.ensureActivitiesVisible(null/* starting */, 0/* configChanges */, !PRESERVE_WINDOWS);
mTargetRootTask.ensureActivitiesVisible(null/* starting */,0/* configChanges */,!PRESERVE_WINDOWS);
然后调用DisplayContent的executeAppTransition方法,去进行栈的显示转换,代码如下:
voidexecuteAppTransition() {
mTransitionController.setReady(this);
if(mAppTransition.isTransitionSet()) {
...
mAppTransition.setReady();
mWmService.mWindowPlacerLocked.requestTraversal();
}
}
栈的显示状态转换完成,则栈顶的Activity也就会被显示出来了。
3.5.3 拉起目标Activity
如果mTargetRootTask获取到了焦点,但是栈不在前台的话,则把对应的栈挪到前台。
if(mTargetRootTask.isTopActivityFocusable()
&& !mRootWindowContainer.isTopDisplayFocusedRootTask(mTargetRootTask)) {
mTargetRootTask.moveToFront("startActivityInner");
}
//开始拉启Avtivity的流程
mRootWindowContainer.resumeFocusedTasksTopActivities(mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);
接下来就是正式拉起Activity的流程了,对应方法为:resumeFocusedTasksTopActivities。
输入参数有四个,分别为:
相关流程代码如下:
classRootWindowContainer{
boolean resumeFocusedTasksTopActivities(Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions,boolean deferPause) {
boolean result =false;
//逻辑1,通知到Task中的resumeTopActivityUncheckedLocked方法
if(targetRootTask !=null&&(targetRootTask.isTopRootTaskInDisplayArea()|| getTopDisplayFocusedRootTask() == targetRootTask)) {
result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions,deferPause);
}
...
}
}
classTask{
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptionsoptions, boolean deferPause) {
if(isLeafTask()) {
//逻辑3,调用到resumeTopActivityInnerLocked方法
if(isFocusableAndVisible()) {
someActivityResumed = resumeTopActivityInnerLocked(prev, options, deferPause);
}
}else{
//逻辑2,遍历子Task
int idx = mChildren.size()- 1;
while(idx >=0) {
finalTask child =(Task) getChildAt(idx--);
...
someActivityResumed |= child.resumeTopActivityUncheckedLocked(prev, options,
deferPause);
// Doing so inorderto prevent IndexOOB since hierarchy might changes while
// resuming activities, for example dismissing split-screen while starting
// non-resizeable activity.
if(idx >= mChildren.size()) {
idx = mChildren.size()- 1;
}
}
}
}
}
逻辑1:RootWindowContainer的resumeFocusedTasksTopActivities方法中,会通知到Task中的resumeTopActivityUncheckedLocked方法,参数一致;
逻辑2:第一次调用这个方法时,肯定是rootTask对象,所以会遍历所有中leafTask,继续执行这个方法。
逻辑3:第二次调用的时候,就是leafTask对象了,此时就会调用到resumeTopActivityInnerLocked方法。
接下来,使用TaskFragment去启动目标Activity。
privateboolean resumeTopActivityInnerLocked(ActivityRecord prev, ...) {
finalActivityRecord topActivity = topRunningActivity(true/* focusableOnly */);
...
finalTaskFragment topFragment = topActivity.getTaskFragment();
resumed[0] = topFragment.resumeTopActivity(prev, options, deferPause);
}
resumeTopActivity方法中,我们把逻辑分为两大块,首先是第一块:
classTaskFragmentextendsWindowContainer<WindowContainer>{
finalboolean resumeTopActivity(ActivityRecord prev, ActivityOptionsoptions, boolean deferPause) {
//获取当前显示区域
finalTaskDisplayArea taskDisplayArea = getDisplayArea();
//逻辑1
if(mResumedActivity ==next&&next.isState(RESUMED){
returnfalse;
}
//逻辑2
finalboolean allPausedComplete = mRootWindowContainer.allPausedActivitiesComplete();
if(!allPausedComplete) {
returnfalse;
}
//逻辑3
boolean pausing =!deferPause && taskDisplayArea.pauseBackTasks(next);
//逻辑4
if(mResumedActivity !=null) {
ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Pausing %s", mResumedActivity);
pausing |= startPausing(mTaskSupervisor.mUserLeaving, false/* uiSleeping */,
next, "resumeTopActivity");
}
...
}
}
总结一下完成以下几项功能:
1.如果当前将要启动的next对象就是正在启动的mResumedActivity对象,则直接返回。
2.如果还存在正在pause的任务,则继续等待。
3.如果不延迟pause,则pause当前显示区域中的Activity,简单来说就是跨栈启动时,pause上一个Task中的Activity。
4.当前栈不为空时,则会存在一个之前栈顶显示的Activity对象resumeAcitivity,为了方便理解,我们暂且称之为LastActivity。此时resumeAcitivity就会被赋值给puaseActivity,然后会通知APP一侧暂停LastActivity对象,最后把系统侧LastActivity设置为PAUSEING状态。
接下来会进入到第二段启动逻辑的代码:
classTaskFragmentextendsWindowContainer<WindowContainer>{
finalboolean resumeTopActivity(ActivityRecord prev, ActivityOptionsoptions, boolean deferPause) {
...
//展示启动动画
if(anim) {
next.applyOptionsAnimation();
} else{
next.abortAndClearOptionsAnimation();
}
//1.这里是resumeTopActivity中的第二段逻辑
if(next.attachedToProcess()) {
finalClientTransaction transaction =
ClientTransaction.obtain(next.app.getThread(), next.token);
// Deliver all pending results.
ArrayList<ResultInfo> a =next.results;
if(a !=null) {
finalintsize= a.size();
if(!next.finishing &&size>0) {
if(DEBUG_RESULTS) {
Slog.v(TAG_RESULTS, "Delivering results to "+next+": "+ a);
}
transaction.addCallback(ActivityResultItem.obtain(a));
}
}
if(next.newIntents !=null) {
transaction.addCallback(
NewIntentItem.obtain(next.newIntents, true/*resume*/));
}
// Well the app will no longer be stopped.
// Clear app token stopped state in window manager if needed.
next.notifyAppResumed(next.stopped);
EventLogTags.writeWmResumeActivity(next.mUserId, System.identityHashCode(next),
next.getTask().mTaskId, next.shortComponentName);
mAtmService.getAppWarningsLocked().onResumeActivity(next);
next.app.setPendingUiCleanAndForceProcessStateUpTo(mAtmService.mTopProcessState);
next.abortAndClearOptionsAnimation();
transaction.setLifecycleStateRequest(
ResumeActivityItem.obtain(next.app.getReportedProcState(),
dc.isNextTransitionForward()));
mAtmService.getLifecycleManager().scheduleTransaction(transaction);
} else{
//2.创建进程及Activity的流程
mTaskSupervisor.startSpecificActivity(next, true, true);
}
}
}
1.首先,展示启动动画;
2.然后判断ActivityRecord是否绑定进程,这时候如果ActivityRecord是复用的,则构建ResumeActivityItem类型生命周期事务,然后通过binder对象通知APP去执行对应的生命周期流程,这一块第四章介绍。
3.如果ActivityRecord是新建的,则没有绑定进程。此时,则会通过startSpecificActivity方法去尝试创建Activity,我们3.4.4中详细介绍
3.5.4 新建目标Activity
上面讲到,如果是新建Activity,则会执行startSpecificActivity方法,我们来看下这个方法:
classActivityTaskSupervisor{
void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
finalWindowProcessController wpc = mService.getProcessController(r.processName, r.info.applicationInfo.uid);
if(wpc !=null&& wpc.hasThread()) {
realStartActivityLocked(r, wpc, andResume, checkConfig);
return;
}
mService.startProcessAsync();
}
}
这又分成了两条分支:
1.如果进程都不存在,则优先创建进程,走进程创建+Activity启动的流程。这块逻辑同应用启动流程,具体流程可以参考下面这篇文章,这里就不扩展了。android源码学习- APP启动流程(android12源码)
2.如果Activity对应的进程存在,则通过realStartActivityLocked方法走新建Activity的流程。我们来看下这个方法。
classActivityTaskSupervisor{
boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc, boolean andResume, boolean checkConfig) throwsRemoteException{
//绑定进程
r.setProcess(proc);
...
//构建事务
finalClientTransaction clientTransaction =ClientTransaction.obtain(proc.getThread(), r.token);
//添加创建Activity的事务到回调队列中
clientTransaction.addCallback(LaunchActivityItem.obtain(newIntent(r.intent),...);
//添加生命周期事务
finalActivityLifecycleItem lifecycleItem;
//这个流程中,andResume一定为true。
if(andResume) {
lifecycleItem =ResumeActivityItem.obtain(isTransitionForward);
} else{
lifecycleItem =PauseActivityItem.obtain();
}
clientTransaction.setLifecycleStateRequest(lifecycleItem);
//通过binder方法通知APP进程
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
...
}
}
总结一下,首先让ActivityRecord绑定进程,然后构建Resume流程生命周期事务,并且添加LaunchActivityItem事务,最终通过binder方法通知到APP侧。这里的具体通知逻辑,仍然参看第四章。
3.6 五种启动类型原理总结
五种启动类型介绍:Activity的5种启动类型
我们经常说Activity有五种启动类型,其实对应的逻辑也就在这一章。这五种只是基础的类型,配合flag启动参数,其不同的类型则更多。这里,我们稍稍作一个五种类型的总结。
其实核心就是mAddingToTask的属性值。如果找到了可复用activity,则mAddingToTask=false,此时就会通知Acitivity进行复用,并且中断后序流程。
而如果没有找到可复用的activity,则mAddingToTask=true,则不会中断后续流程,就会执行Activity关联Task以及栈切换操作。
privatevoid complyActivityFlags(Task targetTask, ActivityRecord reusedActivity,...){
if((mLaunchFlags &(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
==(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
} elseif((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) !=0
|| isDocumentLaunchesIntoExisting(mLaunchFlags)
|| isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK,
LAUNCH_SINGLE_INSTANCE_PER_TASK)) {、
//singleInstance/singleTask/singleInstancePerTask类型
fialActivityRecord clearTop = targetTask.performClearTop(mStartActivity,mLaunchFlags);
if(clearTop !=null&&!clearTop.finishing) {
deliverNewIntent(clearTop, intentGrants);
} else{
mAddingToTask =true;
...
}
} elseif(mStartActivity.mActivityComponent.equals(targetTask.realActivity)) {
if(targetTask == mInTask) {
//singleTop类型
} elseif(((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) !=0
|| LAUNCH_SINGLE_TOP== mLaunchMode)
&& targetTaskTop.mActivityComponent.equals(mStartActivity.mActivityComponent)
&& mStartActivity.resultTo ==null) {
if(targetTaskTop.isRootOfTask()) {
targetTaskTop.getTask().setIntent(mStartActivity);
}
deliverNewIntent(targetTaskTop, intentGrants);
} elseif(reusedActivity ==null) {
mAddingToTask =true;
}
} elseif(!resetTask) {
//standard类型
mAddingToTask =true;
}
}
如上面的代码所示,如果是singleInstance/singleTask/singleInstancePerTask三种类型,如果栈中存在目标Activity,则清理targetTask之上的Activity。如果Activity没有finish,则调用deliverNewIntent走复用流程。否则设置mAddingToTask=true,仍然走绑定Task流程。
如果是singleTop类型,并且Task顶部的targetTaskTop等于目标Activity,则调用deliverNewIntent走复用流程。否则,设置mAddingToTask=true,仍然走绑定Task流程。
最后,!resetTask时,对应的其实就是我们最常使用的standard类型(前提flags中不设置reset标记),直接设置mAddingToTask=true走绑定Task流程。
3.7 startForResult的原理
Activity中startForResult的原理分析
四.系统通过事务通知APP的启动流程
这个单独整理成一篇文章进行讲解:
Activity事务管理ClientLifecycleManager原理讲解
五.扩展性问题
1.Activity启动失败,该怎么处理?
如文本2.2.2中的介绍,最好的方式就是参考失败code,来判断失败的原因。
比如通过后台service启动Activity,就会提示以下的错误:Abort background activity starts from 10235
我们通过对启动流程的分析,知道属于3.3.6小节的逻辑,知道高版本安卓对于后台启动Activity有限制,但是我们只要申请对应的权限(比如具有SystemAlertWindowPermission权限)即可绕过限制。
2.很经典的一个问题,ActivityA跳转ActivityB,整个生命周期流程是怎样的。
这个其实对应的就是本文的所有内容了。这个要区分ActivityB是否已存在。
如果不存在,则周期为:A.onPause()->B.onCreate()->B.onStart()->B.onResume()->A.onStop()。
如果存在,则要看具体的场景了。
欢迎投稿
关于GDG
Google Developer Groups 谷歌开发者社区,是谷歌开发者部门发起的全球项目,面向对 Google 和开源技术感兴趣的人群而存在的公益性开发者社区。GDG Shanghai 创立于 2009 年,是全球 GDG 社区中最活跃和知名的技术社区之一,每年举办 30 – 50 场大大小小的科技活动,每年影响十几万以上海为中心辐射长三角地带的开发者及科技从业人员。
社区中的各位组织者均是来自各个行业有着本职工作的互联网从业者,我们需要更多新鲜血液的加入!如果你对谷歌技术感兴趣,业余时间可调配,认同社区的价值观,愿意为社区做出贡献,欢迎加入我们成为社区志愿者!如果您能为活动提供餐饮、物料制作、礼品、宣发、会务等支持,欢迎联系我们成为赞助合作伙伴。
志愿者加入方式:关注上海 GDG 公众号:GDG_Shanghai,回复:志愿者赞助合作伙伴加入方式:关注上海 GDG 公众号:GDG_Shanghai,回复:赞助社区成员加入方式:社区成员可以通过邮箱接收到我们的活动信息,请发任意邮件至以下邮箱:gdg-shanghai+subscribe@googlegroups.com