Token
涉及的代码路径如下:
frameworks/base/services/core/java/com/android/server/am/
--- ActivityManagerService.java
--- ProcessRecord.java
--- ActivityRecord.java
--- ActivityResult.java
--- ActivityStack.java
--- ActivityStackSupervisor.java
--- ActivityStarter.java
--- TaskRecord.java
frameworks/base/core/java/com/android/internal/policy/
--- DecorView.java
--- PhoneWindow.java
frameworks/base/core/java/android/view/
--- WindowManager.java
--- View.java
--- ViewManager.java
--- ViewRootImpl.java
--- Window.java
--- Display.java
--- WindowManagerImpl.java
--- WindowManager.java
--- WindowManagerGlobal.java
--- IWindowManager.aidl
frameworks/base/services/core/java/com/android/server/wm/
---WindowManagerService.java
---AppWindowToken.java
kernel/drivers/staging/android/binder.c
整体流程图:
红色箭头:跨进程
红色框 :Token是它的实体端
黄色框 :Token的Binder代理端,
所以这里WMS和AMS之间的Token其实指向的是同一个
1、token的创建
Activity的启动中会在AMS服务中构建一个ActivityRecord实例对象来标记Activity,Token是ActivityRecord的静态内部类
ActivityStarter.startActivityLocked(...)
ActivityRecord r = new ActivityRecord(callerApp,intent,aInfo,mSupervisor,...)
appToken = new Token(this, service);
static class Token extends IApplicationToken.Stub {
....
}
interface IApplicationToken
{
void windowsDrawn();
void windowsVisible();
void windowsGone();
boolean keyDispatchingTimedOut(String reason);
long getKeyDispatchingTimeout();
}
匿名Binder实体会传递给其他进程,其它进程拿到的是Token的代理端IApplicationToken.Stub.Proxy
2、token的传递
-
【创建AMS的appToken】 Activity的启动过程中会在AMS中创建一个构建一个ActivityRecord实例对象来标记Activity,构造过程中会创建一个Token的Binder实体对象保存在ActivityRecord的appToken成员变量之中,见P1
-
【创建WMS的appToken】 AMS创建完Token之后会调用WMS服务的addAppToken()方法在WMS中构建一个AppWindowToken实例对象,然后将Token对象保存在它的appToken成员变量之中
在Activity的启动过程中,AMS会调用startActivityLocked()方法向WMS服务传递Token实体对象
ActivityStarter.startActivityUnchecked()---> ActivityStack.startActivityLocked()---> addConfigOverride()----> mWindowManager.addAppToken()--->
//[WindowManagerService.java] @Override public void addAppToken(...,IApplicationToken token,...) { ... //生成ActivityRecord在WMS中对应的AppWindowToken,见P2 atoken = new AppWindowToken(this, token, voiceInteraction); ... //如果没有Task, 就创建一个task, 并加入到stack中, //这里的task/stack都是与AMS中task/stack就一一对应的 Task task = mTaskIdToTask.get(taskId); if (task == null) { task = createTaskLocked(taskId, stackId, userId, atoken, taskBounds, config); } //将AppWindowToken加入到task中管理起来,见P3 task.addAppToken(addPos, atoken, taskResizeMode, homeTask); //加入到mTokenMap中,见P4 mTokenMap.put(token.asBinder(), atoken); }
作用
WindowManagerService中AppWindowToken保存着ActivityManagerService的Binder对象,用来向AMS传递Window和按键的一些信息。另外的一个用处是作为 mTokenMap的key
-
【创建APP的token】 token将其代理通过AMS跨进程调用ActivityThread的scheduleLaunchActivity()方法传递到ActivityThread类中,然后将其保存在ActivityClientRecord、Activity、Window、WindowManager.LayoutParams的token成员变量中
ActivityClientRecord
attachApplicationLocked realStartActivityLocked app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken, ); public final void scheduleLaunchActivity(Intent intent, IBinder token, ) { //生成App中的ActivityClientRecord ActivityClientRecord r = new ActivityClientRecord(); r.token = token; //将AMS中的token保存到 ActivityClientRecord中 见P5 }
Activity,调用它的attach()方法,见P6
//[Activity.java] final void attach(..., IBinder token, ...) { ... mToken = token; ... }
Window,调用它的setWindowManager()方法
//[Window.java] public void setWindowManager(WindowManager wm, IBinder appToken, String appName, boolean hardwareAccelerated) { mAppToken = appToken;//将Token的Binder代理端赋予Window的mAppToken成员变量,见P7 mAppName = appName; mHardwareAccelerated = hardwareAccelerated || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false); if (wm == null) { wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); } mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this); } //每一个Window对象都有一个mAppToken变量,dialog为空
WindowManager.LayoutParams中有三种窗口
- 应用程序窗口,Anctivity/Dialog,需将token设置成Activity的token
- 子窗口,PopupWindow,需将token设置成它所附着宿主窗口的token
- 系统窗口 Toast/输入法
WindowManagerImpl.addView()---> WindowManagerGlobal.addView()---> Window--->adjustLayoutParamsForSubWindow 见P8 //[Window.java] void adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) { /* 判断窗口类型是不是子窗口 */ if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW && wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { if (wp.token == null) { View decor = peekDecorView(); if (decor != null) { //LayoutParams的token设置为W本地Binder对象 wp.token = decor.getWindowToken(); } } ... } else if (wp.type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW && wp.type <= WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) { //当是系统窗口时token为null ... } else { /* 最后一种类型,通常为Activity的窗口类型 则设置token为当前窗口的IApplicationToken.Proxy代理对象, 否则设置为父窗口的IApplicationToken.Proxy代理对象 */ if (wp.token == null) { wp.token = mContainer == null ? mAppToken : mContainer.mAppToken; } } }
-
【App与WMS使用token通信】 Window通过windowManager跨进程调用WMS的addWindow()对添加activity的窗口进行管理,此过程中携带token的Binder代理 (WindowState中的token)
ViewRootImpl.setView()---> mWindowSession.addToDisplay()---> Session.addToDisplay()---> WMS.addWindow()--->
//[WindowManagerService.java] public int addWindow(..., IWindow client, WindowManager.LayoutParams attrs, ...) { //这里的client为IWindow的代理对象,用于WMS和Activity进行通信 ... //根据attrs.token从mWindowMap中取出应用程序窗口在WMS服务中的描述符WindowState WindowToken token = mTokenMap.get(attrs.token); AppWindowToken atoken = null; //为Activity窗口创建WindowState对象,见P9 WindowState win = new WindowState(this, session, client, token, attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent); //以键值对<IWindow.Proxy/Token,WindowToken>形式保存到mTokenMap表中 //mTokenMap中的token已经在在AMS->WMS时添加了 if (addToken) { mTokenMap.put(attrs.token, token); } win.attach(); //以键值对<IWindow的代理对象,WindowState>形式保存到mWindowMap表中 mWindowMap.put(client.asBinder(), win); ... }