ActivityTaskManager启动Activity再读

Activity创建startActivity请求,然后这个请求就被交给了ActivityTaskManagerService

这里还需要有一个概念,在Android系统每个用户有一个独立的uid.这个值从0还是.然后每个安装的包有一个独立的Uid.这个值在安装后就会固定下来,不会变.每个app启动会生成一个动态的进程id也就是pid.然后 Android系统每个用户下安装的app数量是有上限的100000个.比如用户id是0,那么安装包的uid就是从 0 - 99999. 如果用户uid=1 ,那么安装的app的uid是从 100000 - 999999.

我们来看看在Activity调用startActivityActivityTaskManagerService都传递了哪些值过去: (这里我直接带你看InstrumentationexecuStartActivity方法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Instrumentation{
public ActivityResult execStartActivity(Context who , IBinder contextThread , IBinder token , Activity target , Intent intent , int requestCode , Bundel options){
int result = ActivityTaskManager.getService().startActivity(contextThread,
who.getOpPackageName(), who.getAttributionTag(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()), token,
target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
}
}
class ActivityTaskManagerService{
public final int startActivity(IApplicationThread caller, String callingPackage,
String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
Bundle bOptions) {
return
}
}

参数解释:

Instrumentation.execStartActivity:

  1. IBinder contextThread : 是ActivityThread 的 ApplicationThread对象, ApplicationThread连接了App进程和系统服务间进行的通信.也就是跨进程通信.
  2. IBinder token : 是当前调用startActivity的Activity的IBinder值. 每个Activity都一个叫mToken的成员变量,他保存的就是IBinder
  3. Activity target : 是当前调用startActivity的Activity对象
  4. Intent intent : 这个就是我们在startActivity时候新建的Intent对象

ActivityTaskManagerSercice.startActivity:

  1. IApplicationThread caller : 调用startActivity者的ApplicationThread对象,用来实现两个进程间的通信.
  2. Srting callingPackage : 调用者所属的包
  3. Intent intent : 调用者创建的Intent
  4. IBindet resultTo : 调用startActivity的Activity的IBinder对象.通过这个resuleTo可以找到调用者是谁.

总结: 上面最终的参数就是intent 和 token , 通过intent可以知道目标Activity是谁 , 通过token 可以知道调用者是谁.

接着来到ActivityTaskManagerServicestartActivtyAsUser

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class ActivityTaskManagerService{
private int startActivityAsUser(IApplicationThread caller, String callingPackage,
@Nullable String callingFeatureId, Intent intent, String resolvedType,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
//这里判断当前要启动的包是不是当前用户下的app 见我的博客<< Android账户uid和App的uid的含义 >>
assertPackageMatchesCallingUid(callingPackage);

// ActivityStartController
userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");

return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
.setCallingFeatureId(callingFeatureId)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(bOptions)
.setUserId(userId)
.execute();

}
}

然后会先判断应用是否属于当前用户组的应用,如果不是就不给启动,然后如果通过验证.就会去构建一个ActivityStarter,然后会将启动的各种值写入到ActivityStarterRequest的成员变量里面.(这里用到了构造者模式) 然后执行execute进行启动.

1
2
3
4
5
6
7
8
9
10
11
12
class ActivityStarter{
int execute(){
// 第一步: 通过token获取对应的ActivityRecord
final ActivityRecord caller = ActivityRecord.forTokenLocked(mRequest.resultTo);
// 这里会去记录Activity启动的初始时间
launchingState = mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(mRequest.intent, caller, callingUid);
// 第二步: RootWindowContainer获取顶层可见的window , 这个很关键,针对他可以干些事情 关于RootWindowContainer知识去看我的博客<<RootWindowContainer>>
final Task rootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
// 第三步: 去启动Activity
res = executeRequest(mRequest);
}
}

首先第一步通过token值去获取他对应的ActivityRecord对象,这里我们需要知道每一个Activity都有对应他的ActivityRecord对像.
来看下是如何通过Token就能获取到ActivityRecord的:

1
2
3
4
5
6
7
8
//mReqeust.resultTo 是一个IBinder对象,是调用startActivity的那个Activity的IBinder对象
ActivityRecord.forTokenLocked(mRequest.resultTo);

class ActivityRecord{
static ActivityRecord forTokenLocked(IBinder token){
return Token.toTokenActivityRecordLocked((Token)token);
}
}

这里可以看到他将Binder强转成了Token对象了.为什么可以强转,那就要看下Token这个类:

1
2
3
4
5
6
class Token extends IApplicationToken.Stub{
static ActivityRecord tokenToActivityRecordLocked(Token token){
ActivityRecord r = token.weakActivity.get();
return r;
}
}

因为Token就是IBinder的子类,所以可以进行强转.

关于Activity的 mToken:IBinder 值是什么时候传递的这个后面分析

在Android系统中,Activity的生命周期都是由ActivityTaskManagerService来管理的,每个Activity在AMS中都有一个唯一的Token来表示自己.

ActivityTaskManagerService里面创建了RootWindowContainer对象,是怎么创建的呢?

1
2
3
4
5
6
7
8
9
class ActivityTaskManagerService{
RootWindowContainer mRootWindowContainer;
public void setWindowManager(WindowManagerService wm) {
synchronized (mGlobalLock) {
mWindowManager = wm;
mRootWindowContainer = wm.mRoot;
}
}
}

RootWindowContainer 是 Android系统中的顶层窗口容器,他负责管理所有窗口的层级关系.然后每个层级的窗口显示顺序是由 WindowManagerService控制的. 详见博客 < < RootWindowContainer > >

接着看第三步: executeRequest代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
class ActivityStarter{
int executeRequest(Request request){
//request.resultTo这个前面分析了,这个值就是当前触发启动Activity的mToken值.
final IBinder resultTo = request.resultTo;
final IApplicationThread caller = request.caller;
//WindowprocessController管理着手机里面所有的进程信息
WindowProcessController callerApp = null;
//caller就是我们当前app进程的ApplicationThread,然后通过这个值,去我们系统的所有进程里面,找到对应ApplicationThread这个进程的WindowProcessController
callerApp = mService.getProcessController(caller);

ActivityRecord sourceRecord = null;
ActivityRecord resultRecord = null;
if (resultTo != null) {
//通过IBinder去获取对应的Activity他的ActivityRecord对象
//ActivityRecord是一个很重要的对象,他保存了所有关于Activity的信息
sourceRecord = mRootWindowContainer.isInAnyTask(resultTo);
}
//mInterceptor用来拦截Activity的启动的,你可以进行自定义
ActivityStartInterceptor mInterceptor;
// 如果被拦截了,你的Activty就跳转不过去了
if (mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, callingPid,
callingUid, checkedOptions)) {
//这会重新给你的intent进行赋值,赋值为当前触发startAcvitity的intnet . 比如你从MainActivity 跳转到到B Activity,,,,,那么这个intent就会被重新赋值为MainActivity从而是实现拦截效果
intent = mInterceptor.mIntent;
}
// 这一步骤很关键,针对我们要启动的Activity创建对应他的ActivityRecoed对象.
ActivityRecord r = new ActivityRecord.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();

startActivityUnchecked()
}

private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, Task inTask,
boolean restrictedBgActivity, NeededUriGrants intentGrants) {
//在启动activity的时候会去 暂停window布局
activityTaskManagerService.deferWindowLayout();
//启动activity
result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, doResume, options, inTask, restrictedBgActivity, intentGrants);
//让window可以开始布局
mService.continueWindowLayout();
}

int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, Task inTask,
boolean restrictedBgActivity, NeededUriGrants intentGrants){

//目的是获取可重用的任务栈 这个方法很重要,他涉及到了 activity的启动模式
//详细内容见博客<< ActivityStarter.getReusableTask()方法详解 >>
//这里你只需要知道,这里去获取当前要启动的activity需要放的任务栈是谁
final Task reusedTask = getReusableTask();
//如果没有找到可重用的task,那么就执行computeTargetTask()去找task
final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();
//如果找不到指定的task就说明需要新建一个task了 这时候newTask就等于true
final boolean newTask = targetTask == null;
if (newTask) {
// 如果需要新建task 那么就会去新建一个task
final Task taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
? mSourceRecord.getTask() : null;
setNewTask(taskToAffiliate);
} else if (mAddingToTask) {
// 将要启动的Activity加入到存在的task里面, 这里就是Activity被加入到Task的位置.
addOrReparentStartingActivity(targetTask, "adding to task");
}
// 权限检查
mService.mUgmInternal.grantUriPermissionUncheckedFromIntent(intentGrants,
mStartActivity.getUriPermissionsLocked());
//判断用户是否开启了省电模式
mRootWindowContainer.startPowerModeLaunchIfNeeded(
false /* forceSend */, mStartActivity);
}
private Task mTargetRootTask;

//开启启动acvitity的任务
mTargetRootTask.startActivityLocked(mStartActivity,
topRootTask != null ? topRootTask.getTopNonFinishingActivity() : null, newTask,
mKeepCurTransition, mOptions, sourceRecord);
}

在android12上,Handler会发送一个EXECUTE_TRANSACTIONMessage消息。消息内容ClientTransaction。我们看下这个类:

1
2
3
4
case EXECUTE_TRANSACTION:
final ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
break;
1
2
3
4
5
class ClientTransaction{

private ActivityLifecycleItem mLifecycleStateRequest;

}

ClientTransaction内部有个ActivityLifecycleItem的成员变量,这个类是抽象类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public abstract class ActivityLifecycleItem extends ActivityTransactionItem {
@IntDef(prefix = { "UNDEFINED", "PRE_", "ON_" }, value = {
UNDEFINED,
PRE_ON_CREATE,
ON_CREATE,
ON_START,
ON_RESUME,
ON_PAUSE,
ON_STOP,
ON_DESTROY,
ON_RESTART
})
@Retention(RetentionPolicy.SOURCE)
public @interface LifecycleState{}
public static final int UNDEFINED = -1;
public static final int PRE_ON_CREATE = 0;
public static final int ON_CREATE = 1;
public static final int ON_START = 2;
public static final int ON_RESUME = 3;
public static final int ON_PAUSE = 4;
public static final int ON_STOP = 5;
public static final int ON_DESTROY = 6;
public static final int ON_RESTART = 7;
}

看下他的实现类有哪些 : 可以发现他对应的就是我们的Activity的生命周期.

截图 2023-04-12 15-03-22.png

所以这里倒着往回找,找下每个生命周期是怎么触发的,然后ClientTransaction对象是什么时候创建的.

巴拉巴拉…..

过程太过于复杂,这里我直接用语言描述:

在 Activity 触发 startActivity 方法后, 会进入到 system_server进程,然后调用 ActivityTaskManagerService 的 startActivity 方法, 会将构建的 intent ,当前 Activity 的 token 传入到 ActivityTaskManagerService 内, 然后 ActivityTaskManagerService 会构建 ActivityStarter对象,然后创建 Request 将请求的信息放入到 Request里面, 然后执行了 Request.execute() 方法. 接着会判断当前要启动的app是不是属于当前用户组的,在 android 里面每个用户组拥有的资源是有上限制的10000个. 接着会为我们要启动的 Activity 构建 ActivityRecord 对象, 然后会判断当前 Activity 的启动模式, 如果是 singleInstance 的话,必定会创建新Task,但如果设置了Intent.FLOAG_ACTIVITY_NEW_TASK,但是taskAffinity没有设置不同的值的话,还是不会创建新的Task的. 接着在 TASk 里面会触发 ClientLifeCycleManager.scheduleTransaction() 然后会调用 ApplicationThread.scheduleTransaction()方法,实现从系统进程到用户进程的调用.然后就回到了用户进程,然后完成整个Activity的调用.

回顾整个启动流程,我似乎发现 Activity的启动没有那么复杂,主要就做了这么几件事情,Activity调用startActivity方法,然后将事情交给了ActivtiyTaskManagerService, ActivityTaskMangerService的作用就是用来判断要启动的Acvitiy是不是属于当前用户组,是否有权限,然后判断进程是否要创建,task是否要创建,activtity要放入那个task里面,管理着activity的生命周期.用户进程只需要关心页面怎么展示就行.