android surfaceflinger研究----Surface机制

 

转自: http://blog.csdn.net/windskier/article/details/7041610

       前一篇文章介绍了android的显示系统,这篇文章中,我们把视角往上层移动一下,研究一下framework是如何与surfaceflinger进行业务交互的。

       1)如何创建surface

       2)如何显示窗口等等

       所有的这一切都是通过系统服务WindowManagerService与surfaceflinger来进行的。

        Android中的Surface机制这一块代码写的比较难理解,光叫Surface的类就有3个,因此本篇文章从两部分来分析。

       首先,想要理解Surface机制,还是需要首先理清各个类之间的关系。

       其次,在理解了整个Surface机制的类关系之后,到时我们再结合前一篇文章中对显示系统的介绍,研究一下一个Surface是如何和显示系统建立起联系来的,这个联系主要是指Surface的显示buffer的存储管理。

        在下篇文章中,再分析SurfaceFlinger是如何将已经存储了窗口图形数据的Surface Buffer显示到显示系统中。

1. Surface机制的静态关系

    将这一部分叫做Surface机制,是有别于SurfaceFlinger而言的,android的图形系统中,作为C/S模型两端的WMS和SurfaceFlinger是图形系统业务的核心,但是不把WMS和SurfaceFlinger中间的这层联系搞清楚的话,是很难理解整个图形系统的,在本文中我将两者之间的这个联系关系称之为Surface机制,它的主要任务就是创建一个Surface,ViewRoot在这个Surface上描绘当前的窗口,SurfaceFlinger将这个Surface flinger(扔)给显示系统将其呈现在硬件设备上。其实这里这个Surface在不同的模块中是以不同的形态存在的,唯一不变的就是其对应的显示Buffer。

1.1 ViewRoot和WMS共享Surface

      我们知道每个Activity都会有一个ViewRootImpl作为Activity Window与WMS交互的接口,ViewRootImpl会绘制整个Activity的窗口View到Surface上,因此我们在ViewRootImpl中就有了创建Surface的需求。看一下代码中的Surface的定义:

ViewRootImpl.java

    // These can be accessed by any thread, must be protected with a lock.
    // Surface can never be reassigned or cleared (use Surface.clear()).
    private final Surface mSurface = new Surface();


Surface(SurfaceTexture surfaceTexture)@Surface.java

    /**
     * Create Surface from a {@link SurfaceTexture}.
     *
     * Images drawn to the Surface will be made available to the {@link
     * SurfaceTexture}, which can attach them an OpenGL ES texture via {@link
     * SurfaceTexture#updateTexImage}.
     *
     * @param surfaceTexture The {@link SurfaceTexture} that is updated by this
     * Surface.
     */
    public Surface(SurfaceTexture surfaceTexture) {
        if (DEBUG_RELEASE) {
            mCreationStack = new Exception();
        }
        mCanvas = new CompatibleCanvas();
        initFromSurfaceTexture(surfaceTexture);
    }


       由上面可以看出在ViewRootImpl中定义的Surface只是一个空壳,那么真正的Surface是在哪里被初始化的呢?大管家WMS中!当ViewRootImpl请求WMS relayout时,会将ViewSurface中的Surface交给WMS初始化。在WMS中,对应每个WindowState对象,在relayout窗口时,同样会创建一个Surface,wms中的这个Surface会真正的初始化,然后再将这个WMS Surface复制给ViewRootImpl中的Surface。这么实现的目的就是保证ViewRootImpl和WMS共享同一个Surface。ViewRootImpl对Surface进行绘制,WMS对这个Surface进行初始化及管理。很和谐!

[email protected]

    private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
            boolean insetsPending) throws RemoteException {
        ... 
        int relayoutResult = sWindowSession.relayout(
                mWindow, mSeq, params,
                (int) (mView.getMeasuredWidth() * appScale + 0.5f),
                (int) (mView.getMeasuredHeight() * appScale + 0.5f),
                viewVisibility, insetsPending, mWinFrame,
                mPendingContentInsets, mPendingVisibleInsets,
                mPendingConfiguration, mSurface);
        //Log.d(TAG, "<<<<<< BACK FROM relayout");
        if (restore) {
            params.restore();
        }
        
        if (mTranslator != null) {
            mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
            mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
            mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
        }
        return relayoutResult;
    }

relayoutWindow()@WindowManagerService.java

    public int relayoutWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int requestedWidth,
            int requestedHeight, int viewVisibility, boolean insetsPending,
            Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,
            Configuration outConfig, Surface outSurface) {
        boolean displayed = false;
        boolean inTouchMode;
        boolean configChanged;

        // if they don't have this permission, mask out the status bar bits
        synchronized(mWindowMap) {
            WindowState win = windowForClientLocked(session, client, false);

            if (viewVisibility == View.VISIBLE &&
                    (win.mAppToken == null || !win.mAppToken.clientHidden)) {
                displayed = !win.isVisibleLw();
                ...
                try {
                    Surface surface = win.createSurfaceLocked();
                    if (surface != null) {
                        outSurface.copyFrom(surface);
                        win.mReportDestroySurface = false;
                        win.mSurfacePendingDestroy = false;
                        if (SHOW_TRANSACTIONS) Slog.i(TAG,
                                "  OUT SURFACE " + outSurface + ": copied");
                    } else {
                        // For some reason there isn't a surface.  Clear the
                        // caller's object so they see the same state.
                        outSurface.release();
                    }
                } catch (Exception e) {
                    mInputMonitor.updateInputWindowsLw(true /*force*/);
                    
                    Slog.w(TAG, "Exception thrown when creating surface for client "
                             + client + " (" + win.mAttrs.getTitle() + ")",
                             e);
                    Binder.restoreCallingIdentity(origId);
                    return 0;
                }
                ...
           }
    }


 

1.2 SurfaceSession

     SurfaceSession可以认为是创建Surface过程中,WMS和SurfaceFlinger之间的会话层,通过这个SurfaceSession实现了Surface的创建。 

     一个SurfaceSession表示一个到SurfaceFlinger的连接,通过它可以创建一个或多个Surface实例。

       SurfaceSession是JAVA层的概念,@SurfaceSession.java。它对应的native实体是一个SurfaceComposerClient对象。

       SurfaceComposerClient通过ComposerService类来获得SurfaceFlinger的IBinder接口ISurfaceComposer,但是光获得SurfaceFlinger的IBinder接口是不够的,要想请求SurfaceFlinger创建一个Surface,还需要向SurfaceFlinger获得一个IBinder接口ISurfaceComposerClient,通过这个ISurfaceComposerClient来请求SurfaceFlinger创建一个Surface,为什么这么绕呢,为什么不直接让SurfaceFlinger创建Surface呢?

     站在SurfaceFlinger的角度来考虑,对于SurfaceFlinger来说,可能有多个Client来请求SurfaceFlinger的业务,每个Client可能会请求SurfaceFlinger创建多个Surface,那么SurfaceFlinger本地需要提供一套机制来保存每个client请求创建的Surface,SurfaceFlinger通过为每个client创建一个Client对象实现这个机制,并将这个Client的IBinder接口ISurfaceComposerClient返给SurfaceComposerClient对象。SurfaceComposerClient对象在通过ISurfaceComposerClient去请求创建Surface(ISurfaceComposerClient的功能只有创建和销毁Surface)。

@SurfaceFlinger.h

class Client : public BnSurfaceComposerClient

class SurfaceFlinger :
        public BinderService,
        public BnSurfaceComposer,
        public IBinder::DeathRecipient,
        protected Thread


@SurfaceComposerClient.cpp

void SurfaceComposerClient::onFirstRef() {
    sp sm(getComposerService());
    if (sm != 0) {
        sp conn = sm->createConnection();
        if (conn != 0) {
            mClient = conn;
            mStatus = NO_ERROR;
        }
    }
}


在SurfaceFlinger中对应的执行代码为:

sp SurfaceFlinger::createConnection()
{
    sp bclient;
    sp client(new Client(this));
    status_t err = client->initCheck();
    if (err == NO_ERROR) {
        bclient = client;
    }
    return bclient;
}

     下图描述了整个SurfaceSession的内部结构与工作流程。

      蓝色箭头是SurfaceComposerClient通过ComposerService获得SurfaceFlinger的IBinder接口ISurfaceComposer过程;

      红色箭头表示SurfaceComposerClient通过IPC请求SurfaceFlinger创建Client的过程,并获得Client的IBinder接口ISurfaceComposerClient;

      绿色箭头表示SurfaceComposerClient通过IPC请求Client创建Surface。


 

1.3 Surface的形态

       上一节我们分析了SurfaceSession的静态结构,得知Surface的创建过程是通过SurfaceSession这个中间会话层去请求SurfaceFlinger去创建的,并且这篇文章中,我们说了半天Surface了,那么究竟我们要创建的Surface究竟是什么样的一个东西呢,它的具体形态是什么呢?这一小节我们就来分析以下Surface的形态。

1.3.1 client端Surface的形态

    首先,我们看一下Surface在WMS中定义的代码

createSurfaceLocked()@WindowState.java

  Surface createSurfaceLocked() {
        if (mSurface == null) {
            ...
            try {
                final boolean isHwAccelerated = (mAttrs.flags &
                        WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
                final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : mAttrs.format;
                if (!PixelFormat.formatHasAlpha(mAttrs.format)) {
                    flags |= Surface.OPAQUE;
                }
                mSurface = new Surface(
                        mSession.mSurfaceSession, mSession.mPid,
                        mAttrs.getTitle().toString(),
                        0, w, h, format, flags);
                if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
                        "  CREATE SURFACE "
                        + mSurface + " IN SESSION "
                        + mSession.mSurfaceSession
                        + ": pid=" + mSession.mPid + " format="
                        + mAttrs.format + " flags=0x"
                        + Integer.toHexString(flags)
                        + " / " + this);
            } 
            ...
        }
        return mSurface;
    }


       我们可以看到,它将SurfaceSession对象当作参数传递给了Surface的构造函数。往下看Surface的构造函数。

@Surface.java

    /** create a surface with a name @hide */
    public Surface(SurfaceSession s,
            int pid, String name, int display, int w, int h, int format, int flags)
        throws OutOfResourcesException {
        if (DEBUG_RELEASE) {
            mCreationStack = new Exception();
        }
        mCanvas = new CompatibleCanvas();
        init(s,pid,name,display,w,h,format,flags);
        mName = name;
    }


       这个构造函数,不同于我们在ViewRootImpl中看到的Surface的构造函数,这个构造函数并不是一个空壳,它做了本地实体的初始化工作,因此这个Surface才是一个真正的Suface。

       Native函数init(Surface_init@android_view_Surface.cpp)会调到SurfaceComposerClient::createSurface,再向下的过程在上一节的图中描述很清楚了,在此不作介绍了。同时,先不管SurfaceFlinger为SurfaceComposerClient创建的Surface到底是一个什么东西,我们先看看SurfaceComposerClient为WMS创建的是一个什么东西?

 

@SurfaceComposerClient.cpp

sp SurfaceComposerClient::createSurface(
        const String8& name,
        DisplayID display,
        uint32_t w,
        uint32_t h,
        PixelFormat format,
        uint32_t flags)
{
    sp result;
    if (mStatus == NO_ERROR) {
        ISurfaceComposerClient::surface_data_t data;
        sp surface = mClient->createSurface(&data, name, //mClient为BpSurfaceComposerClient
                display, w, h, format, flags);
        if (surface != 0) {
            result = new SurfaceControl(this, surface, data);
        }
    }
    return result;
}

       从上面的代码我们可以看出,SurfaceComposerClient为WMS返回的是一个SurfaceControl对象,这个SurfaceControl对象包含了surfaceFlinger为SurfaceComposerClient创建的surface,这个surfaceFlinge创建的Surface在Client端的形态为ISurface。这个过程下面分析SurfaceFlinger端的Surface形态时会看到。

    SurfaceControl类中还有一个非常重要的成员mSurfaceData,它的类型也叫做Surface,定义在frameworks/base/include/surfaceflinger/surface.h。这个Surface提供了显示Buffer的管理。在文章的后面再介绍。

@frameworks/base/libs/gui/Surface.cpp

sp SurfaceControl::getSurface() const
{
    Mutex::Autolock _l(mLock);
    if (mSurfaceData == 0) {
        sp surface_control(const_cast(this));
        mSurfaceData = new Surface(surface_control);
    }
    return mSurfaceData;
}


1.3.2 SurfaceFlinger端Surface形态

SurfaceFlinger::[email protected]  
sp SurfaceFlinger::createSurface(
        ISurfaceComposerClient::surface_data_t* params,
        const String8& name,
        const sp& client,
        DisplayID d, uint32_t w, uint32_t h, PixelFormat format,
        uint32_t flags)
{
    sp layer;
    sp surfaceHandle;

    if (int32_t(w|h) < 0) {
        LOGE("createSurface() failed, w or h is negative (w=%d, h=%d)",
                int(w), int(h));
        return surfaceHandle;
    }

    //LOGD("createSurface for pid %d (%d x %d)", pid, w, h);
    sp normalLayer;
    switch (flags & eFXSurfaceMask) {
        case eFXSurfaceNormal:
            normalLayer = createNormalSurface(client, d, w, h, flags, format);
            layer = normalLayer;
            break;
        case eFXSurfaceBlur:
            // for now we treat Blur as Dim, until we can implement it
            // efficiently.
        case eFXSurfaceDim:
            layer = createDimSurface(client, d, w, h, flags);
            break;
        case eFXSurfaceScreenshot:
            layer = createScreenshotSurface(client, d, w, h, flags);
            break;
    }

    if (layer != 0) {
        layer->initStates(w, h, flags);
        layer->setName(name);
        ssize_t token = addClientLayer(client, layer);

        surfaceHandle = layer->getSurface();
        if (surfaceHandle != 0) {
            params->token = token;
            params->identity = layer->getIdentity();
            if (normalLayer != 0) {
                Mutex::Autolock _l(mStateLock);
                mLayerMap.add(layer->getSurfaceBinder(), normalLayer);
            }
        }

        setTransactionFlags(eTransactionNeeded);
    }

    return surfaceHandle;
}

       当client请求SurfaceFlinger创建Surface时,SurfaceFlinger首先根据WMS提供的窗口的属性来一个命名为Layer概念的对象,然后再根据Layer创建它的子类对象LayerBaseClient::BSurface。此时第三个名为Surface(BSurface)类出现了,下一节我们来介绍一下这个Layer的概念。

 

 1.4 Layer 

 

1.4.1 Layer的分类

    目前,android4.0中有3中Layer类型,如上图所示。  

    1. Layer, 普通的Layer,它为每个Client端请求的Surface创建显示Buffer。

    2. LayerDim,这种Layer不会创建显示Buffer,它只是将通过这个Layer将原来FrameBuffer上的数据进行暗淡处理;

    3. LayerScreenshot,这种Layer不会创建显示Buffer,它只是将通过这个Layer将原来FrameBuffer上的数据进行抓取;

     从这些Layer看出,我们分析的重点就是第一种Layer,下面我们着重分析一下普通的Layer。Layer的具体业务我们在下一篇文章中分析

1.4.2 Layer的管理

    上文我们在分析SurfaceSession的时候,也分析过,一个Client可能会创建多个Surface,也就是要创建多个Layer,那么SurfaceFlinger端如何管理多个Layer呢?SurfaceFlinger维护了3个Vector来管理LayerDefaultKeyedVector< size_t, wp > mLayers;SurfaceFlinger:LayerVector     layersSortedByZ;>。

       第一种方式,我们知道SurfaceFlinger会为每个SurfaceSession创建一个Client对象,这第一种方式就是将所有为某一个SurfacSession创建的Layer保存在它对应的Client对象中。

     SurfaceFlinger::createSurface()@SurfaceFlinger.cpp,调用路径如下:

     SurfaceFlinger::addClientLayer->

         client->attachLayer(lbc)->

              mLayers.add(name, layer);

 

       第二种方式,在SurfaceFlinger中以排序的方式保存下来。其调用路径如下:

       SurfaceFlinger::addClientLayer->

          SurfaceFlinger::addLayer_l->

             mCurrentState.layersSortedByZ.add(layer)

 

       第三种方式,将所有的创建的普通的Layer保存起来,以便Client Surface在请求实现Buffer时能够辨识Client Surface对应的Layer。

SurfaceFlinger::createSurface()@SurfaceFlinger.cpp

 

        surfaceHandle = layer->getSurface();
        if (surfaceHandle != 0) {
            params->token = token;
            params->identity = layer->getIdentity();
            if (normalLayer != 0) {
                Mutex::Autolock _l(mStateLock);
                mLayerMap.add(layer->getSurfaceBinder(), normalLayer);
            }
        }

2. Surface 显示Buffer的存储管理

       在前文介绍Client端的Surface形态的内容时,我们提到SurfaceControl中还会维护一个名为Surface对象,它定义在 frameworks/base/libs/surfaceflinger/Surface.h中,它负责向LayerBaseClient::BSurface请求显示Buffer,同时将显示Buffer交给JAVA Surface的Canvas去绘制窗口,我们称这个Surface为Client Surface

2.1 窗口绘制

    我们先从ViewRootImpl中分析一下,它是如何显示窗口View的,如何用到Client Surface请求的显示Buffer的。

draw()@ViewRoot.java

            Canvas canvas;
            try {
                int left = dirty.left;
                int top = dirty.top;
                int right = dirty.right;
                int bottom = dirty.bottom;

                final long lockCanvasStartTime;
                if (ViewDebug.DEBUG_LATENCY) {
                    lockCanvasStartTime = System.nanoTime();
                }

                canvas = surface.lockCanvas(dirty);

                if (ViewDebug.DEBUG_LATENCY) {
                    long now = System.nanoTime();
                    Log.d(TAG, "Latency: Spent "
                            + ((now - lockCanvasStartTime) * 0.000001f)
                            + "ms waiting for surface.lockCanvas()");
                }

                if (left != dirty.left || top != dirty.top || right != dirty.right ||
                        bottom != dirty.bottom) {
                    mAttachInfo.mIgnoreDirtyState = true;
                }

                // TODO: Do this in native
                canvas.setDensity(mDensity);
            


       上面的代码显示,JAVA Surface 会lock canvas。而Client Surface的创建就在这个过程中,即下面代码中的第一行getSurface().我们先不管Client Surface的创建,先看看Canvas是如何与Client Surface的显示Buffer关联的。

       Surface_lockCanvas@android_view_Surface.cpp

static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect)
{
    const sp& surface(getSurface(env, clazz));
    if (!Surface::isValid(surface)) {
        doThrowIAE(env);
        return 0;
    }

    // get dirty region
    Region dirtyRegion;
    if (dirtyRect) {
        Rect dirty;
        dirty.left  = env->GetIntField(dirtyRect, ro.l);
        dirty.top   = env->GetIntField(dirtyRect, ro.t);
        dirty.right = env->GetIntField(dirtyRect, ro.r);
        dirty.bottom= env->GetIntField(dirtyRect, ro.b);
        if (!dirty.isEmpty()) {
            dirtyRegion.set(dirty);
        }
    } else {
        dirtyRegion.set(Rect(0x3FFF,0x3FFF));
    }

    Surface::SurfaceInfo info;
    status_t err = surface->lock(&info, &dirtyRegion);
    if (err < 0) {
        const char* const exception = (err == NO_MEMORY) ?
            OutOfResourcesException :
            "java/lang/IllegalArgumentException";
        jniThrowException(env, exception, NULL);
        return 0;
    }

    // Associate a SkCanvas object to this surface
    jobject canvas = env->GetObjectField(clazz, so.canvas);
    env->SetIntField(canvas, co.surfaceFormat, info.format);

    SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas);
    SkBitmap bitmap;
    ssize_t bpr = info.s * bytesPerPixel(info.format);
    bitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, bpr);
    if (info.format == PIXEL_FORMAT_RGBX_8888) {
        bitmap.setIsOpaque(true);
    }
    if (info.w > 0 && info.h > 0) {
        bitmap.setPixels(info.bits);
    } else {
        // be safe with an empty bitmap.
        bitmap.setPixels(NULL);
    }
    nativeCanvas->setBitmapDevice(bitmap);

    SkRegion clipReg;
    if (dirtyRegion.isRect()) { // very common case
        const Rect b(dirtyRegion.getBounds());
        clipReg.setRect(b.left, b.top, b.right, b.bottom);
    } else {
        size_t count;
        Rect const* r = dirtyRegion.getArray(&count);
        while (count) {
            clipReg.op(r->left, r->top, r->right, r->bottom, SkRegion::kUnion_Op);
            r++, count--;
        }
    }

    nativeCanvas->clipRegion(clipReg);

    int saveCount = nativeCanvas->save();
    env->SetIntField(clazz, so.saveCount, saveCount);

    if (dirtyRect) {
        const Rect& bounds(dirtyRegion.getBounds());
        env->SetIntField(dirtyRect, ro.l, bounds.left);
        env->SetIntField(dirtyRect, ro.t, bounds.top);
        env->SetIntField(dirtyRect, ro.r, bounds.right);
        env->SetIntField(dirtyRect, ro.b, bounds.bottom);
    }

    return canvas;
}


      上面的代码,我们可以看出,Canvas的Bitmap设备设置了Client Surface的显示Buffer为其Bitmap pixel存储空间。 
   

        bitmap.setPixels(info.bits);

    这样Canvas的绘制空间就有了。下一步就该绘制窗口了。

   draw()@ViewRootImpl.java

                  try {
                        canvas.translate(0, -yoff);
                        if (mTranslator != null) {
                            mTranslator.translateCanvas(canvas);
                        }
                        canvas.setScreenDensity(scalingRequired
                                ? DisplayMetrics.DENSITY_DEVICE : 0);
                        mAttachInfo.mSetIgnoreDirtyState = false;
                        mView.draw(canvas);
                    }


    其中ViewRootImpl中的mView为整个窗口的View。它将Render自己和所有它的子View。

2.2 Client Surface的初始化(SurfaceControl中的Surface)

        Client Surface的创建是从ViewRootImpl首次Lock canvas时进行的,这么做的目的可能也是为了节约空间,减少不必要的开支。

        Client Surface的初始化和显示Buffer的管理过程比较复杂,下图给出了这一部分的一个静态结构图,有些东西从图上表现不出来,下面我简单的介绍一下。

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(DisplaySystem)