【Android】WMS和AMS初探

代碼基于Android 9.0

1、wms的啟動

SystemServer的main函數(shù),啟動了SystemServer線程,同時啟動了各種服務(wù),其中的startOtherServices啟動了對應(yīng)的AMS,IMS,WMS等系統(tǒng)服務(wù)。

SystemServer.java
            traceBeginAndSlog("StartInputManagerService");
            //新建IMS
            inputManager = new InputManagerService(context);
            traceEnd();

            traceBeginAndSlog("StartWindowManagerService");
            // WMS needs sensor service ready
            ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
            mSensorServiceStart = null;
            //初始化WMS,綁定IMS
            wm = WindowManagerService.main(context, inputManager,
                    mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
                    !mFirstBoot, mOnlyCore, new PhoneWindowManager());
            ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
                    DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
            ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
                    /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
            traceEnd();

            traceBeginAndSlog("SetWindowManagerService");
            //關(guān)聯(lián)AMS和WMS
            mActivityManagerService.setWindowManager(wm);
            traceEnd();

            traceBeginAndSlog("WindowManagerServiceOnInitReady");
            //初始化WMP
            wm.onInitReady();
            traceEnd();

WMS的main函數(shù)和InitPolicy函數(shù)都執(zhí)行了handler的runWithScissors,該方法會執(zhí)行新開的線程,然后阻塞當(dāng)前線程,直到新開線程執(zhí)行完畢。WMS單例的創(chuàng)建是在DisplayThread進(jìn)行,WindowManagerPolicy(具體實現(xiàn)是PhoneWindowManager)的初始化是在UiThread進(jìn)行。

WindowManagerService.java
    public static WindowManagerService main(final Context context, final InputManagerService im,
            final boolean haveInputMethods, final boolean showBootMsgs, final boolean onlyCore,
            WindowManagerPolicy policy) {
        //運(yùn)行在DisplayThread
        DisplayThread.getHandler().runWithScissors(() ->
                sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs,
                        onlyCore, policy), 0);
        return sInstance;
    }

    private void initPolicy() {
        //運(yùn)行在UiThread
        UiThread.getHandler().runWithScissors(new Runnable() {
            @Override
            public void run() {
                WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());
                mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);
            }
        }, 0);
    }

2、AMS和WMS關(guān)聯(lián)

Activity啟動的時候,ActivityStarter.StartActivity會創(chuàng)建一個ActivityRecord。

ActivityStarter.java
    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) {
                ...
                ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
                callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
                resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
                mSupervisor, checkedOptions, sourceRecord);
                ...
            }

ActivityRecord創(chuàng)建的時候會創(chuàng)建一個appToken(IApplicationToken),通過該token創(chuàng)建AppWindowContainerController,創(chuàng)建時傳入AppWindowContainerListener回調(diào),WMS的單例,初始化mRoot。把ActivityRecord傳過來的appToken轉(zhuǎn)化成AppWindowToken,AppWindowToken繼承WindowToken,會調(diào)用onDisplayChanged(dc),通過DisplayContent最終會調(diào)用WMS的addWindowToken方法。通過win.attach()保存Seesion和創(chuàng)建SurfaceSession。

Session.java
    public SurfaceSession() {
        mNativeClient = nativeCreate();
    }

   //這里創(chuàng)建的是SurfaceComposerClient,
    static jlong nativeCreate(JNIEnv* env, jclass clazz) {
        SurfaceComposerClient* client = new SurfaceComposerClient();
        client->incStrong((void*)nativeCreate);
        return reinterpret_cast<jlong>(client);
    }

DisplayContent的tokenMap保存了ActivityRecord的token,key為token,value為WindowToken 。
AppWindowToken持有WMS,所以可以直接調(diào)用WMS的方法。
總結(jié):ActivityRecord通過AppWindowContainerController持有的WMS直接執(zhí)行方法(AppWindowContainerController和AppWindowToken都繼承WindowContainer,持有WMS),實現(xiàn)AMS和WMS通訊。

ActivityRecord.java
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) {
        //初始化mRoot
        super(listener, service);
        mHandler = new H(service.mH.getLooper());
        mToken = token;
        synchronized(mWindowMap) {

            AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder());
            if (atoken != null) {
                // TODO: Should this throw an exception instead?
                Slog.w(TAG_WM, "Attempted to add existing app token: " + mToken);
                return;
            }

            final Task task = taskController.mContainer;
            if (task == null) {
                throw new IllegalArgumentException("AppWindowContainerController: invalid "
                        + " controller=" + taskController);
            }
            //把IApplicationToken轉(zhuǎn)化成AppWindowToken
            atoken = createAppWindow(mService, token, voiceInteraction, task.getDisplayContent(),
                    inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
                    requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
                    alwaysFocusable, this);
            if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
                    + " controller=" + taskController + " at " + index);
            //添加token到task里面,task也是WindwContainer
            task.addChild(atoken, index);
        }
    }

3、Activity與WMS關(guān)聯(lián)

啟動Activity的時候,ActivityThread執(zhí)行到performLaunchActivity時,創(chuàng)建activity對象,調(diào)用Activity.attach方法,這里創(chuàng)建了一個PhoneWindow和關(guān)聯(lián)了WindowManager。

ActivityThread.java

    /**  Core implementation of activity launch. */
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
                ...
                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);
                 ...
                 }

handleResumeActivity時把PhoneWindow里面的DecorView設(shè)置成不可見,最后調(diào)用Activity的makevisible。

ActivityThread.java
    @Override
    public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
            String reason) {
           ...
          if (r.window == null && !a.mFinished && willBeVisible) {
            r.window = r.activity.getWindow();
            View decor = r.window.getDecorView();
            //設(shè)置DecorView不可見
            decor.setVisibility(View.INVISIBLE);
            ViewManager wm = a.getWindowManager();
            WindowManager.LayoutParams l = r.window.getAttributes();
            a.mDecor = decor;
            l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
            l.softInputMode |= forwardBit;
            if (r.mPreserveWindow) {
                a.mWindowAdded = true;
                r.mPreserveWindow = false;
                // Normally the ViewRoot sets up callbacks with the Activity
                // in addView->ViewRootImpl#setView. If we are instead reusing
                // the decor view we have to notify the view root that the
                // callbacks may have changed.
                ViewRootImpl impl = decor.getViewRootImpl();
                if (impl != null) {
                    impl.notifyChildRebuilt();
                }
            }
            if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
                    //把decorview添加到wm,具體實現(xiàn)是在WindowManagerImpl里
                    wm.addView(decor, l);
                } else {
                    // The activity will get a callback for this {@link LayoutParams} change
                    // earlier. However, at that time the decor will not be set (this is set
                    // in this method), so no action will be taken. This call ensures the
                    // callback occurs with the decor set.
                    a.onWindowAttributesChanged(l);
                }
            }
            ...
            if (r.activity.mVisibleFromClient) {
                //activity設(shè)置成可見的
                r.activity.makeVisible();
            }
           ...
            }

WindowManager(WindowManagerImpl)添加DecorView,實際是調(diào)用了WindowManagerGolbal的addView。

WindowManagerGlobal.java
    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        ...
        ViewRootImpl root;
        View panelParentView = null;
         ...
            root = new ViewRootImpl(view.getContext(), display);

            view.setLayoutParams(wparams);

            //所有的view對象
            mViews.add(view);
            //viewrootimpl
            mRoots.add(root);
            //對應(yīng)view的參數(shù)
            mParams.add(wparams);

            // do this last because it fires off messages to start doing things
            try {
                //viewRootImpl關(guān)聯(lián)DecorView
                root.setView(view, wparams, panelParentView);
            } catch (RuntimeException e) {
                // BadTokenException or InvalidDisplayException, clean up.
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
                throw e;
            }
        }
    }

這里創(chuàng)建了ViewRootImpl,其初始化創(chuàng)建Session,mWindow,attachInfo等,然后通過ViewRootImpl的setView把DecorView添加上去,setView會調(diào)用addToDisplay,傳遞了Session和Window(IWindow),InputChanel。

ViewRootImpl.java
public ViewRootImpl(Context context, Display display) {
        mContext = context;
        //進(jìn)程單例
        mWindowSession = WindowManagerGlobal.getWindowSession();
        mDisplay = display;
        ...
        //IWindow的binder對象,屬于ViewRootImpl
        mWindow = new W(this);
        ...
        //AttachInfo比較重要的
        mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
                context);
        ...
    }

/**
     * We have one child
     */
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        ....
                try {
                    mOrigWindowType = mWindowAttributes.type;
                    mAttachInfo.mRecomputeGlobalAttributes = true;
                    collectViewAttributes();
                    //此處最終調(diào)用了WindowManagerService的addWindow方法
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
                } catch (RemoteException e) {
                    mAdded = false;
                    mView = null;
                    mAttachInfo.mRootView = null;
                    mInputChannel = null;
                    mFallbackEventHandler.setView(null);
                    unscheduleTraversals();
                    setAccessibilityFocus(null, null);
                    throw new RuntimeException("Adding window failed", e);
                } finally {
                    if (restore) {
                        attrs.restore();
                    }
                }
        ...
     }

這里最后是調(diào)用了WindowManagerService的addWindow(通過Session的IPC),同時傳遞了Session和mWindow。這里的Session由于是WindowManagerGolbal單例來的,所以對應(yīng)的是app的,mWindow對應(yīng)的是ViewRootImpl的。這里還創(chuàng)建了相應(yīng)的token。

WindowManagerService.java

    public int addWindow(Session session, IWindow client, int seq,
            LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
           ...
           //省略部分通過各種邏輯創(chuàng)建對應(yīng)的token
           //創(chuàng)建對應(yīng)的WindowState
            final WindowState win = new WindowState(this, session, client, token, parentWindow,
                    appOp[0], seq, attrs, viewVisibility, session.mUid,
                    session.mCanAddInternalSystemWindow);

          ...
            //這里調(diào)用了mSession.put(session)
            win.attach();
            mWindowMap.put(client.asBinder(), win);

           ....
           }

WMS里面的windowMap保存的是key為mWindow,value為生成的WindowState,也就是間接的ViewRootImpl。WMS同時也保存了Session在數(shù)組里。


app和WMS的關(guān)系圖

想到幾個問題,后續(xù)再研究解決

1、status bar,wallpaper,dialog,popupwindow,Navigation等窗口的顯示流程邏輯。
2、Activity切換動畫過程。
3、輸入事件和window的交互,位置大小變化。
4、多任務(wù)上滑的是否為多窗口。
5、窗口的移除。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容