android IApplicationToken分析

  1.      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)