应用程序中的每个窗口,对应本地代码中的Surface,而Surface又对应 于SurfaceFlinger中的各个Layer,SurfaceFlinger的主要作用是为这些Layer申请内存,根据应用程序的请求管理这些 Layer显示、隐藏、

重画等操作,最终由SurfaceFlinger把所有的Layer组合到一起,显示到显示器上。

一、Surface的创建过程:



请看如下序列图:

android自定义surfaceview设置边框 android surface创建_primitive

那么创建 Surface 主要分为两个步骤:

1、建立 SurfaceSession

     主要利用 SurfaceComposerClient 实例,调用 sp<ISurfaceFlingerClient> SurfaceFlinger::createConnection() 返回一个 ISurfaceFlingerClient接口给

     SurfaceComposerClient,并在createConnection的过程中,SurfaceFlinger创建了用于管理缓冲

区切换的SharedClient。最后,本地层把SurfaceComposerClient的实例返回给 JAVA层,完成

SurfaceSession的建立。 这个过程一般只执行一次。


2、利用 SurfaceSession 创建 Surface 

     在 WindowManagerService.java 中创建不同属性的 Surface ,目前有如下三种类型:

    (Surface.java 中定义)

public static final int FX_SURFACE_NORMAL   = 0x00000000;
    public static final int FX_SURFACE_BLUR     = 0x00010000;
    public static final int FX_SURFACE_DIM     = 0x00020000;

    一般如此使用:

mSurface = new Surface(
                             mSession.mSurfaceSession, mSession.mPid,
                             mAttrs.getTitle().toString(),
                             0, w, h, mAttrs.format, flags)

    比如没有硬件光标层就是在此创建一个Surface用于鼠标移动的显示,作为鼠标移动时的画布。

    

    SurfaceFlinger::createSurface

    根据flags创建不同类型的Layer,然后调用Layer的setBuffers()方法, 为该Layer创建了两个缓冲区,

然后返回该Layer的ISurface接口,SurfaceComposerClient使用这个 ISurface接 口创建一个

SurfaceControl实例,并把这个SurfaceControl返回给JAVA层。

    重要代码:

sp<Layer> layer = new Layer(this, display, client, id);
     status_t err = layer->setBuffers(w, h, format, flags);    ...
    return layer ;

二、获得Surface对应的显示缓冲区:

SurfaceFlinger在创建Layer时已经为每个Layer申请了两个缓冲区,但是此时在JAVA层并看不到这

两个缓冲区, JAVA层要想在Surface上进行画图操作,必须要先把其中的一个缓冲区绑定到Canvas

中,然后所有对该Canvas的画图操作最后都会画到该缓冲区内.

android自定义surfaceview设置边框 android surface创建_layer_02


重要的几个操作分析:

/** draw into a surface */
lockCanvas -> lockCanvasNative() --> JNI 函数
static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect)
 
{ 
// 利用 SurfaceControl对象,通过getSurface() 取得本地层的Surface对象  
const sp<Surface>& surface(getSurface(env, clazz));
// 利用dequeueBuffer(&backBuffer) 返回该Surface的信息,其中包含 Surface 缓冲区的
// 首地址vaddr, 最后调用到libgralloc.so 动态库中去了,这个后面分析
status_t err = surface->lock(&info, &dirtyRegion);
==>
           void* vaddr;
             status_t res = backBuffer->lock(
                     GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,                    newDirtyRegion.bounds(), &vaddr);
...

// 需要将 Surface 转换成 Bitmap 对象,这个JAVA对象直接在Canvas画图,其所有操作都会在以
// vaddr为首的缓冲区中, 两个对象的关系通过setBitmapDevice建立
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); // bitmap绑定到Canvas中...}

下面对 Surface::lock 补充说明一下:

a、dequeueBuffer(&backBuffer)获取backBuffer 

  SharedBufferClient->dequeue()获得当前空闲缓冲区的编号

  通过缓冲区编号获得真正的GraphicBuffer:backBuffer

  如果还没有对Layer中的buffer进行映射(Mapper),getBufferLocked通过ISurface接口重新重新映射

sp<GraphicBuffer> buffer = s->requestBuffer(index, usage);

 b、获取frontBuffer --> const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);

c、根据两个Buffer的更新区域,把frontBuffer的内容拷贝到backBuffer中,这样保证了两个Buffer中显示内容同步

利用 copyBlt(backBuffer, frontBuffer, copyback); --> 这里通过 memcpy,效率上是否有影响?

 d、backBuffer->lock() 获得backBuffer缓冲区的首地址vaddr,最后通过info参数返回vaddr


三、释放Surface对应的显示缓冲区

画图完成后,要想把Surface的内容显示到屏幕上,需要把Canvas中绑定的缓冲区释放,并且把该缓冲区从

变成可投递(因为默认只有两个 buffer,所以实际上就是变成了frontBuffer),SurfaceFlinger的工作线程会

在适当的刷新时刻,把系统中所有的 frontBuffer混合在一起,然后通过OpenGL刷新到屏幕上。

 

android自定义surfaceview设置边框 android surface创建_android_03

/** unlock the surface and asks a page flip */
 public native   void unlockCanvasAndPost(Canvas canvas);


JNI 操作:

static void Surface_unlockCanvasAndPost(
         JNIEnv* env, jobject clazz, jobject argCanvas)
 {     const sp<Surface>& surface(getSurface(env, clazz));
// 绑定一个空的bitmap到Canvas中
nativeCanvas->setBitmapDevice(SkBitmap());
    // unlock surface
      status_t err = surface->unlockAndPost();}

status_t Surface::unlockAndPost() 
 { status_t err = mLockedBuffer->unlock();
err = queueBuffer(mLockedBuffer.get());
}

调用Surface的unlockAndPost方法 

1、 调用GraphicBuffer的unlock(),解锁缓冲区

2、queueBuffer()调用了SharedBufferClient的queue(),把该缓冲区更新为可投递状态


================= 小概念==========================================

画图需要“四大金钢”相互合作:

Bitmap: 用于存储像素,也就是画布,可把它当做一块数据存储区域

Canvas: 用于记载画图的动作,比如画一个圆,矩形等,提供这些基本的绘图函数

Paint: 用于描述绘画时使用的颜色,风格(如实线,虚线)等

Drawing primitive: 绘图基元,如矩形,圆,文本,图片等