Activity类组成分析(二)mToken
前言
继上一篇讲了Instrumentation,本文继续探究Activity的成员之mToken。
private IBinder mToken;
搜索一下mToken的使用,可以看到基本都是用来做进程间通信时传递的参数的
Line 8012: WindowManagerGlobal.getInstance().setStoppedState(mToken, true);
Line 8167: ActivityTaskManager.getService().startLockTaskModeByToken(mToken);
Line 8190: ActivityTaskManager.getService().stopLockTaskModeByToken(mToken);
Line 8202: ActivityTaskManager.getService().showLockTaskEscapeMessage(mToken);
Line 8473: ActivityTaskManager.getService().setDisablePreviewScreenshots(mToken, disable);
可见在android中token也是带有一种令牌、标志身份的含义。本文主要探究一下Activity中的这个token创建以及与ams、wms之间的关联。
来龙去脉
AMS相关
Activity.java
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
...
//ActivityThread所在的线程
mUiThread = Thread.currentThread();
//ActivityThread实例的引用
mMainThread = aThread;
mInstrumentation = instr;
// token的使用1
mToken = token;
...
// token的使用2
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
可以看到mToken等成员变量是在attach方法中赋值的,这个在之前已经叙述多次,是ActivityThread在performLaunchActivity中创建一个Activity实例后调用的attach。可以看到参数token在两个地方有使用,一个是赋值给mToken,一个是通过setWindowManager方法传给mWindow了。
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
token来自于ActivityClientRecord,它是ActivityThread的内部类,其实主要作用就是接收来自AMS远端的ActivityRecord然后本地化,将要创建的Activity的参数接收过来,作为要创建的Activity的参数,同时持有创建后的Activity实例,这样AMS中的ActivityRecord、App进程中的ActivityClientRecord、和Activity实体一一对应起来。ActivityThread内部有个mActivities成员,来存放所有的Activity实例。
final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
这个map是通过token为key组织ActivityRecord的。下面继续追溯
这是Ams远程回调ApplicationThread的方法,这儿解释了token是从AMS参数传递来的,而且还包括了其他很多待启动的Activity的信息。
ActivityThread.java
// we use token to identify this activity without having to send the
// activity itself back to the activity manager. (matters more with ipc)
@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo,int taskId_param) {
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.referrer = referrer;
r.voiceInteractor = voiceInteractor;
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
r.persistentState = persistentState;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
r.profilerInfo = profilerInfo;
r.overrideConfig = overrideConfig;
r.taskId = taskId_param;
updatePendingConfiguration(curConfig);
sendMessage(H.LAUNCH_ACTIVITY, r);
}
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo,r.task.taskId);
r是ActivityRecord,现在去追寻ActivityRecord的创建。
> ActivityStarter.java
private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
SafeActivityOptions options,
boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup,
PendingIntentRecord originatingPendingIntent) {
......
// 构建 ActivityRecord,其中会初始化 token
ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
mSupervisor, checkedOptions, sourceRecord);
......
return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
true /* doResume */, checkedOptions, inTask, outActivity);
}
再看一下ActivityRecord的构造函数,因为没看到Token的创建。
ActivityRecord(ActivityManagerService _service, ProcessRecord _caller,
int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,
ActivityInfo aInfo, Configuration _configuration,
ActivityRecord _resultTo, String _resultWho, int _reqCode,
boolean _componentSpecified, boolean _rootVoiceInteraction,
ActivityStackSupervisor supervisor,
ActivityContainer container, ActivityOptions options, ActivityRecord sourceRecord) {
service = _service;
//创建Token
appToken = new Token(this, service);
看一下Token的类型和构造函数
public final IApplicationToken.Stub appToken
看到Stub,才到appToken应该是个Binder了,IApplicationToken.Stub这是aidl编译后的生成的类,直接查IApplicationToken.adil看有没有。
./core/java/android/view/IApplicationToken.aidl
package android.view;
/** {@hide} */
interface IApplicationToken
{
void windowsDrawn();
void windowsVisible();
void windowsGone();
boolean keyDispatchingTimedOut(String reason);
long getKeyDispatchingTimeout();
boolean isHomeActivity();
}
再看Token这个类,
static class Token extends IApplicationToken.Stub {
private final WeakReference<ActivityRecord> weakActivity;
private final ActivityManagerService mService;
Token(ActivityRecord activity, ActivityManagerService service) {
weakActivity = new WeakReference<>(activity);
mService = service;
}
@Override
public void windowsDrawn() {
synchronized (mService) {
ActivityRecord r = tokenToActivityRecordLocked(this);
if (r != null) {
r.windowsDrawnLocked();
}
}
}
@Override
public void windowsVisible() {
synchronized (mService) {
ActivityRecord r = tokenToActivityRecordLocked(this);
if (r != null) {
r.windowsVisibleLocked();
}
}
}
@Override
public void windowsGone() {
synchronized (mService) {
ActivityRecord r = tokenToActivityRecordLocked(this);
if (r != null) {
if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + r);
r.nowVisible = false;
return;
}
}
}
@Override
public boolean keyDispatchingTimedOut(String reason) {
ActivityRecord r;
ActivityRecord anrActivity;
ProcessRecord anrApp;
synchronized (mService) {
r = tokenToActivityRecordLocked(this);
if (r == null) {
return false;
}
anrActivity = r.getWaitingHistoryRecordLocked();
anrApp = r != null ? r.app : null;
}
return mService.inputDispatchingTimedOut(anrApp, anrActivity, r, false, reason);
}
@Override
public long getKeyDispatchingTimeout() {
synchronized (mService) {
ActivityRecord r = tokenToActivityRecordLocked(this);
if (r == null) {
return 0;
}
r = r.getWaitingHistoryRecordLocked();
return ActivityManagerService.getInputDispatchingTimeoutLocked(r);
}
}
private static final ActivityRecord tokenToActivityRecordLocked(Token token) {
if (token == null) {
return null;
}
ActivityRecord r = token.weakActivity.get();
if (r == null || r.task == null || r.task.stack == null) {
return null;
}
return r;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(128);
sb.append("Token{");
sb.append(Integer.toHexString(System.identityHashCode(this)));
sb.append(' ');
sb.append(weakActivity.get());
sb.append('}');
return sb.toString();
}
@Override
public boolean isHomeActivity() throws RemoteException{
ActivityRecord activity = weakActivity.get();
if (activity != null && activity.isHomeActivity()) {
return true;
}
return false;
}
}
Token类继承并实现了IApplicationToken.Stub的服务接口,同时持有了ActivityRecord的弱引用和Ams实例。
刚才是倒推的过程,如果顺着看token的生成过程,那么是startActivity的时候,Ams创建ActivityRecord,其中也创建了token,然后通过调用scheduleLaunchActivity将token和一些其他Activity相关的信息传给ActivityThread,ActivityThread在创建Activity实例的时候调用attach将token传给Activity实例。所以token是每个Activity实例独有的;通过token能够唯一标识一个Activity实例,和其对应的在ActivityThread中的ActivityClientRecord以及AMS中的ActivityRecord。
WMS内
上节说了token在AMS体系中的作用,但是toke在wms中也发挥了很大的作用,因为wms也需要知道每个Activity的身份,同时通知AMS一些信息。
直接看调用栈,ams在创建ActivityRecord后,同时也会将token传给wms
AMS
startActivityLocked
addConfigOverride(r, task);//r就是ActivityRecord
mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
WMS
public void addAppToken( ) {
//生成ActivityRecord在WMS中对应的AppWindowToken,并引用到ActivityRecord中的Token,见p2
atoken = new AppWindowToken(this, token, voiceInteraction);
//如果没有Task, 就创建一个task, 并加入到stack中,
//这里的task/stack都是与AMS中task/stack就一一对应的。 见p3
Task task = mTaskIdToTask.get(taskId);
if (task == null) {
task = createTaskLocked(taskId, stackId, userId, atoken, taskBounds, config);
}
//将AppWindowToken加入到task中管理起来
task.addAppToken(addPos, atoken, taskResizeMode, homeTask);
mTokenMap.put(token.asBinder(), atoken); //加入到mTokenMap中, 见p4
}
可以看到在WMS通过拿到AMS的token后,内部创建了WMS的token - AppWindowToken,并且放到map中保存起来,这两者在WMS中也形成了对应关系。
Window内
Window内也有token,严格说来Window属于App进程了。
Window.java
private IBinder mAppToken;
这个mAppToken又是谁创建的呢。通过查找,在Activity的attach调用的时候会创建一个PhoneWindow并且setWindow的mApptoken
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
//给AppToken赋值
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated;
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
Activity.java
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
当然,Activity的attach是在ActivityThread中调用的,所以这个mToken。
ActivityThread.java
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window);
所以Window里面的token和Activity里面的mToken是同一个对象。但是在实际开发中,由于Window并不总是对应一个Activity,我们常见的Dialog,ContextMenu等等中也会包含一个Window,这个时候就不牵涉WmS和AmS之间的通信问题了,那么这个时候Window中的mAppToken为空,否则mAppToken和Activity中的mToken是相同的。
总结
从整个系统的角度来说,token涉及到的东西还很多,特别是wms相关的,本文主要是一个大概的梳理,全局可以看一下这张图。

浙公网安备 33010602011771号