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.appToken
已经被赋值。所以 Token 是在 AMS 的 startActivity 流程中创建的。但是 Token 的校验显然是发生在 WMS 中的,所以 AMS 还得把 Token 交到 WMS 。
WMS 是如何拿到 Token 的?
继续跟下去,startActivity()
最后会调用到 ActivityStack.startActivityLocked()
,这个方法就是把 Token 给到 WMS 的关键。
ActivityStack.java
void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
boolean newTask, boolean keepCurTransition, ActivityOptions options) {
…
if (r.getWindowContainerController() == null) {
// 创建 AppWindowContainerController 对象,其中包含 token 对象
r.createWindowContainer();
…
}
其他代码都省略了,重点关注 r.createWindowContainer()
,这里的 r 就是一开始创建的 ActivityRecord 对象。
ActivityRecord.java
void createWindowContainer() {
if (mWindowContainerController != null) {
throw new IllegalArgumentException(“Window container=” + mWindowContainerController
- " already created for r=" + this);
}
inHistory = true;
final TaskWindowContainerController taskController = task.getWindowContainerController();
…
// 构造函数中会调用 createAppWindow() 创建 AppWindowToken 对象
mWindowContainerController = new AppWindowContainerController(taskController, appToken,
this, Integer.MAX_VALUE /* add on top */, info.screenOrientation, fullscreen,
(info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, info.configChanges,
task.voiceSession != null, mLaunchTaskBehind, isAlwaysFocusable(),
appInfo.targetSdkVersion, mRotationAnimationHint,
ActivityManagerService.getInputDispatchingTimeoutLocked(this) * 1000000L);
task.addActivityToTop(this);
…
}
在 AppWindowContainerController
的构造函数中传入了之前已经初始化过的 appToken
。
AppWindowContainerController.java
public AppWindowContainerController(TaskWindowContainerController taskController,
IApplicationToken token, AppWindowContainerListener listener, int index,
int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
WindowManagerService service) {
super(listener, service);
mHandler = new H(service.mH.getLooper());
mToken = token;
synchronized(mWindowMap) {
…
atoken = createAppWindow(mService, token, voiceInteraction, task.getDisplayContent(),
inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
alwaysFocusable, this);
…
}
}
createAppWindow()
方法中会创建 AppWindowToken
对象,注意传入的 token 参数。
AppWindowContainerController.java
AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
boolean alwaysFocusable, AppWindowContainerController controller) {
return new AppWindowToken(service, token, voiceInteraction, dc,
inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation,
rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
controller);
}
AppWindowToken.java
AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction,
DisplayContent dc, boolean fillsParent) {
// 父类是 WindowToken
super(service, token != null ? token.asBinder() : null, TYPE_APPLICATION, true, dc,
false /* ownerCanManageAppTokens */);
appToken = token;
mVoiceInteraction = voiceInteraction;
mFillsParent = fillsParent;
mInputApplicationHandle = new InputApplicationHandle(this);
}
这里调用了父类的构造函数,AppWindowToken
的父类是 WindowToken
。
WindowToken.java
WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
DisplayContent dc, boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) {
super(service);
token = _token;
windowType = type;
mPersistOnEmpty = persistOnEmpty;
mOwnerCanManageAppTokens = ownerCanManageAppTokens;
mRoundedCornerOverlay = roundedCornerOverlay;
// 接着跟进去
onDisplayChanged(dc);
}
WindowToken.java
void onDisplayChanged(DisplayContent dc) {
// 调用 DisplayContent.reParentWindowToken()
dc.reParentWindowToken(this);
mDisplayContent = dc;
…
}
DisplayContent.java
void reParentWindowToken(WindowToken token) {
…
addWindowToken(token.token, token);
}
private void addWindowToken(IBinder binder, WindowToken token) {
…
// mTokenMap 是一个 HashMap<IBinder, WindowToken>,
mTokenMap.put(binder, token);
…
}
mTokenMap
是一个 HashMap<IBinder, WindowToken>
对象,保存了 WindowToken 以及其 Token 信息。我们从 AMS 启动 Activity 一路追到这里,其实已经走到了 WMS 的逻辑。AMS 和 WMS 都是运行在 system_server 进程的,并不存在 binder 调用。AMS 就是按照上面的调用链把 Token 传递给了 WMS 。
再来一张清晰的流程图总结一下 Token 从 AMS 传递到 WMS 的整个流程:
WMS 是如何校验 Token 的?
其实一直很纠结源码解析类的文章应该怎么写。单纯说思想,但对很多人来说并不够;源码说多了,文章又显得枯燥乏味。大家有好的建议可以在评论区聊一聊。
这一块的源码我就不在文章里一点一点追了。大家可以对着下面的流程图自己啃一下源码。从 Dialog.show()
开始,最后走到 WindowManagerService.addwWindow()
。
在 WMS.addWindow()
方法中就会对 Token 进行校验,这一块来看一下源码。
public int addWindow(Session session, IWindow client, int seq,
LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
…
AppWindowToken atoken = null;
final boolean hasParent = parentWindow != null;
// 获取 WindowToken
WindowToken token = displayContent.getWindowToken(
hasParent ? parentWindow.mAttrs.token : attrs.token);
if (token == null) {
if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
Slog.w(TAG_WM, "Attempted to add application window with unknown token "
- attrs.token + “. Aborting.”);
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
…
} else {
…
}
…
}
最后
文末放一个小福利给大家,点击我的GitHub即可领取
群内有许多技术大牛,有任何问题,欢迎广大网友一起来交流,群内还不定期免费分享高阶Android学习视频资料和面试资料包~
偷偷说一句:群里高手如云,欢迎大家加群和大佬们一起交流讨论啊!
F%E5%A6%82%E4%BD%95%E9%9D%A2%E8%AF%95%E6%8B%BF%E9%AB%98%E8%96%AA%EF%BC%81.md)**
群内有许多技术大牛,有任何问题,欢迎广大网友一起来交流,群内还不定期免费分享高阶Android学习视频资料和面试资料包~
偷偷说一句:群里高手如云,欢迎大家加群和大佬们一起交流讨论啊!
[外链图片转存中…(img-AIPIOlvA-1643786301828)]