Android13 WMS窗口相关流程(二)

接着上篇:https://www.jianshu.com/p/67a61225fdc7?v=1698053234018

三、代码流程详解

1.客户端

1.1 Activity走到onresume后

从ActivityThread.handleResumeActivity方法看起
1.调用performResumeActivity,执行onResume。
2.获取WindowManager的实现类WindowManagerImpl的实例。
3.调用WindowManagerImpl.addView传入DecorView和当前布局参数WindowManager.LayoutParams。
代码路径:framework/core/java/android/app/ActivityThread.java

@Override
    public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
            boolean isForward, String reason) {
            ......
        // TODO Push resumeArgs into the activity for consideration
        // skip below steps for double-resume and r.mFinish = true case.
        /*1.执行onResume*/
        if (!performResumeActivity(r, finalStateRequest, reason)) {
            return;
        }
        ......
        //获取Activity实例
        final Activity a = r.activity;
        ......
        // If the window hasn't yet been added to the window manager,
        // and this guy didn't finish itself or start another activity,
        // then go ahead and add the window.
        //mStartedActivity在performLaunchActivity和performResumeActivity方法中被置为false
        boolean willBeVisible = !a.mStartedActivity;
        ......
        if (r.window == null && !a.mFinished && willBeVisible) {
            //获取当前Activity的PhoneWindow
            r.window = r.activity.getWindow();
            //从PhoneWindow中获取DecorView
            View decor = r.window.getDecorView();
            //将view的可见性状态设置为INVISIBLE,view不可见但是仍然占用布局空间
            decor.setVisibility(View.INVISIBLE);
            /*2.获取WindowManager的实现类WindowManagerImpl的实例*/
            ViewManager wm = a.getWindowManager();
            //获取布局参数
            WindowManager.LayoutParams l = r.window.getAttributes();
            //将phoneWindow的DecorView赋值给mDecor
            a.mDecor = decor;
            //设置窗口类型为TYPE_BASE_APPLICATION
            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;
                    /*3.传入DecorView和当前布局参数WindowManager.LayoutParams*/
                    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);
                }
            }
        }
        ......
    }

wm.addView(decor, l);WindowManager接口的实现是WindowManagerImpl,即实际调用的是WindowManagerImpl中的addView方法
代码路径:framework/core/java/android/view/WindowManagerImpl.java

    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyTokens(params);
        //转交给windowManagerGlobal,添加view
        mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
                mContext.getUserId());
    }

WindowManagerImpl对窗口的管理交给WindowManagerGlobal,调用WindowManagerGlobal的addView方法
WindowManagerGlobal中对窗口的处理主要如下几个步骤:
1.对WindowManagerImpl传进来的参数进行检查。
2.设置WindowManager.LayoutParams中的token、title等相关属性。查看“【1.2 Token的创建与传递】”。
3.创建ViewRootImpl对象,并获取客户端与WMS通信的Session。查看“【1.3 ViewRootImpl的创建】”。
4.在WindowManagerGlobal中备份DecorView,WindowManager.LayoutParams以及ViewRootImpl。
5.调用ViewRootImpl,与WMS通信添加窗口。查看“【1.4 ViewRootImpl与WMS的通信】”。
代码路径:framework/core/java/android/view/WindowManagerGlobal.java

    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow, int userId) {
        /*1.对WindowManagerImpl传进来的参数进行检查*/
        if (view == null) {
            throw new IllegalArgumentException("view must not be null");
        }
        if (display == null) {
            throw new IllegalArgumentException("display must not be null");
        }
        if (!(params instanceof WindowManager.LayoutParams)) {
            throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
        }

        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        //此处的ParentWindow即当Activity的PhoneWindow
        if (parentWindow != null) {
            /*2.为wparams的token进行赋值*/
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } else {
            ......
        }

        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {
            ......
            IWindowSession windowlessSession = null;
            ......
            if (windowlessSession == null) {
                /*3.新建ViewRootImpl,在新建时会通过WindowManagerGlobal获取session*/
                root = new ViewRootImpl(view.getContext(), display);
            } else {
                root = new ViewRootImpl(view.getContext(), display,
                        windowlessSession);
            }

            view.setLayoutParams(wparams);
            /*4.在WindowManagerGlobal中备份DecorView,WindowManager.LayoutParams以及ViewRootImpl。*/
            //当前view加入到view列表中
            mViews.add(view);
            //将新建的viewRootImpl加入到root列表中
            mRoots.add(root);
            //将当前布局参数加入到布局参数列表中
            mParams.add(wparams);

            // do this last because it fires off messages to start doing things
            try {
                /*5.调用ViewRootImpl,设置view,panelParentView为null,与WMS通信添加窗口*/
                root.setView(view, wparams, panelParentView, userId);
            } catch (RuntimeException e) {
                // BadTokenException or InvalidDisplayException, clean up.
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
                throw e;
            }
        }
    }
1.2 Token的创建与传递

parentWindow.adjustLayoutParamsForSubWindow(wparams);调用Window的adjustLayoutParamsForSubWindow()方法
在adjustLayoutParamsForSubWindow中会分别对WindowManager.LayoutParams中的token以及title进行赋值。
1.首先针对子窗口、系统窗口以及应用窗口做了不同的处理,此处我们只关注应用窗口的处理。
2.其次将当前PhoneWindow.mAppToken赋值给WindowManager.LayoutParams.token。
代码路径:framework/core/java/android/view/Window.java

    void adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) {
        CharSequence curTitle = wp.getTitle();
        if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                //对子窗口的Token以及Title赋值
                ......
        } else if (wp.type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW &&
                wp.type <= WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
                //对子窗口的Token以及Title赋值
                ......
        } else {
            //对应用窗口的Token以及Title赋值
            if (wp.token == null) {
                //将当前PhoneWindow的mAppToken赋值给wp.Token
                wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
            }
            //将Title设置为mAppName
            if ((curTitle == null || curTitle.length() == 0)
                    && mAppName != null) {
                wp.setTitle(mAppName);
            }
        }
        //设置为packageName 
        if (wp.packageName == null) {
            wp.packageName = mContext.getPackageName();
        }
        ......
    }

此处的mAppToken便是在Activity启动时,在ATMS端创建的Token。
接下来我们看看Token是如何从ATMS端传递过来,并赋值给PhoneWindow.mAppToken的


image.png

1.在ATMS端新建ActivityRecord时,便新建了Token。并赋值给ActivityRecord.token
ActivityRecord继承WindowToken
代码路径:framework/services/core/java/com/android/server/wm/ActivityRecord.java

 private ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller,
            int _launchedFromPid, int _launchedFromUid, String _launchedFromPackage,
            @Nullable String _launchedFromFeature, Intent _intent, String _resolvedType,
            ActivityInfo aInfo, Configuration _configuration, ActivityRecord _resultTo,
            String _resultWho, int _reqCode, boolean _componentSpecified,
            boolean _rootVoiceInteraction, ActivityTaskSupervisor supervisor,
            ActivityOptions options, ActivityRecord sourceRecord, PersistableBundle persistentState,
            TaskDescription _taskDescription, long _createTime) {
        //新建Token
        super(_service.mWindowManager, new Token(), TYPE_APPLICATION, true,
                null /* displayContent */, false /* ownerCanManageAppTokens */);
        ......
}

2.将ActivityRecord.token封装在clientTransaction中,并将这个传递到客户端
代码路径:framework/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java

    boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
            boolean andResume, boolean checkConfig) throws RemoteException {
        ......
        final Task task = r.getTask();
        final Task rootTask = task.getRootTask();
        ......

        try {
            ......

            try {
                ......
                // Create activity launch transaction.
                /*将ActivityRecord.token封装在clientTransaction中*/
                final ClientTransaction clientTransaction = ClientTransaction.obtain(
                        proc.getThread(), r.token);

                final boolean isTransitionForward = r.isTransitionForward();
                final IBinder fragmentToken = r.getTaskFragment().getFragmentToken();
                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.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor,
                        proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(),
                        results, newIntents, r.takeOptions(), isTransitionForward,
                        proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
                        r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken));
                ......

                // Schedule transaction.
                /*将clientTransaction传递给客户端*/
                mService.getLifecycleManager().scheduleTransaction(clientTransaction);
                ......

            } catch (RemoteException e) {
                ......
            }
        } finally {
            ......
        }
        ......
        return true;
    }

final ClientTransaction clientTransaction = ClientTransaction.obtain( proc.getThread(), r.token);
在ClientTransaction中调用obtain方法,把ActivityRecord.token存到mActivityToken
代码路径:framework/core/java/android/app/servertransaction/ClientTransaction.java

    /** Obtain an instance initialized with provided params. */
    public static ClientTransaction obtain(IApplicationThread client, IBinder activityToken) {
        ClientTransaction instance = ObjectPool.obtain(ClientTransaction.class);
        if (instance == null) {
        //创建ClientTransaction
            instance = new ClientTransaction();
        }
        instance.mClient = client;
        /*把ActivityRecord.token存到mActivityToken*/
        //private IBinder mActivityToken;
        instance.mActivityToken = activityToken;

        return instance;
    }

3.客户端从ClientTransaction中获取ATMS端传来的Token,并传递到LaunchActivityItem中
代码路径:framework/core/java/android/app/servertransaction/TransactionExecutor.java

   /** Cycle through all states requested by callbacks and execute them at proper times. */
    @VisibleForTesting
    public void executeCallbacks(ClientTransaction transaction) {
        final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
        ......
        /*从ClientTransaction中获取ATMS端传来的Token*/
        final IBinder token = transaction.getActivityToken();
        ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
        ......

        final int size = callbacks.size();
        for (int i = 0; i < size; ++i) {
            final ClientTransactionItem item = callbacks.get(i);
            ......
            /*将Token传递到LaunchActivityItem中*/
            item.execute(mTransactionHandler, token, mPendingActions);
            item.postExecute(mTransactionHandler, token, mPendingActions);
            ......
        }
    }

4.在LaunchActivityItem中将客户端传过来的Token保存在ActivityClientRecord.token中
代码路径:framework/core/java/android/app/servertransaction/LaunchActivityItem.java

    @Override
    public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
        //将客户端传过来的Token保存在ActivityClientRecord的token中
        ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
                mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
                mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
                client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble,
                mTaskFragmentToken);
        client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    }

client.handleLaunchActivity(r, pendingActions, null /* customIntent */);ClientTransactionHandler调用handleLaunchActivity方法,ClientTransactionHandler为抽象类,其子类为ActivityThread,即实际调用的是该类中的handleLaunchActivity(),有从该方法中调用到了performLaunchActivity()
5.客户端ActivityThread将ActivityClientRecord以及其对应的token保存在ActivityThread.mActivities数组中,并调用Activity.attach将Token传给Activity。
代码路径:framework/core/java/android/app/ActivityThread.java

    /**  Core implementation of activity launch. */
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ......
        try {
            Application app = r.packageInfo.makeApplicationInner(false, mInstrumentation);
            ......
            synchronized (mResourcesManager) {
                /*将ActivityClientRecord以及其对应的Token保存在mActivities中*/
                //mActivities的类型为ArrayMap<IBinder, ActivityClientRecord>
                mActivities.put(r.token, r);
            }

            if (activity != null) {
                ......
                /*将Token赋值给Activity.mToken*/
                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.activityConfigCallback,
                        r.assistToken, r.shareableActivityToken);
                ......

        } catch (SuperNotCalledException e) {
            throw e;

        } catch (Exception e) {
            ......
        }

        return activity;
    }

6.在Activity中将客户端传来的Token赋值给Activity.mToken。此外在该方法中还新建了PhoneWindow,并将PhoneWindow.mAppToken也设置为客户端传过来的Token。
代码路径:framework/core/java/android/app/Activity.java

    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken,
            IBinder shareableActivityToken) {
        attachBaseContext(context);

        mFragments.attachHost(null /*parent*/);
        /*新建PhoneWindow*/
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        ......
        /*将客户端传过来的Token赋值给mToken*/
        mToken = token;
        ......
        /*PhoneWindow.mAppToken设置为当前客户端传递过来的Token*/
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        ......
    }

PhoneWindow继承Window,setWindowManager实际调用的是其父类方法,把mAppToken设置为当前客户端传递过来的mToken
代码路径:framework/core/java/android/view/Window.java

    /**
     * Set the window manager for use by this Window to, for example,
     * display panels.  This is <em>not</em> used for displaying the
     * Window itself -- that must be done by the client.
     *
     * @param wm The window manager for adding new windows.
     */
    public void setWindowManager(WindowManager wm, IBinder appToken, String appName) {
        //传递客户端的mToken给appToken
        setWindowManager(wm, appToken, appName, false);
    }

    /**
     * Set the window manager for use by this Window to, for example,
     * display panels.  This is <em>not</em> used for displaying the
     * Window itself -- that must be done by the client.
     *
     * @param wm The window manager for adding new windows.
     */
    public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        /*把appToken赋值给mAppToken*/
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated;
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }

1.3 ViewRootImpl的创建

root = new ViewRootImpl(view.getContext(), display);之前在【1.1 Activity走到onresume后】的流程中有调用创建ViewRootImpl,这里我们看下ViewRootImpl的构造方法
代码路径:framework/core/java/android/view/ViewRootImpl.java

    public ViewRootImpl(Context context, Display display) {
        this(context, display, WindowManagerGlobal.getWindowSession(),
                false /* useSfChoreographer */);
    }

    public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session) {
        this(context, display, session, false /* useSfChoreographer */);
    }

    public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session,
            boolean useSfChoreographer) {
        mContext = context;
        mWindowSession = session;
        ......
    }

从这个构造方法中我们可以看出,通过WindowManagerGlobal.getWindowSession获取到客户端与WMS沟通的桥梁IWindowSession,并将其赋值给ViewRootImpl.mWindowSession。

下面我们查看WindowManagerGlobal中是如何获取Session的。
1.通过getWindowManagerService获取IWindowManager,而WindowManagerService则实现了这个Binder接口。
2.调用IWindowManager.openSession方法即WMS.openSession,在WMS端便会新建Session。至此客户端与WMS通信的桥梁便已经搭建好了
代码路径:framework/core/java/android/view/WindowManagerGlobal.java

    @UnsupportedAppUsage
    public static IWindowSession getWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowSession == null) {
                try {
                    // Emulate the legacy behavior.  The global instance of InputMethodManager
                    // was instantiated here.
                    // TODO(b/116157766): Remove this hack after cleaning up @UnsupportedAppUsage
                    InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
                    /*1.获取Binder*/
                    IWindowManager windowManager = getWindowManagerService();
                    /*2.调用WMS的openSession*/
                    sWindowSession = windowManager.openSession(
                            new IWindowSessionCallback.Stub() {
                                @Override
                                public void onAnimatorScaleChanged(float scale) {
                                    ValueAnimator.setDurationScale(scale);
                                }
                            });
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowSession;
        }
    }

从代码中可以看出如果sWindowSession不为空则直接返回,sWindowSession为当前WindowManagerGlobal属性,且WindowManagerGloba又是单例的,所以客户端一个进程中只有一个IWindowSession与WMS通信。如果sWindowSession为空,则会创建IWindowSession。

调用WindowManagerService中的openSession,新建Session
代码路径:framework/services/core/java/com/android/server/wm/WindowManagerService.java

    @Override
    public IWindowSession openSession(IWindowSessionCallback callback) {
        /*新建Session*/
        return new Session(this, callback);
    }

1.4 ViewRootImpl与WMS的通信

root.setView(view, wparams, panelParentView, userId);之前在【1.1 Activity走到onresume后】的流程中有调用ViewRootImpl与WMS的通信,继续看看
当前方法是与WMS进行通信添加窗口的入口,在此处我们只关注两点:
1.requestLayout()该方法会调用到doTraversal(),之后调用performTraversals(),最终调用到relayoutWindow()和reportDrawFinished()流程,在通过Session与服务端通信
2.mWindowSession.addToDisplayAsUser,与服务端进行Binder通信,调用Session的addToDisplayAsUser方法。

   /**
     * We have one child
     */
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        setView(view, attrs, panelParentView, UserHandle.myUserId());
    }

    /**
     * We have one child
     */
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
            int userId) {
        synchronized (this) {
            if (mView == null) {
                mView = view;
                ......
                //将布局参数拷贝纸mWindowAttributes
                mWindowAttributes.copyFrom(attrs);
                //设置包名
                if (mWindowAttributes.packageName == null) {
                    mWindowAttributes.packageName = mBasePackageName;
                }
                mWindowAttributes.privateFlags |=
                        WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST;

                attrs = mWindowAttributes;
                ......
                // Keep track of the actual window flags supplied by the client.
                //获取当前布局的flags
                mClientWindowLayoutFlags = attrs.flags;
                ......
                int res; /* = WindowManagerImpl.ADD_OKAY; */

                // Schedule the first layout -before- adding to the window
                // manager, to make sure we do the relayout before receiving
                // any other events from the system.
                /*请求布局,对应服务端layoutWindow流程*/
                requestLayout();
                InputChannel inputChannel = null;
                if ((mWindowAttributes.inputFeatures
                        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                    inputChannel = new InputChannel();
                }
                ......

                try {
                    ......
                    /*与服务端进行Binder通信,调用Session的addToDisplayAsUser方法*/
                    //执行addWindow的相关流程
                    res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), userId,
                            mInsetsController.getRequestedVisibilities(), inputChannel, mTempInsets,
                            mTempControls);
                    ......
                } catch (RemoteException e) {
                    ......
                } finally {
                    if (restore) {
                        attrs.restore();
                    }
                }
                ......
                if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
                if (res < WindowManagerGlobal.ADD_OKAY) {
                    mAttachInfo.mRootView = null;
                    mAdded = false;
                    mFallbackEventHandler.setView(null);
                    unscheduleTraversals();
                    setAccessibilityFocus(null, null);
                    switch (res) {
                        case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
                        case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
                            throw new WindowManager.BadTokenException(
                                    "Unable to add window -- token " + attrs.token
                                    + " is not valid; is your activity running?");
                        case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
                            throw new WindowManager.BadTokenException(
                                    "Unable to add window -- token " + attrs.token
                                    + " is not for an application");
                        case WindowManagerGlobal.ADD_APP_EXITING:
                            throw new WindowManager.BadTokenException(
                                    "Unable to add window -- app for token " + attrs.token
                                    + " is exiting");
                        case WindowManagerGlobal.ADD_DUPLICATE_ADD:
                            throw new WindowManager.BadTokenException(
                                    "Unable to add window -- window " + mWindow
                                    + " has already been added");
                        case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
                            // Silently ignore -- we would have just removed it
                            // right away, anyway.
                            return;
                        case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
                            throw new WindowManager.BadTokenException("Unable to add window "
                                    + mWindow + " -- another window of type "
                                    + mWindowAttributes.type + " already exists");
                        case WindowManagerGlobal.ADD_PERMISSION_DENIED:
                            throw new WindowManager.BadTokenException("Unable to add window "
                                    + mWindow + " -- permission denied for window type "
                                    + mWindowAttributes.type);
                        case WindowManagerGlobal.ADD_INVALID_DISPLAY:
                            throw new WindowManager.InvalidDisplayException("Unable to add window "
                                    + mWindow + " -- the specified display can not be found");
                        case WindowManagerGlobal.ADD_INVALID_TYPE:
                            throw new WindowManager.InvalidDisplayException("Unable to add window "
                                    + mWindow + " -- the specified window type "
                                    + mWindowAttributes.type + " is not valid");
                        case WindowManagerGlobal.ADD_INVALID_USER:
                            throw new WindowManager.BadTokenException("Unable to add Window "
                                    + mWindow + " -- requested userId is not valid");
                    }
                    throw new RuntimeException(
                            "Unable to add window -- unknown error code " + res);
                }
                ......
            }
        }
    }

其中关键的添加代码为

res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
        getHostVisibility(), mDisplay.getDisplayId(), userId,
        mInsetsController.getRequestedVisibilities(), inputChannel, mTempInsets,
        mTempControls);

addToDisplayAsUser()方法最终会走到WindowManagerService.java的addWindow方法,addWindow方法的返回值最后会返回给res,之后回看ViewRootImpl的setView方法,返回值如果满足if (res < WindowManagerGlobal.ADD_OKAY)条件,那么会根据switch (res)中对应的case抛出异常。
至此,客户端流程结束,后面进入服务端流程。

————————————————
版权声明:本文为CSDN博主「yi诺千金」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yimelancholy/article/details/130339779

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容