Token是ActivityRecord的内部静态类,我们先来看下Token的继承关系,
Token extends IApplicationToken.Stub,从IApplicationToken.Stub类进行继承,根据Binder的机制可以知道Token是一个匿名Binder实体类,这个匿名Binder实体会传递给其他进程,其他进程会拿到Token的代理端。
我们知道匿名Binder有两个比较重要的用途,一个是拿到Binder代理端后可跨Binder调用实体端的函数接口,另一个作用便是在多个进程中标识同一个对象。往往这两个作用是同时存在的,比如我们这里研究的Token就同时存在这两个作用,但最重要的便是后者,Token标识了一个ActivityRecord对象,即间接标识了一个Activity。
下面这个图是Token的传递,首先会传递到WMS中,接着会传递到应用进程ActivityThread中,下面来具体分析这个传递流程。
1、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, ActivityStackSupervisor supervisor,
ActivityContainer container, Bundle options) {
service = _service;
appToken = new Token(this);
........
}
在ActivityRecord的构造函数中创建,标识着当前这个ActivityRecord,即间接代表着一个Activity。
2、AMS调用WMS的addAPPToken()接口
在启动一个Activity时,会调用startActivityLocked()来在WMS中添加一个AppWindowToken对象;
final void startActivityLocked(ActivityRecord r, boolean newTask,
boolean doResume, boolean keepCurTransition, Bundle options) {
......
mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId,
r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind);
......
}
public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
int configChanges, boolean voiceInteraction, boolean launchTaskBehind) {
......
synchronized(mWindowMap) {
AppWindowToken atoken = findAppWindowToken(token.asBinder());
if (atoken != null) {
Slog.w(TAG, "Attempted to add existing app token: " + token);
return;
}
atoken = new AppWindowToken(this, token, voiceInteraction);
......
Task task = mTaskIdToTask.get(taskId);
if (task == null) {
createTask(taskId, stackId, userId, atoken);
} else {
task.addAppToken(addPos, atoken);
}
mTokenMap.put(token.asBinder(), atoken);
// Application tokens start out hidden.
atoken.hidden = true;
atoken.hiddenRequested = true;
//dump();
}
}
3、AMS跨Binder调用应用进程的
scheduleLaunchActivity()将
Token传递给上层应用进程
final boolean realStartActivityLocked(ActivityRecord r,
ProcessRecord app, boolean andResume, boolean checkConfig)
throws RemoteException {
......
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
r.compat, r.launchedFromPackage, r.task.voiceInteractor, app.repProcState,
r.icicle, r.persistentState, results, newIntents, !andResume,
mService.isNextTransitionForward(), profilerInfo);
......
}
这个是通过调用app.thread.scheduleLaunchActivity()完成的,可以知道对端接收到的便是Token的代理对象。
我们来看下ApplicationThread中scheduleLaunchActivity()的实现:
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
PersistableBundle persistentState, List pendingResults,
List pendingNewIntents, boolean notResumed, boolean isForward,
ProfilerInfo profilerInfo) {
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;
updatePendingConfiguration(curConfig);
sendMessage(H.LAUNCH_ACTIVITY, r);
}
函数中创建一个ActivityClientRecord对象,然后将Token的代理对象保存在
ActivityClientRecord.token中。ActivityClientRecord也代表着一个Activity,不过是在应用进程中,而ActivityRecord是在ActivityManagerService中代表一个Activity。
4、Activity窗口添加
ViewRootImpl.setView()函数中添加Activity窗口时在参数mWindowAttributes中携带Token代理对象。
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
......
mWindowAttributes.copyFrom(attrs);
......
try {
......
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mInputChannel);
} catch (RemoteException e) {
......
} finally {
......
}
......
}
}
}
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, InputChannel outInputChannel) {
......
boolean addToken = false;
WindowToken token = mTokenMap.get(attrs.token);
......
win = new WindowState(this, session, client, token,
attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
mWindowMap.put(client.asBinder(), win);
......
}
根据Binder机制可以知道从上层应用传递过来的Token代理对象会转换成SystemServer进程中的Token本地对象,后者与第2步中从Token对象
是同一个对象,所以上面调用
mTokenMap.get(attrs.token)时便能返回正确返回一个WindowToken(这个WindowToken其实是一个APPWindowToken),这样添加的窗口也就跟Activity关联上了。