其他
token在Window当中是怎么工作的?
https://blog.csdn.net/weixin_43766753
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val dialog = AlertDialog.Builder(this)
dialog.run{
title = "我是标题"
setMessage("我是内容")
}
dialog.show()
}
...
// 注意这里换成了ApplicationContext
val dialog = AlertDialog.Builder(applicationContext)
...
}
...
// 注意这里添加了主题
val dialog = AlertDialog.Builder(applicationContext,R.style.AppTheme)
...
}
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
...
int res;
...
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
mTempInsets);
...
if (res < WindowManagerGlobal.ADD_OKAY) {
...
switch (res) {
case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
/*
* 1
*/
throw new WindowManager.BadTokenException(
"Unable to add window -- token " + attrs.token
+ " is not valid; is your activity running?");
...
}
...
}
...
}
class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
final WindowManagerService mService;
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
Rect outStableInsets, Rect outOutsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel,
outInsetsState);
}
}
LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState) {
...
WindowState parentWindow = null;
...
// 获取parentWindow
parentWindow = windowForClientLocked(null, attrs.token, false);
...
final boolean hasParent = parentWindow != null;
// 获取token
WindowToken token = displayContent.getWindowToken(
hasParent ? parentWindow.mAttrs.token : attrs.token);
...
// 验证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;
}
...//各种验证
}
...
}
...
// The actual token.
final IBinder token;
}
token是一个IBinder对象
只有利用token才能成功添加dialog
Dialog在show过程中是如何拿到token并给到WMS验证的?
这个token在activity和application两者之间有什么不同?
WMS怎么知道这个token是合法的,换句话说,WMS怎么验证token的?
WindowToken token = displayContent.getWindowToken(
hasParent ? parentWindow.mAttrs.token : attrs.token);
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
...
}
public void show() {
...
WindowManager.LayoutParams l = mWindow.getAttributes();
...
mWindowManager.addView(mDecor, l);
...
}
// 如果context没有主题,需要把context封装成ContextThemeWrapper
if (createContextThemeWrapper) {
if (themeResId == Resources.ID_NULL) {
final TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true);
themeResId = outValue.resourceId;
}
mContext = new ContextThemeWrapper(context, themeResId);
} else {
mContext = context;
}
// 初始化windowManager
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
// 初始化PhoneWindow
final Window w = new PhoneWindow(mContext);
mWindow = w;
...
// 把windowManager和PhoneWindow联系起来
w.setWindowManager(mWindowManager, null, null);
...
}
public Object getSystemService(@ServiceName @NonNull String name) {
if (getBaseContext() == null) {
throw new IllegalStateException(
"System services not available to Activities before onCreate()");
}
if (WINDOW_SERVICE.equals(name)) {
// 返回的是自身的WindowManager
return mWindowManager;
} else if (SEARCH_SERVICE.equals(name)) {
ensureSearchManager();
return mSearchManager;
}
return super.getSystemService(name);
}
ContextImpl.class(api29)
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
Display display, Window parentWindow) {
...
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (parentWindow != null) {
parentWindow.adjustLayoutParamsForSubWindow(wparams);
}
...
ViewRootImpl root;
...
root = new ViewRootImpl(view.getContext(), display);
...
try {
root.setView(view, wparams, panelParentView);
}
...
}
void adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) {
CharSequence curTitle = wp.getTitle();
if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
// 子窗口token获取逻辑
if (wp.token == null) {
View decor = peekDecorView();
if (decor != null) {
wp.token = decor.getWindowToken();
}
}
...
} else if (wp.type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW &&
wp.type <= WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
// 系统窗口token获取逻辑
...
} else {
// 应用窗口token获取逻辑
if (wp.token == null) {
wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
}
...
}
...
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
// 最终会调用这个方法来创建window
// 注意r.token参数
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, r.configCallback,
r.assistToken);
...
}
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) {
...
// 创建window
mWindow = new PhoneWindow(this, window, activityConfigCallback);
...
// 创建windowManager
// 注意token参数
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
mWindowManager = mWindow.getWindowManager();
...
}
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated;
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
private void handleBindApplication(AppBindData data) {
...
// 获取到Application实例
Application app;
...
try {
app = data.info.makeApplication(data.restrictedBackupMode, null);
...
}
...
}
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
if (mApplication != null) {
return mApplication;
}
...
Application app = null;
...
try {
java.lang.ClassLoader cl = getClassLoader();
...
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
}
...
mActivityThread.mAllApplications.add(app);
mApplication = app;
if (instrumentation != null) {
try {
instrumentation.callApplicationOnCreate(app);
}
...
}
...
return app;
}
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = getFactory(context.getPackageName())
.instantiateApplication(cl, className);
app.attach(context);
return app;
}
public void callApplicationOnCreate(Application app) {
app.onCreate();
}
Application.java
final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
void adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) {
if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
// 子窗口token获取逻辑
if (wp.token == null) {
View decor = peekDecorView();
if (decor != null) {
wp.token = decor.getWindowToken();
}
}
...
} else {
// 应用窗口token获取逻辑
if (wp.token == null) {
wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
}
...
}
...
}
token到底是在什么时候被创建的?
WMS怎么知道我这个token是合法的?
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
mPendingResults, mPendingNewIntents, mIsForward,
mProfilerInfo, client);
// ClientTransactionHandler是ActivityThread实现的接口,具体逻辑回到ActivityThread
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
public void execute(ClientTransaction transaction) {
...
executeCallbacks(transaction);
...
}
public void executeCallbacks(ClientTransaction transaction) {
...
final IBinder token = transaction.getActivityToken();
item.execute(mTransactionHandler, token, mPendingActions);
...
}
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
...
final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
r.appToken);
...
}
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) {
...
//记录得到的activity信息
ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
mSupervisor, checkedOptions, sourceRecord);
...
}
ActivityRecord(... Intent _intent,...) {
appToken = new Token(this, _intent);
...
}
static class Token extends IApplicationToken.Stub {
...
Token(ActivityRecord activity, Intent intent) {
weakActivity = new WeakReference<>(activity);
name = intent.getComponent().flattenToShortString();
}
...
}
void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
boolean newTask, boolean keepCurTransition, ActivityOptions options) {
...
r.createWindowContainer();
...
}
void createWindowContainer() {
...
// 注意参数有token,这个token就是之前初始化的token
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);
...
}
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) {
...
synchronized(mWindowMap) {
AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder());
...
atoken = createAppWindow(mService, token, voiceInteraction, task.getDisplayContent(),
inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
alwaysFocusable, this);
...
}
}
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(WindowManagerService service, IApplicationToken token, ...) {
this(service, token, voiceInteraction, dc, fullscreen);
...
}
WindowToken.class
WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
DisplayContent dc, boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) {
token = _token;
...
onDisplayChanged(dc);
}
void onDisplayChanged(DisplayContent dc) {
dc.reParentWindowToken(this);
...
}
DisplayContent.class(api28)
void reParentWindowToken(WindowToken token) {
addWindowToken(token.token, token);
}
private void addWindowToken(IBinder binder, WindowToken token) {
...
mTokenMap.put(binder, token);
...
}
token在创建ActivityRecord的时候一起被创建,他是一个IBinder对象,实现了接口IApplicationToken。
token创建后会发送到WMS,在WMS中封装成WindowToken,并存在一个HashMap<IBinder,WindowToken>。
token会随着ActivityRecord被发送到本地进程,ActivityThread根据AMS的指令执行Activity启动逻辑。
Activity启动的过程中会创建PhoneWindow和对应的WindowManager,同时把token存在PhoneWindow中。
通过Activity的WindowManager添加view/弹出dialog时会把PhoneWindow中的token放在窗口LayoutParams中。
通过viewRootImpl向WMS进行验证,WMS在LayoutParams拿到IBinder之后就可以在Map中获取WindowToken。
根据获取的结果就可以判断该token的合法情况。