android IApplicationToken分析
- IApplicationToken初始化:
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的几个重要的文件中的重要的标识。
更多相关文章
- android学习资料与资源记录
- Android应用程序组件Content Provider在应用程序之间共享数据的
- Android(安卓)面试题(经典)
- appt命令检测Apk信息的方法
- android通用适配器
- android实时监听网络状态并在断网的情况下打开网络设置
- 〖Android〗arm-linux-androideabi-gdb报 libpython2.6.so.1.0:
- Android中的几种网络请求方式
- 使用googleMap获取api方法