WindowManager窗口添加管理流程分析一

WindowManagerService窗口添加管理流程分析

Api中窗口定义与使用

我们知道Android中界面显示是由一个窗口一个窗口叠加而成的,不管是顶部的statusbar还是底部的navigation bar还是我们显示的activity或悬浮窗、toast、dialog实际上都是窗口。而这些窗口有各自的优先级,通过不同的优先级和类型,可以显示在不同的位置和层级。
android提供的窗口type定义范围由应用级的FIRST_APPLICATION_WINDOW(1)- LAST_APPLICATION_WINDOW(99),
应用级子窗口:
FIRST_SUB_WINDOW(1000)-
LAST_SUB_WINDOW(1999),
系统级的FIRST_SYSTEM_WINDOW(2000)- LAST_SYSTEM_WINDOW(2999),这些权限一般需要系统级权限。虽然有很多定义,但是由于历史原因,很多窗口类型被整合和替代,现在主要使用的窗口类型有:
应用级窗口
TYPE_BASE_APPLICATION = 1; Activity启动的时候的窗口
TYPE_APPLICATION = 2
应用级子窗口
TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW 显示在父窗口之上的窗口
系统级窗口
TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW 顶部状态栏
TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1 搜索窗口
TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4 锁屏窗口
TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW+8 系统窗口
TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11 输入法窗口
TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12 输入法对话框,一般先试试在输入法之上
TYPE_DREAM = FIRST_SYSTEM_WINDOW+23 屏保窗口(现在很少有了)
TYPE_SCREENSHOT = FIRST_SYSTEM_WINDOW + 36 截图窗口
TYPE_APPLICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 38 表示一种可以在所有activity之上显示的悬浮窗

如何增加窗口,一般我们分为如下步骤:

WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);  // 获取windowmanager,进行系统调用
windowManager.addView(view, layoutParams);  // 第一个参数表示添加的view,第二个表示布局参数

下一节我们就开始讲WindowManagerService的实现

WindowManagerService初始化

前面我们讲Ams初始化流程中,其实也讲到了WindowManagerService的一部分流程,实际上也是SystemServer启动的服务,隶属于SystemServer。我们看一下WindowManagerService(简写为WMS)的具体初始化方法:

public static WindowManagerService main(final Context context, final InputManagerService im,
        final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
        ActivityTaskManagerService atm) {
    return main(context, im, showBootMsgs, onlyCore, policy, atm,
            SurfaceControl.Transaction::new);
}

@VisibleForTesting
public static WindowManagerService main(final Context context, final InputManagerService im,
        final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
        ActivityTaskManagerService atm, TransactionFactory transactionFactory) {
        // 这里的DisplayThread是一个设置高优先级的线程Thread,用来为WindowManager 和InputManager 以及DisplayManager专门创建的线程,保证他的优先级。
    DisplayThread.getHandler().runWithScissors(() ->
            sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
                    atm, transactionFactory), 0);       
    return sInstance;
}

private WindowManagerService(Context context, InputManagerService inputManager,
        boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
        ActivityTaskManagerService atm, TransactionFactory transactionFactory) {

   // 获取到其他强关联的模块,输入法和显示模块
    mInputManager = inputManager; // Must be before createDisplayContentLocked.
    mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
    mDisplayWindowSettings = new DisplayWindowSettings(this);

   // WindowManagerPolicy 为本地服务,仅仅fwk本地调用
    LocalServices.addService(WindowManagerPolicy.class, mPolicy);

    mKeyguardDisableHandler = KeyguardDisableHandler.create(mContext, mPolicy, mH);

     // WindowManager创建成功,需要通知其他模块相应地实现
    mActivityManager = ActivityManager.getService();
    mActivityTaskManager = ActivityTaskManager.getService();
    mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
    mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
    mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
    AppOpsManager.OnOpChangedInternalListener opListener =
            new AppOpsManager.OnOpChangedInternalListener() {
                @Override public void onOpChanged(int op, String packageName) {
                    updateAppOpsState();
                }
            };
    mAppOps.startWatchingMode(OP_SYSTEM_ALERT_WINDOW, null, opListener);
    mAppOps.startWatchingMode(AppOpsManager.OP_TOAST_WINDOW, null, opListener);

   // 注册WindowManagerInternal为本地服务
    LocalServices.addService(WindowManagerInternal.class, new LocalService());
}

窗口创建流程

在AMS流程的介绍中,我们知道AMS 会通过传递一个初始生命周期LaunchActivityItem和一个目标生命周期ResumeActivityItem。
而实际整个窗口建立的过程与这些生命周期息息相关,我们首先看一下上层LaunchActivityItem也就是会调用的performLaunchActivity的流程,做了什么?

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    try {

        // Activity 在Ams中建立完成,回调上层进行初始化
        if (activity != null) {
            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);

            // 回调Activity的performCreate方法,也就是onCreate的回调执行所在
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
        }

    }catch (Exception e) {
    }

    return activity;
}

那我们看一下窗口在不在launch的过程中建立,先看一下attach方法:

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) {
        attachBaseContext(context);

        mFragments.attachHost(null /*parent*/);

       // 建立PhoneWindow
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);

      // 初始化一下Activity的参数
        mUiThread = Thread.currentThread();
        mMainThread = aThread;
        mInstrumentation = instr;
        mToken = token;
        mAssistToken = assistToken;
        mIdent = ident;
        mApplication = application;
        mIntent = intent;

      // 设置PhoneWindow的wms
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
         // 如果是子activity,则设置当前window被父activity包含(当前相关api废弃,AMS中有讲)
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }
    }

performCreate方法中,主要就是调用oncreate的回调,一般我们在Activity初始化的时候,还会做一件事情,就是setContentView用于设置Activity的主布局,我们看一下他的实现。
Activity里面是通过getWindow().setContentView来实现的,实际上我们上面也看到这个mWindow就是PhoneWindow,我们看一下实现:

public void setContentView(View view, ViewGroup.LayoutParams params) {
    // mContentParent 实际decorView中的id为android.id.content的FrameLayout,我们知道其实我们setContentView的layout实际上并不是直接嵌套在DecorView中的,实际是在这个android.id.content里,所以我们就算没有执行setContentView,我们依然可以通过这个id,在api侧能取到root view(mContentParent)。
    if (mContentParent == null) {
       // DecorView没创建,则开始生成Decorview,并生成
        installDecor(); // 这个方法很多地方都会调用,比如findViewByid时,也会判断有没有创建DecorView
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        // 有的话,移除所有子view
        mContentParent.removeAllViews();
    }

    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        view.setLayoutParams(params);
        final Scene newScene = new Scene(mContentParent, view);
        transitionTo(newScene);
    } else {
        // 将view 加到root view中
        mContentParent.addView(view, params);
    }
}

当然正如我们代码注释所说,就算没有执行setContentView方法,你只要去getDecorView了就会创建:

@Override
public final @NonNull View getDecorView() {
    if (mDecor == null || mForceDecorInstall) {
        installDecor();
    }
    return mDecor;
}

我们再回调ResumeActivityItem执行的生命周期方法,看一下他的上层实现handleResumeActivity:

public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
                                     String reason) {

        // 执行Activity的performResume方法,即回调onResume
        final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
        final Activity a = r.activity;

        if (r.window == null && !a.mFinished && willBeVisible) {
            r.window = r.activity.getWindow();
            // 这个decorView实际就是activity真正的root view,(api侧能设置的只是我们上面提到的mContentParent)
            View decor = r.window.getDecorView();
            decor.setVisibility(View.INVISIBLE);
            ViewManager wm = a.getWindowManager();
            WindowManager.LayoutParams l = r.window.getAttributes();
            a.mDecor = decor;
            // 可以看到默认的type为TYPE_BASE_APPLICATION类型
            l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
            l.softInputMode |= forwardBit;
            if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);  // 将decorview增加到window中
                } else {
                    a.onWindowAttributesChanged(l);
                }
            }
        } else if (!willBeVisible) {
            r.hideForNow = true;
        }

        if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
            if (r.newConfig != null) {
                // 如果配置变化,通知参数变化
                performConfigurationChangedForActivity(r, r.newConfig);
                r.newConfig = null;
            }

            WindowManager.LayoutParams l = r.window.getAttributes();
            if ((l.softInputMode
                         & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)
                    != forwardBit) {
                l.softInputMode = (l.softInputMode
                                           & (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))
                        | forwardBit;
                if (r.activity.mVisibleFromClient) {
                    ViewManager wm = a.getWindowManager();
                    View decor = r.window.getDecorView();
                    // 由于输入法存在不同的模式(叠加,或者压缩window,都需要重新调节window的参数)
                    wm.updateViewLayout(decor, l);
                }
            }

        }
    }

我们主要看WindowManager的addView方法。首先我们看看WindowManager的实体对象是什么?获取服务的实现实际都在ContextImpl模块的

public String getSystemServiceName(Class<?> serviceClass) {
    return SystemServiceRegistry.getSystemServiceName(serviceClass);
}

然后我们看一下SystemServiceRegistry里面到底对应什么

    public static String getSystemServiceName(Class<?> serviceClass) {
        return SYSTEM_SERVICE_NAMES.get(serviceClass);
    }

static {
        registerService(Context.WINDOW_SERVICE, WindowManager.class,
                new CachedServiceFetcher<WindowManager>() {
            @Override
            public WindowManager createService(ContextImpl ctx) {
                return new WindowManagerImpl(ctx);
            }});
}

    private static <T> void registerService(String serviceName, Class<T> serviceClass,
            ServiceFetcher<T> serviceFetcher) {
        SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
        SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
    }

由上面的代码段知道为WindowManagerImpl,我们看一看实现

@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}

这里有个mContext.getDisplay()表示什么意思,实际上就是多屏显示的时候,显示器的id号。
再一次丢给了WindowManagerGlobal的单例对象mGlobal,我们看一下WindowManagerGlobal实现:

public void addView(View view, ViewGroup.LayoutParams params,
                        Display display, Window parentWindow) {

        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {

            // 生成一个ViewRootImpl作为上下层的中间辅助类
            root = new ViewRootImpl(view.getContext(), display);

            view.setLayoutParams(wparams);

            // 增加到本地的数组,用于管理
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);

            try {
                // 绑定ViewRootImpl和view,并进一步显示
                root.setView(view, wparams, panelParentView);
            } catch (RuntimeException e) {
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
                throw e;
            }
        }
    }

接着ViewRootImpl的setView方法:

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    synchronized (this) {
        if (mView == null) {
            mView = view;

            if (view instanceof RootViewSurfaceTaker) {
                mSurfaceHolderCallback =
                        ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
                if (mSurfaceHolderCallback != null) {
                    mSurfaceHolder = new TakenSurfaceHolder();
                    mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
                    mSurfaceHolder.addCallback(mSurfaceHolderCallback);
                }
            }

            if (mSurfaceHolder == null) {
                enableHardwareAcceleration(attrs);
                final boolean useMTRenderer = MT_RENDERER_AVAILABLE
                        && mAttachInfo.mThreadedRenderer != null;
                if (mUseMTRenderer != useMTRenderer) {
                    // Shouldn't be resizing, as it's done only in window setup,
                    // but end just in case.
                    endDragResizing();
                    mUseMTRenderer = useMTRenderer;
                }
            }

            // 进行绘图
            requestLayout();
            try {
                mOrigWindowType = mWindowAttributes.type;
                mAttachInfo.mRecomputeGlobalAttributes = true;
                collectViewAttributes();
                // 建立session 将window调用底层显示
                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();
                }
            }
        }
    }
}

两个重要的方法,requestLayout,上层绘图步骤

public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
        checkThread();  // 检查线程是否主线程
        mLayoutRequested = true;
        scheduleTraversals(); // 实现绘图操作
    }
}
void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        mChoreographer.postCallback(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        if (!mUnbufferedInputDispatch) {
            scheduleConsumeBatchedInput();
        }
        notifyRendererOfFramePending();
        pokeDrawLockIfNeeded();
    }
}

这里涉及到绘图重要的组织者Choreographer,我们看看他post在做什么

public void postCallback(int callbackType, Runnable action, Object token) {
        // 实际上执行的就是下面这个postCallbackDelayedInternal
        postCallbackDelayed(callbackType, action, token, 0);
}
 private void postCallbackDelayedInternal(int callbackType,
            Object action, Object token, long delayMillis) {
        if (DEBUG_FRAMES) {
            Log.d(TAG, "PostCallback: type=" + callbackType
                    + ", action=" + action + ", token=" + token
                    + ", delayMillis=" + delayMillis);
        }

        synchronized (mLock) {
            final long now = SystemClock.uptimeMillis();
            final long dueTime = now + delayMillis;
            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

            if (dueTime <= now) {
                scheduleFrameLocked(now);
            } else {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
                msg.arg1 = callbackType;
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, dueTime);
            }
        }
    }

这边有两个逻辑,一个是如果当前时间刚刚好,那就直接执行,否则,发送一个延迟的handler消息进行执行。
而handler的message MSG_DO_SCHEDULE_CALLBACK最终会执行到:

void doScheduleCallback(int callbackType) {
    synchronized (mLock) {
        if (!mFrameScheduled) {
            final long now = SystemClock.uptimeMillis();
            if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
                scheduleFrameLocked(now);
            }
        }
    }
}

实际上还是执行scheduleFrameLocked。我们看一下方法

private void scheduleFrameLocked(long now) {
        if (!mFrameScheduled) {
            mFrameScheduled = true;
            if (USE_VSYNC) {
                // 使用VSYNC信号进行通知
                if (isRunningOnLooperThreadLocked()) {
                    // 如果在当前looper的thread里,直接执行
                    scheduleVsyncLocked(); // 发送vsync消息给底层
                } else {
                    // 如果执行thread不是当前looper,则发送消息,达到当前looper的线程里
                    Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
                    msg.setAsynchronous(true);
                    mHandler.sendMessageAtFrontOfQueue(msg); // 最终还是执行到scheduleVsyncLocked
                }
            } else {
                // 直接执行
                final long nextFrameTime = Math.max(
                        mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
                Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, nextFrameTime);
            }
        }
    }

我们知道手机上所有的view的展示,都是一帧一帧的,而为了界面显示的流畅性,要判断是否要到了刷新的下一帧。所以这边展示的时候,会再发一个消息,以保证真正执行的时间是下一帧,而不是立即执行。由于每一帧展示需要耗时绘制view,所以会给这个过程增加标记mFrameScheduled。如果在预期下一帧到来时还没有执行完毕,那么就会被新的一帧所代替。
MSG_DO_FRAME最终会调用到doFrame()方法。
为什么这边还有个VSYNC的概念,这是两种方式,目的是类似的,我们看一下VSYNC的机制。

private final class FrameDisplayEventReceiver extends DisplayEventReceiver
            implements Runnable {
        private boolean mHavePendingVsync;
        private long mTimestampNanos;
        private int mFrame;

        public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
            super(looper, vsyncSource);
        }
        @Override
        public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
            mTimestampNanos = timestampNanos;
            mFrame = frame;
            Message msg = Message.obtain(mHandler, this);
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
        }

        @Override
        public void run() {
            mHavePendingVsync = false;
            doFrame(mTimestampNanos, mFrame);
        }
    }

当Vsync消息到达之后,FrameDisplayEventReceiver会回调onVsync,而后执行run()中的doFrame方法。这就和前面回归到了一起,我们再看一下doFrame方法。

void doFrame(long frameTimeNanos, int frame) {
    try {
        AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);

        mFrameInfo.markInputHandlingStart();
        // 根据type,执行我们在一开始postCallback中的任务
        doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);

        mFrameInfo.markAnimationsStart();
        doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
        doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);

        mFrameInfo.markPerformTraversalsStart();
        doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);

        doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
    } finally {
    }
}

具体看一下doCallbacks

void doCallbacks(int callbackType, long frameTimeNanos) {
    try {
        for (CallbackRecord c = callbacks; c != null; c = c.next) {
            c.run(frameTimeNanos);
        }
    } finally {
        synchronized (mLock) {
            mCallbacksRunning = false;
            do {
                final CallbackRecord next = callbacks.next;
                recycleCallbackLocked(callbacks);
                callbacks = next;
            } while (callbacks != null);
        }
    }
}

实际上就是在执行我们前面post的runnable。
那我们再来看一下ViewRootImpl中post的runnable的方法具体实现

mTraversalRunnable:
    final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }
    void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
            performTraversals();
        }
    }

performTraversals()实际就会执行到
performMeasure
performLayout
performDraw
三个方法,这个就是上层绘制过程,这边先不讨论。

接着我们看到服务层的addview的过程,也就是上面代码段

res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                        getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
                        mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                        mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);

先看一下这个mWindowSession创建

public static IWindowSession getWindowSession() {
    synchronized (WindowManagerGlobal.class) {
        if (sWindowSession == null) {
            try {

           InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
                IWindowManager windowManager = getWindowManagerService();
                sWindowSession = windowManager.openSession(
                        new IWindowSessionCallback.Stub() {
                            @Override
                            public void onAnimatorScaleChanged(float scale) {
                                ValueAnimator.setDurationScale(scale);
                            }
                        });
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
        return sWindowSession;
    }
}

这个创建session的操作,实际是WMS来实现的,OK ,我们看一下实现:

public IWindowSession openSession(IWindowSessionCallback callback) {
    return new Session(this, callback);
}

实际上Session就是WMS为上层添加view的binder。我们看一下其addToDisplay实现:

public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
        int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
        Rect outStableInsets, Rect outOutsets,
        DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
        InsetsState outInsetsState) {
    return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
            outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel,
            outInsetsState);
}

实际上Session还是在调用WMS的接口,这里面就涉及到了窗口优先级,窗口的分组等问题,这些我们以后在分析。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值