美文网首页
第十一章:WindowManagerService(2)

第十一章:WindowManagerService(2)

作者: momxmo | 来源:发表于2020-04-28 15:56 被阅读0次

    通过上一章 我们了解到了WMS与App直接是如何实现双向通信,以及Window、Session、WindowState、WindowToken、DisplayContent等重要类的意义和在这个过程中的作用;

    本章主要通过应用开发过程中,Window是如何添加到WMS和删除;
    主要流程如下;

    一、 Window的添加

    Activity并不是View展示的唯一方式, 初步理解Window体系这篇文章有大致介绍了Activity启动--->window创建--->window显示的过程,实际过程更为复杂,这里我们通过简单的View浮窗展示来分析;
    app创建浮窗代码:

    private void addTextViewWindow(Context context){
    
        TextView mview=new TextView(context);
        ...<!--设置颜色 样式-->
        <!--Step:1-->
        WindowManager mWindowManager = (WindowManager) context.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
        WindowManager.LayoutParams wmParams = new WindowManager.LayoutParams();
        <!--Step:2-->
        wmParams.type = WindowManager.LayoutParams.TYPE_TOAST;
        wmParams.format = PixelFormat.RGBA_8888;
        wmParams.width = 800;
        wmParams.height = 800;
        <!--Step:3-->
        mWindowManager.addView(mview, wmParams);
    }
    
    • Step1:通过content获取系统WMS服务代理对象WindowManager;代理对象实例为WindowManagerImpl类;
      具体可以看:
      frameworks/base/core/java/android/app/SystemServiceRegistry.java
    final class SystemServiceRegistry {
    ....
      registerService(Context.WINDOW_SERVICE, WindowManager.class,
                    new CachedServiceFetcher<WindowManager>() {
                @Override
                public WindowManager createService(ContextImpl ctx) {
                    return new WindowManagerImpl(ctx);
                }});
    ....
    }
    
    • Step2:WindowManager.LayoutParams,主要看一个type参数,这个参数决定了窗口的类型,这里我们定义成一个Toast窗口,属于系统窗口,不需要处理父窗口、子窗口之类的事,更容易分析
    • Step3:WindowManagerImpladdView方法添加ViewWMS,如下源码
    public final class WindowManagerImpl implements WindowManager {
    ......
    //单利  整个进程唯一
        private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    ......
      @Override
        public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
          //设置默认token
            applyDefaultToken(params);
    //委托mGlobal添加View
            mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
        }
    }
    

    WindowManagerGlobal的addView方法
    分析一下addView所执行的操作

    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
    
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
            <!--关键点1-->
            root = new ViewRootImpl(view.getContext(), display);
            view.setLayoutParams(wparams);
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
        }
       <!--关键点2-->
        try {
            root.setView(view, wparams, panelParentView);
        }           
         ...  }
    
    • 关键点1,WindowManagerGlobal首先创建ViewRootImpl;ViewRootImpl是与WMS相互通讯的关键;比如将View添加到WMS中、处理WMS传入触摸事件、通知WMS更新窗口大小等;如图,可以看上一篇理解
      image.png
      同时ViewRootImpl也封装了View的绘制与更新方法等;
      下面分析ViewRootImpl如何setView将试图添加到WMS中;
      frameworks/base/core/java/android/view/ViewRootImpl.java
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
            synchronized (this) {
                if (mView == null) {
                    mView = view;
                      ...
                        <!--关键点1 -->
                    // 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.
                    requestLayout();
                    if ((mWindowAttributes.inputFeatures
                            & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                        mInputChannel = new InputChannel();
                    }
                    try {
                        <!--关键点2 -->
                        res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                                getHostVisibility(), mDisplay.getDisplayId(),
                                mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                                mAttachInfo.mOutsets, mInputChannel);
                    } catch (RemoteException e) {
                   ...
    
    • 关键点1:将第一个布局安排在添加到窗口管理器之前,以确保在从系统接收任何其他事件之前进行中继。也就是说,必须要先将各个View的布局、位置处理好,才处理其他WMS传来的事件,例如触摸事件等;
    • 关键点2:mWindowSession是WMS对外提供的AIDL接口类,能够直接调用VMS的内部服务;这个接口主要是App向WMS发起调用,还有一个mWindow是App提供WMS调用的AIDL接口,mWindowSessionmWindow是比较重要的通讯对象;都是在ViewRootImpl实例化的时候创建;
    public ViewRootImpl(Context context, Display display) {
        mContext = context;
        mWindowSession = WindowManagerGlobal.getWindowSession();
        mWindow = new W(this);
    .....
    

    下面分析一下Session.addToDisplay的实现
    frameworks/base/services/core/java/com/android/server/wm/Session.java

    public int addWindow(Session session, IWindow client, int seq,
                WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
                Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
                InputChannel outInputChannel) {
            ...
            synchronized(mWindowMap) {
            ...
            <!--关键点1 不能重复添加-->
                if (mWindowMap.containsKey(client.asBinder())) {
                    return WindowManagerGlobal.ADD_DUPLICATE_ADD;
                }
            <!--关键点2 对于子窗口类型的处理 1、必须有父窗口 2,父窗口不能是子窗口类型-->
                if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
                    parentWindow = windowForClientLocked(null, attrs.token, false);
                    if (parentWindow == null) {
                        return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
                    }
                    if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
                            && parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
                        return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
                    }}
               ...
               boolean addToken = false;
                <!--关键点3 根据IWindow 获取WindowToken WindowToken是窗口分组的基础,每个窗口必定有一个分组-->
                WindowToken token = mTokenMap.get(attrs.token);
              <!--关键点4对于Toast类系统窗口,其attrs.token可以看做是null, 如果目前没有其他的类似系统窗口展示,token仍然获取不到,仍然要走新建流程-->
                if (token == null) {
                ...    
                    token = new WindowToken(this, attrs.token, -1, false);
                    addToken = true;
                } 
                ...
                 <!--关键点5 新建WindowState,WindowState与窗口是一对一的关系,可以看做是WMS中与窗口的抽象实体-->
                WindowState win = new WindowState(this, session, client, token,
                        attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
                ...
                if (addToken) {
                    mTokenMap.put(attrs.token, token);
                }
                win.attach();
                mWindowMap.put(client.asBinder(), win);
                ... 
               <!--关键点6-->
              addWindowToListInOrderLocked(win, true);
            return res;
        }
    
    

    参数理解:

    • IWindow:APP端窗口暴露给WMS的抽象实例,在ViewRootImpl中实例化,与ViewRootImpl一一对应,同时也是WMS向APP端发送消息的Binder通道。

    • WindowState:WMS端窗口的令牌,与IWindow,或者说与窗口一一对应,是WMS管理窗口的重要依据。

    • WindowToken:窗口的令牌,其实也可以看做窗口分组的依据,在WMS端,与分组对应的数据结构是WindowToken(窗口令牌),而与组内每个窗口对应的是WindowState对象,每块令牌(AppWindowToken、WindowToken)都对应一组窗口(WindowState),Activity与Dialog对应的是AppWindowToken,PopupWindow对应的是普通的WindowToken。


      image.png
    • AppToken:其实是ActivityRecord里面的IApplicationToken.Stub appToken 代理,也是ActivityClientRecord里面的token,可以看做Activity在其他服务(非AMS)的抽象
      关键点:

    • 关键点1:一个窗口不能被添加两次,IWindow是一个Binder代理,在WMS端,一个窗口只会有一个IWindow代理,这是由Binder通信机制保证的,这个对象不能被添加两次,否则会报错。

    • 关键点2,如果是子窗口的话,父窗口必须已被添加,由于我们分析的是系统Toast窗口,可以先不用关心;

    • 关键点3,WindowManager.LayoutParams中有一个token字段,该字段标志着窗口的分组属性,比如Activity及其中的Dialog是复用用一个AppToken,Activity里的PopupWindow复用一个IWindow类型Token,其实就是Activity的ViewRootImpl里面创建的IWindow,而对于我们现在添加的Toast类系统窗口,并未设置其attrs.token,那即是null,其实所有的Toast类系统窗口的attrs.token都可以看做null,就算不是null,也会在WMS被强制设置为null。所以Toast类系统窗口必定复用一个WindowToken,也可以说所有的Toast类系统窗口都是位于同一分组,这也是因为该类型系统窗口太常用,而且为所有进程服务,直接用一个WindowToken管理更加快捷,毕竟快速新建与释放WindowToken也算是一种开销。假设到我们添加系统窗口的时候,没有任何系统窗口展示,是获取不到key=null的WindowToken的,要新建WindowToken,并且添加到全局的TokenMap中,而

    • 关键点5,其实就是新建窗口在WMS端的抽象实例:WindowState,它同窗口一一对应,详细记录了窗口的参数、Z顺序、状态等各种信息,新建只有会被放入全局的Map中,同时也会被附加到相应的WindowToken分组中去;


    到这里APP端向WMS注册窗口的流程就算走完了,不过只算完成了前半部分,WMS还需要向SurfaceFlinger申请Surface,才算完成真正的分配了窗口。在向SurfaceFlinger申请Surface之前,WMS端需要获得SF的代理,在WindowState对象创建后会利用 win.attach()函数为当前APP申请建立SurfaceFlinger的链接:

    void attach() {
        if (WindowManagerService.localLOGV) Slog.v(
        mSession.windowAddedLocked();
    }
    
    void windowAddedLocked() {
        if (mSurfaceSession == null) {
           // SurfaceSession新建
            mSurfaceSession = new SurfaceSession();
            mService.mSessions.add(this);
           ...
        }
        mNumWindow++;
    }
    

    二、申请Surface

    SurfaceSession对于Session来说是单利的,也就是与APPSeesion一一对应,SurfaceSession所握着的SurfaceFlinger的代理其实就是SurfaceComposerClient,其实现如下:
    frameworks/base/core/java/android/view/SurfaceSession.java

     public SurfaceSession() {
            mNativeClient = nativeCreate();
        }
    
        static jlong nativeCreate(JNIEnv* env, jclass clazz) {
            SurfaceComposerClient* client = new SurfaceComposerClient();
            client->incStrong((void*)nativeCreate);
            return reinterpret_cast<jlong>(client);
        }
    

    Session与APP进程是一一对应的,它会进一步为当前进程建立SurfaceSession会话,可以这么理解:Session是APP同WMS通信的通道,SurfaceSession是WMS为APP向SurfaceFlinger申请的通信通道,同样 SurfaceSession与APP也是一一对应的,既然是同SurfaceFlinger通信的信使,那么SurfaceSession就应该握着SurfaceFlinger的代理,其实就是SurfaceComposerClient里的ISurfaceComposerClient mClient对象,它是SurfaceFlinger为每个APP封装一个代理,也就是
    进程 <-> Session <-> SurfaceSession <-> SurfaceComposerClient <-> ISurfaceComposerClient(BpSurfaceComposerClient)
    五者是一条线, 为什么不直接与SurfaceFlinger通信呢?大概为了SurfaceFlinger管理每个APP的Surface比较方便吧,这四个类的模型如下图:

    image.png

    至于ISurfaceComposerClient(BpSurfaceComposerClient) 究竟是怎么样一步步创建的,其实它是利用ComposerService这样一个单利对象为为每个APP在WMS端申请一个ISurfaceComposerClient对象,在WMS端表现为BpSurfaceComposerClient,在SurfaceFlinger端表现为BnSurfaceComposerClient,具体代码如下:

    SurfaceComposerClient::SurfaceComposerClient()
        : mStatus(NO_INIT), mComposer(Composer::getInstance())
    {
    }
    // 单利的,所以只有第一次的时候采用
    void SurfaceComposerClient::onFirstRef() {
        sp<ISurfaceComposer> sm(ComposerService::getComposerService());
        if (sm != 0) {
            sp<ISurfaceComposerClient> conn = sm->createConnection();
            if (conn != 0) {
                mClient = conn;
                mStatus = NO_ERROR;
            }
        }
    }
    
    sp<ISurfaceComposerClient> SurfaceFlinger::createConnection()
    {
        sp<ISurfaceComposerClient> bclient;
        sp<Client> client(new Client(this));
        status_t err = client->initCheck();
        if (err == NO_ERROR) {
            bclient = client;
        }
        return bclient;
    }
    
    image.png

    刚才说完成了前半部分,主要针对WMS的窗口管理,后半部分则是围绕Surface的分配来进行的,还记得之前ViewRootImpl在setView时候分了两步吗?虽然先调用requestLayout先执行,但是由于其内部利用Handler发送消息延迟执行的,所以可以看做requestLayout是在addWindow之后执行的,那么这里就看添加窗口之后,如何分配Surface的,requestLayout函数调用里面使用了Hanlder的一个小手段,那就是利用postSyncBarrier添加了一个Barrier(挡板),这个挡板的作用是阻塞普通的同步消息的执行,在挡板被撤销之前,只会执行异步消息,而requestLayout先添加了一个挡板Barrier,之后自己插入了一个异步任务mTraversalRunnable,其主要作用就是保证mTraversalRunnable在所有同步Message之前被执行,保证View绘制的最高优先级。具体实现如下:

    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
    
                <!--关键点1 添加塞子-->
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            <!--关键点2 添加异步消息任务-->
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            ...
    

    mTraversalRunnable任务的主要作用是:如果Surface未分配,则请求分配Surface,并测量、布局、绘图,其执行主体其实是performTraversals()函数,该函数包含了APP端View绘制大部分的逻辑, performTraversals函数很长,这里只简要看几个点,其实主要是关键点1:relayoutWindow:

    private void performTraversals() {
                final View host = mView;
                 ...
        if (mFirst || windowShouldResize || insetsChanged ||
                viewVisibilityChanged || params != null) {
                <!--关键点1 申请Surface或者重新设置参数-->
                relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
              <!--关键点2 测量-->
                    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
                }        
              <!--关键点3 布局-->
                    performLayout(lp, desiredWindowWidth, desiredWindowHeight);
               <!--关键点4 更新window-->
                  try {
                    mWindowSession.setInsets(mWindow, insets.mTouchableInsets,
                            contentInsets, visibleInsets, touchableRegion);
                ...
              <!--关键点5 绘制-->
               performDraw();
               ...  
           }
    

    relayoutWindow主要是通过mWindowSession.relayout向WMS申请或者更新Surface如下,这里只关心一个重要的参数mSurface,在Binder通信中mSurface是一个out类型的参数,也就是Surface内部的内容需要WMS端负责填充,并回传给APP端:

     private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
                boolean insetsPending) throws RemoteException {
           ...
            int relayoutResult = mWindowSession.relayout(
                    mWindow, mSeq, params, ...  mSurface);
            ...
            return relayoutResult;
        }
    

    看下到底relayout是如何向SurfaceFlinger申请Surface的。我们知道每个窗口都有一个WindowState与其对应,另外每个窗口也有自己的动画,比如入场/出厂动画,而WindowStateAnimator就是与WindowState的动画,为什么要提WindowStateAnimator,因为WindowStateAnimator是

     public int relayoutWindow(Session session, IWindow client, int seq,... Surface outSurface) {
             WindowState win = windowForClientLocked(session, client, false);
            WindowStateAnimator winAnimator = win.mWinAnimator;
             <!--关键点1 -->
               SurfaceControl surfaceControl = winAnimator.createSurfaceLocked();
               if (surfaceControl != null) {
             <!--关键点2 -->
                 outSurface.copyFrom(surfaceControl);
                    } else {
                        outSurface.release();
                    }
    

    这里只看Surface创建代码,首先通过windowForClientLocked找到WindowState,利用WindowState的WindowStateAnimator成员创建一个SurfaceControl,SurfaceControl会调用native函数nativeCreate(session, name, w, h, format, flags)创建Surface

    static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
            jstring nameStr, jint w, jint h, jint format, jint flags) {
        ScopedUtfChars name(env, nameStr);
        <!--关键点1-->
        sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
        <!--关键点2-->
        sp<SurfaceControl> surface = client->createSurface(
                String8(name.c_str()), w, h, format, flags);
        surface->incStrong((void *)nativeCreate);
        return reinterpret_cast<jlong>(surface.get());
    }
    

    关键点1是取到SurfaceSession对象中SurfaceComposerClient对象,之后调用SurfaceComposerClient的createSurface方法进一步创建SurfaceContro

    sp<SurfaceControl> SurfaceComposerClient::createSurface(
            const String8& name,
            uint32_t w,
            uint32_t h,
            PixelFormat format,
            uint32_t flags)
    {
        sp<SurfaceControl> sur;
        if (mStatus == NO_ERROR) {
            sp<IBinder> handle;
            sp<IGraphicBufferProducer> gbp;
            <!--关键点1 获取图层的关键信息handle, gbp-->
            status_t err = mClient->createSurface(name, w, h, format, flags,
                    &handle, &gbp);
             <!--关键点2 根据返回的图层关键信息 创建SurfaceControl对象-->
            if (err == NO_ERROR) {
                sur = new SurfaceControl(this, handle, gbp);
            }
        }
        return sur;
    }
    

    这里先看mClient->createSurface,SurfaceComposerClient的mClient其实是一个BpSurfaceComposerClient对象,它SurfaceFlinger端Client在WMS端的代理,因此创建Surface的代码还是在SurfaceFlinger服务端的Client对象中,这里有两个关键的变量sp<IBinder> handle与 sp<IGraphicBufferProducer> gbp,前者标志在SurfaceFlinger端的图层,后者用来创建GraphicBuffer,两者类型都是IBinder类型,同时也是需要SurfaceFlinger填充的对象,这两者是一个图层对应的最关键的信息:

    status_t Client::createSurface(
            const String8& name,
            uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
            sp<IBinder>* handle,
            sp<IGraphicBufferProducer>* gbp){
        ...
        <!--关键点2 这里并未直接创建 ,而是通过发送了一个MessageCreateLayer消息-->
        sp<MessageBase> msg = new MessageCreateLayer(mFlinger.get(),
                name, this, w, h, format, flags, handle, gbp);
        mFlinger->postMessageSync(msg);
        return static_cast<MessageCreateLayer*>( msg.get() )->getResult();
    }
    

    Client 并不会直接新建图层,而是向SurfaceFlinger发送一个MessageCreateLayer消息,通知SurfaceFlinger服务去执行,其handler代码如下:

     class MessageCreateLayer : public MessageBase {
            SurfaceFlinger* flinger;
            Client* client;
                virtual bool handler() {
                result = flinger->createLayer(name, client, w, h, format, flags,
                        handle, gbp);
                return true;
            }
        };
    

    其实就是调用SurfaceFlinger的createLayer,创建一个图层,到这里才是真正的创建图层:

    status_t SurfaceFlinger::createLayer(
            const String8& name,
            const sp<Client>& client,
            uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
            sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp)
    {
        if (int32_t(w|h) < 0) {
            return BAD_VALUE;
        }
    
        status_t result = NO_ERROR;
    
        sp<Layer> layer;
      <!--关键点1 新建不同图层-->
        switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
            case ISurfaceComposerClient::eFXSurfaceNormal:
                result = createNormalLayer(client,
                        name, w, h, flags, format,
                        handle, gbp, &layer);
                break;
            case ISurfaceComposerClient::eFXSurfaceDim:
                result = createDimLayer(client,
                        name, w, h, flags,
                        handle, gbp, &layer);
                break;
            default:
                result = BAD_VALUE;
                break;
        }
    
        if (result != NO_ERROR) {
            return result;
        }
       ...
    }
    

    SurfaceFlinger会根据不同的窗口参数,创建不同类型的图层,这里只看一下createNormalLayer普通样式的图层

    status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
            const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
            sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
    {
        // initialize the surfaces
        switch (format) {
        case PIXEL_FORMAT_TRANSPARENT:
        case PIXEL_FORMAT_TRANSLUCENT:
            format = PIXEL_FORMAT_RGBA_8888;
            break;
        case PIXEL_FORMAT_OPAQUE:
            format = PIXEL_FORMAT_RGBX_8888;
            break;
        }
        <!--关键点 1 -->
        *outLayer = new Layer(this, client, name, w, h, flags);
        status_t err = (*outLayer)->setBuffers(w, h, format, flags);
        <!--关键点 2-->
        if (err == NO_ERROR) {
            *handle = (*outLayer)->getHandle();
            *gbp = (*outLayer)->getProducer();
        }
      return err;
    }
    

    可以看到 图层最终对应的是Layer,这里会新建一个Layer对象,Layer中包含着与这个图层对应的Handle及Producer对象,Handle可以看做是Surface的唯一性标识,不过好像没太大的作用,最多是一个标识,将来清理的时候有用。相比之下gbp = (*outLayer)->getProducer()比较重要,它实际是一个BufferQueueProducer对象,关系到共享内存的分配问题,后面会专门分析,这里到此打住,我们终于得到了一个图层对象,到这里之后,我们梳理一下,图层如何建立的:

    • 首先APP端新建一个Surface图层的容器壳子,
    • APP通过Binder通信将这个Surface的壳子传递给WMS,
    • WMS为了填充Surface去向SurfaceFlinger申请真正的图层,
    • SurfaceFlinger收到WMS请求为APP端的Surface分配真正图层
    • 将图层相关的关键信息Handle及Producer传递给WMS

    Layer建立之后,SurfaceFlinger会将图层标识信息Handle及Producer传递给WMS,WMS利用这两者创建一个SurfaceControl对象,之后再利用该对象创建Surface,具体代码如下:

    void getSurface(Surface outSurface) {
        outSurface.copyFrom(mSurfaceControl);
    }
    
    public void copyFrom(SurfaceControl other) {
    long surfaceControlPtr = other.mNativeObject;
    long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr);
    synchronized (mLock) {
        setNativeObjectLocked(newNativeObject);
    }
    }
    

    可以看到Surface的拷贝函数其实就是直接修改Surface native对象指针值,native的Surface对象中包含mGraphicBufferProducer对象,很重要,会被传递给APP端。

    static jlong nativeCreateFromSurfaceControl(JNIEnv* env, jclass clazz,
            jlong surfaceControlNativeObj) {
    
        sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));
        sp<Surface> surface(ctrl->getSurface());
        if (surface != NULL) {
            surface->incStrong(&sRefBaseOwner);
        }
        return reinterpret_cast<jlong>(surface.get());
    }
    
    sp<Surface> SurfaceControl::getSurface() const
    {
        Mutex::Autolock _l(mLock);
        if (mSurfaceData == 0) {
            mSurfaceData = new Surface(mGraphicBufferProducer, false);
        }
        return mSurfaceData;
    }
    

    到这里WMS端Surface创建及填充完毕,并且Surface其实与WMS的SurfaceControl一一对应,当APP端需要在图层级别进行操控的时候,其实还是要依靠SurfaceControl的,WMS的Surface创建完毕后,需要传递给APP端,之后APP端就获得直接同SurfaceFlinger通信的能力,比如绘图与UI更新,怎传递的呢?

    三、APP端与SurfaceFlinger底层服务通信

    我们知道Surface实现了Parcel接口,因此可以传递序列化的数据,其实看一下Surface nativeReadFromParcel就知道到底是怎么传递的了,利用readStrongBinder获取IGraphicBufferProducer对象的句柄,之后转化为IGraphicBufferProducer代理其实就是BpGraphicBufferProducer,之后利用BpGraphicBufferProducer构建Surface,这样APP端Surface就被填充完毕,可以同SurfaceFlinger通信了:

    static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz,
            jlong nativeObject, jobject parcelObj) {
        Parcel* parcel = parcelForJavaObject(env, parcelObj);
        if (parcel == NULL) {
            doThrowNPE(env);
            return 0;
        }
         sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
        sp<IBinder> binder(parcel->readStrongBinder());
        if (self != NULL
                && (IInterface::asBinder(self->getIGraphicBufferProducer()) == binder)) {
            return jlong(self.get());
        }
        sp<Surface> sur;
        sp<IGraphicBufferProducer> gbp(interface_cast<IGraphicBufferProducer>(binder));
        if (gbp != NULL) {
            sur = new Surface(gbp, true);
            sur->incStrong(&sRefBaseOwner);
        }
    
        if (self != NULL) {
            self->decStrong(&sRefBaseOwner);
        }
    
        return jlong(sur.get());
    }
    

    到这里为止,APP<->WMS <->WMS 通信申请Surface的流程算走完了

    image.png

    四、总结

    窗口的添加流程简化如下,这里暂且忽略窗口的分组管理。

    • APP首先去WMS登记窗口
    • WMS端登记窗口
    • APP新建Surface壳子,请求WMS填充Surface
    • WMS请求SurfaceFlinger分配窗口图层
    • SurfaceFlinger分配Layer,将结果回传给WMS
    • WMS将窗口信息填充到Surface传输到APP
    • APP端获得填充信息,获取与SurfaceFlinger通信的能力

    相关文章

      网友评论

          本文标题:第十一章:WindowManagerService(2)

          本文链接:https://www.haomeiwen.com/subject/dxwvwhtx.html