IApplicationToken.aidl的服务端IApplicationToken.Stub的对象在ActivityRecord中定义持有。在ActivityRecord初始化的时候同时做初始化。正常一个activity对应一个activityrecord对象同时对应一个appwindowtoken对象。android 8.0 appwindowtoken通过初始化AppWindowContainerController对象后,通过AppWindowContainerController对象的createAppWindow对象。同时会将ActivityRecord持有的ApplicationToken.stub对象传给AppWindowToken对象。android 10.0是直接初始化。这样AppWindowToken和ActivityRecord同时持有ApplicationToken.stub对象appToken。AppWindowToken初始化后,会执行父类的构造函数
super(service, token != null ? token.asBinder() : null, TYPE_APPLICATION, true, dc,
false /* ownerCanManageAppTokens */);
WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
DisplayContent dc, boolean ownerCanManageAppTokens) {
mService = service;
token = _token;
windowType = type;
mPersistOnEmpty = persistOnEmpty;
mOwnerCanManageAppTokens = ownerCanManageAppTokens;
onDisplayChanged(dc);
}
构造函数里面会执行onDisplayChanged方法,执行DisplayContent的reParentWindowToken方法,里面会把这个_token和AppWindowToken对象放到它的mTokenMap中
mTokenMap.put(binder, token);
具体这个DisplayContent怎么初始化,干啥的,后面文章再讲。现在知道它是个统管。
当activity启动的时候,10.0的版本ATMS中是通过LaunchActivityItem,启动应用端的activity。在ActivityStackSupervisor的realStartActivityLocked方法中有这样一段代码,下面这个代码段,获取了r.appToken,就是上面创建的appToken,传入。通过LaunchActivityItem带入到应用端。
// Create activity launch transaction.
final ClientTransaction clientTransaction = ClientTransaction.obtain(
proc.getThread(), r.appToken);
final DisplayContent dc = r.getDisplay().mDisplayContent;
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
// and override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
r.icicle, r.persistentState, results, newIntents,
dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded(),
r.assistToken));
// Set desired final stat
LaunchActivityItem的execute方法,会调用ActivityThread的handleLaunchActivity方法。里面构建ActivityClientRecord(应用端的ActivityRecord),ActivityRecord的appToken就在里面,ActivityThread.handleLaunchActivity调用preformLaunchActivity,之后调用到了调用Activity.attach方法,同时将ActivityClientRecord对象传入,将appToken给Activity的mToken。这个时候客户端的activityrecord持有的apptoken和activity持有的mToken是同一个token。
在ActivityThread执行handleResumeActivity的时候,会执行wm.addview,这个wm是从activity获取的mWindowManager 对象,mWindowManager 是WindowManager的实例,Windowmanager继承自ViewManager,从Windowmanager.java的注释上看,它是app和window manager沟通的桥梁。那么这个wm是在哪里初始化的?在执行activity的attach的时候 ,会创建一个Activity的持有的Window的实例mWindow对象,具体实现是PhoneWindow。代码:mWindow = new PhoneWindow(this, window, activityConfigCallback); 这个时候初始化好mWindow后开始执行mWindow的 setWindowManager 方法:
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
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);
}
这个时候就在mWindow里面创建好了mWindowmanager对象实例是WindowmanagerImpl. 同时activity里面执行 mWindowManager = mWindow.getWindowManager(); 那么自此这个wm对象来历已经清楚了,是Activity持有的mWindow里面初始化好后返回给Activity,同时Activity用mWindowManager 保存,供使用。
回到刚刚那个wm.addview里面参数一个decor,一个l,这两个都是解析的activity布局文件获取的。暂时不做分析,后面会专门写一篇相关文档分析。这边只要知道把activity要显示的布局decor和参数l带过去了。addview实际执行的应该就是刚刚那个WindowManagerImpl里面。addview有下面这段代码:
if (parentWindow != null) {
parentWindow.adjustLayoutParamsForSubWindow(wparams);
} else {
// If there's no parent, then hardware acceleration for this view is
// set from the application's hardware acceleration setting.
final Context context = view.getContext();
if (context != null
&& (context.getApplicationInfo().flags
& ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
}
由于这个parentWindow是刚刚activity里面创建的mWindow对象,所以走的if条件。adjustLayoutParamsForSubWindow方法,里面先判断窗口的type类型,作为activity,走的下面这个:
} else {
if (wp.token == null) {
wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
}
if ((curTitle == null || curTitle.length() == 0)
&& mAppName != null) {
wp.setTitle(mAppName);
}
}
这段代码会把mAppToken给LayoutParams对象的token。这个mAppToken就是之前讲的Activity的mToken,在PhoneWindow初始化的时候给它的。后面就是初始化ViewRootImpl:
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
// do this last because it fires off messages to start doing things
try {
root.setView(view, wparams, panelParentView);
这边执行完后会把viewrootimpl放到mRoots数组里面,同时会执行setView方法,里面会带入view和wparams。
这个setview方法重点关注下下面这个代码:
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
这里面传入的参数mWidowAttributes,这里addToDisplay是在Session.java里面执行的,这里面会执行到Wms的addWidow方法,这里面有几行关键的代码:
WindowToken token = displayContent.getWindowToken(
hasParent ? parentWindow.mAttrs.token : attrs.token);
这里的attrs.token就是刚刚addview的时候赋值的,通过displayContent.getWindowToken方法获取到WindowToken,里面参数即是实际上ActivityRecord里面的mAppToken。这个displayContent后面文章会写,看下这个getWindowToken方法
WindowToken getWindowToken(IBinder binder) {
return mTokenMap.get(binder);
}
那这个就很明显了,会获取到之前存储的对应的AppWindowToken。那么这个时候就可以传入token,初始化对应的WindowState了,并且把windowstate设置为AppWindowToken的子WindowToken:win.mToken.addWindow(win);
final WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], seq, attrs, viewVisibility, session.mUid,
session.mCanAddInternalSystemWindow);
至此,IApplicationToken在初始化到WindowState创建过程中的作用和关系阐明清楚了。应该说它是一个activity的几个重要的文件中的重要的标识。