Android图形系统(七)-app请求SurfaceFlinger创建Surface过程

接上篇,WindowManager addView流程来:

ViewRootImpl走setView 我们已经讲了mWindowSession.addToDisplay这条线,app与SurfaceFlinger服务建立了连接,下面我们接着看另外一条线: requestLayout()。

前面我们讲了,requestLayout()开启了绘制流程,具体流程如下图所示:

前三步不啰嗦了,不了解的可以去看View绘制篇,这里我们从WMS中relayoutWindow开始说起:

//WindowManagerService
public int relayoutWindow(Session session, IWindow client,
            WindowManager.LayoutParams attrs, int requestedWidth,
            int requestedHeight, int viewVisibility, boolean insetsPending,
            Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,
            Configuration outConfig, Surface outSurface) {
        ......
        synchronized(mWindowMap) {
            WindowState win = windowForClientLocked(session, client, false);
                ......
                    Surface surface = win.createSurfaceLocked();
                    if (surface != null) {
                        outSurface.copyFrom(surface);
                        ......
                    } 
            ......
}

调用WindowState对象win的成员函数createSurfaceLocked来为它创建一个Surface。如果这个Surface已创建成功,就会将它的内容拷贝到输出参数outSurface,这个outSurface就是从ViewRootImpl调用relayoutWindow通过参数带进来的空Surface对象,以便可以将它返回给应用程序进程处理。

先来看看win.createSurfaceLocked()

    private final class WindowState implements WindowManagerPolicy.WindowState {
        ......
        Surface mSurface;
        ......
        Surface createSurfaceLocked() {
        …...
                   mSurface = new Surface(
                            mSession.mSurfaceSession, mSession.mPid,
                            mAttrs.getTitle().toString(),
                            0, w, h, mAttrs.format, flags);
                    ......
            return mSurface;
        }
        ......
}

简单理解就是new 了一个java层Surface,然后初始化了应用程序窗口的各种属性:包括pid、标题、像素格式、宽、高、图形缓冲区属性标志等。

那么接着我们来看下Surface这个对象:

public class Surface implements Parcelable {
    private int mSurfaceControl;
    private Canvas mCanvas;
    private String mName;
    ......
    public Surface(SurfaceSession s,
            int pid, String name, int display, int w, int h, int format, int flags)
        throws OutOfResourcesException {
        ......
        mCanvas = new CompatibleCanvas();
        init(s,pid,name,display,w,h,format,flags);
        mName = name;
    }
    ......
    private native void init(SurfaceSession s,
            int pid, String name, int display, int w, int h, int format, int flags)
            throws OutOfResourcesException;
    ......
public void copyFrom(SurfaceControl other) {
   if (other == null) {
       throw new IllegalArgumentException("other must not be null");
   }
   long surfaceControlPtr = other.mNativeObject;
   if (surfaceControlPtr == 0) {
       throw new NullPointerException(
               "SurfaceControl native object is null. Are you using a released SurfaceControl?");
   }
   long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr);
   synchronized (mLock) {
       if (mNativeObject != 0) {
           nativeRelease(mNativeObject);
       }
       setNativeObjectLocked(newNativeObject);
   }
}

Surface类有三个成员变量mSurfaceControl、mCanvas和mName,它们的类型分别是int、Canvas和mName,其中,mSurfaceControl保存的是在C++层的一个SurfaceControl对象的地址值,mCanvas用来描述一块类型为CompatibleCanvas的画布,mName用来描述当前正在创建的一个绘图表面的名称。这里我们主要关注成员变量mSurfaceControl所关联的C++层的SurfaceControl对象是如何创建的。

Surface类的构造函数是通过调用另外一个成员函数init来创建与成员变量mSurfaceControl所关联的C++层的SurfaceControl对象的。Surface类的成员函数init是一个JNI方法,它是由C++层的函数Surface_init来实现的,如下所示:

static void Surface_init(JNIEnv*env, jobject clazz, jobject session, jint pid, jstring jname, jint dpy, jint w, jint h, jint format, jintflags) {
    //从 SurfaceSession 对象中取出之前创建的那个 SurfaceComposerClient 对象
    SurfaceComposerClient* client = (SurfaceComposerClient*)env->GetIntField(session, sso.client);
    sp<SurfaceControl> surface;//注意它的类型是 SurfaceControl
    if (jname == NULL) {
        //调用 SurfaceComposerClient 的 createSurface 函数,返回的 surface 是一个 SurfaceControl 类型,这个Surface是为WMS服务的。
        surface = client->createSurface(pid, dpy, w, h, format, flags);
    } else{
        ......
    }
   //把这个 surfaceControl 对象设置到 Java 层的 Surface 对象中,对应mSurfaceControl
   setSurfaceControl(env, clazz, surface);
}

很明显看出来,SurfaceComposerClient在这里执行了createSurface方法,要创建Surface. 但是经过上篇我们知道,SurfaceComposerClient最终会通过binder IPC 到Client 最终会在SurfaceFlinger中来执行createSurface:

sp<ISurface>SurfaceFlinger::createSurface(ClientID clientId, int pid, const String8& name, ISurfaceFlingerClient::surface_data_t* params, DisplayID d, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) {
    sp<LayerBaseClient> layer;//LayerBaseClient 是 Layer 家族的基类
    //这里又冒出一个 LayerBaseClient 的内部类,它也叫Surface
    sp<LayerBaseClient::Surface> surfaceHandle;
    Mutex::Autolock _l(mStateLock);
    //根据 clientId 找到 createConnection 时加入的那个 Client 对象
    sp<Client> client = mClientsMap.valueFor(clientId);
    ......
    //注意这个 id,它的值表示 Client 创建的是第几个显示层
    //同时也表示将使用 SharedBufferStatck 数组的第 id 个元素
    int32_t id = client->generateId(pid);
    //一个 Client 不能创建多于 NUM_LAYERS_MAX 个的Layer
    if(uint32_t(id) >= NUM_LAYERS_MAX) {
       return surfaceHandle;
    }
    //根据 flags 参数来创建不同类型的显示层
    switch(flags & eFXSurfaceMask) {
        case eFXSurfaceNormal:
           if (UNLIKELY(flags & ePushBuffers)) {
             //创建 PushBuffer 类型的显示层
            layer = createPushBuffersSurfaceLocked(client, d, id, w, h, flags);
            } else {
               //创建 Normal 类型的显示层
               layer = createNormalSurfaceLocked(client, d, id, w, h, flags, format);
           }
           break;
        case eFXSurfaceBlur:
            //创建 Blur 类型的显示层
           layer = createBlurSurfaceLocked(client, d, id, w, h, flags);
           break;
        case eFXSurfaceDim:
            //创建 Dim 类型的显示层
           layer = createDimSurfaceLocked(client, d, id, w, h, flags);
           break;
    }
    if(layer != 0) {
        layer->setName(name);
        setTransactionFlags(eTransactionNeeded);
        //从显示层对象中取出一个 ISurface 对象赋值给 SurfaceHandle
        surfaceHandle = layer->getSurface();
        if(surfaceHandle != 0) {
           params->token = surfaceHandle->getToken();
           params->identity = surfaceHandle->getIdentity();
           params->width = w;
           params->height = h;
           params->format = format;
        }
    }
    return surfaceHandle;//ISurface 的 Bn 端就是这个对象
}

在SurfaceFlinger::createSurface方法中,首先根据不同参数创建不同类型的显示层Layer,它是SurfaceFlinger中对Surface的描述,也是合成视图的基本单元。以createNormalSurfaceLocked为例:

sp<LayerBaseClient>SurfaceFlinger::createNormalSurfaceLocked(const sp<Client>& client, DisplayID display, int32_t id, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format) {
   //图像方面的参数设置
    switch(format) { 
    case PIXEL_FORMAT_TRANSPARENT:
    case PIXEL_FORMAT_TRANSLUCENT:
       format = PIXEL_FORMAT_RGBA_8888;
       break;
    case PIXEL_FORMAT_OPAQUE:
       format = PIXEL_FORMAT_RGB_565;
       break;
    }
    //创建一个 Layer 类型的对象,进去看构造方法,有一些初始工作
    sp<Layer> layer = new Layer(this, display,client, id);
    //设置 Buffer
    status_t err = layer->setBuffers(w, h, format, flags);
    if (LIKELY(err == NO_ERROR)) {
        //初始化这个新 layer 的一些状态
        layer->initStates(w, h, flags);
        //下面这个函数把这个 layer 加入到 Z 轴集合中
        addLayer_l(layer);
    }
......
    return layer;
}

Layer类的成员函数setBuffers就创建了一个SurfaceLayer(像素格式信息)对象,并且保存成员变量mSurface中。initStates初始化这个新 layer 的一些状态,addLayer_l把这个 layer 加入到 Z 轴集合中。

然后返回去看看:surfaceHandle = layer->getSurface();

//Layer
sp<LayerBaseClient::Surface> Layer::createSurface() const
{
    return mSurface;
}

前面我们已经知道了Layer类的成员变量mSurface 就是一个SurfaceLayer对象。这时候SurfaceFlinger服务就完成了Android应用程序所请求创建的Surface了,最后就会将用来描述这个Surface的一个SurfaceLayer对象的一个Binder代理对象返回Android应用程序,以便Android应用程序可以将它封装成一个SurfaceControl对象。

//Surface.cpp
Surface::Surface(const sp<SurfaceControl>& surface)
    : mBufferMapper(GraphicBufferMapper::get()),
      mClient(SurfaceClient::getInstance()),
      mSharedBufferClient(NULL),
      mInitCheck(NO_INIT),
      mSurface(surface->mSurface),
      mIdentity(surface->mIdentity),
      mFormat(surface->mFormat), mFlags(surface->mFlags),
      mWidth(surface->mWidth), mHeight(surface->mHeight)
{
    init();
}

Surface类的成员变量mClient指向了Android应用程序进程中的一个SurfaceClient单例。

Surface类的成员变量mSharedBufferClient指向了一个SharedBufferClient对象。

再看下init():

void Surface::init()
{
     //里面设置了一堆成员函数,重点关注dequeueBuffer和queueBuffer
    ANativeWindow::setSwapInterval  = setSwapInterval;
    ANativeWindow::dequeueBuffer    = dequeueBuffer;
    ANativeWindow::cancelBuffer     = cancelBuffer;
    ANativeWindow::lockBuffer       = lockBuffer;
    ANativeWindow::queueBuffer      = queueBuffer;
    ANativeWindow::query            = query;
    ANativeWindow::perform          = perform;
    ...
    if (mSurface != 0 && mClient.initCheck() == NO_ERROR) {
        int32_t token = mClient.getTokenForSurface(mSurface);
        if (token >= 0) {
             //new 了SharedBufferClient
            mSharedBufferClient = new SharedBufferClient(
                    mClient.getSharedClient(), token, 2, mIdentity);
            mInitCheck = mClient.getSharedClient()->validate(token);
        }
    }
}
看下getTokenForSurface
//UserClient.getTokenForSurface
ssize_t UserClient::getTokenForSurface(const sp<ISurface>& sur) const
{
    //token设置相关
    ...
            status_t err = layer->setToken(
                    const_cast<UserClient*>(this), ctrlblk, name);
    ...
    return name;
}

再看下setToken

status_t Layer::setToken(const sp<UserClient>& userClient,
        SharedClient* sharedClient, int32_t token)
{
    //这里new 了SharedBufferServer
    sp<SharedBufferServer> lcblk = new SharedBufferServer(
            sharedClient, token, mBufferManager.getDefaultBufferCount(),
            getIdentity());
    status_t err = mUserClientRef.setToken(userClient, lcblk, token);
    LOGE_IF(err != NO_ERROR,
            "ClientRef::setToken(%p, %p, %u) failed",
            userClient.get(), lcblk.get(), token);
    if (err == NO_ERROR) {
        // we need to free the buffers associated with this surface
    }
    return err;
}

createSurface一路叉下来分析了很深,总结下:当Android应用程序请求SurfaceFlinger服务创建一个Surface的时候,需要在SurfaceFlinger服务这一侧创建一个Layer对象、一个Layer::SurfaceLayer对象和一个SharedBufferServer对象,同时又需要在Android应用程序这一侧创建一个SurfaceControl对象、一个Surface对象和一个SharedBufferClient对象。这个SurfaceControl最终通过copyFrom返回给客户端。

至于SharedClient、SharedBufferClient、SharedBufferServer会在之后的app与SurfaceFlinger共享UI元数据过程中来分析。

总结:

  1. 每一个应用程序窗口都对应有两个Java层的Surface对象,其中一个是在WindowManagerService服务这一侧创建的,而另外一个是在应用程序进程这一侧创建的。在应用程序进程这一侧创建的ava层的Surface在C++层关联有一个Surface对象,用来绘制应用程序窗口的UI,在WindowManagerService服务这一侧创建的Java层的Surface对象在C++层关联有一个SurfaceControl对象,用来设置应用窗口的属性,例如,大小和位置等。为什么需要两个Surface,因为绘制应用程序窗口是独立的,由应用程序进程来完即可,而设置应用程序窗口的属性却需要全局考虑,即需要由WindowManagerService服务来统筹安排,两者必须结合考虑。

  2. 应用程序进程是UI绘制表面是通过两个Surface来描述,而在SurfaceFlinger服务内部使用的是一个Layer对象来描述。他们相互对应。

最后附上两张非常好的图,所谓一图胜千言可不是盖的:

Surface创建时序图:

Surface创建过程:

下一节总结下app与SurfaceFlinger共享UI元数据过程

参考:
https://blog.csdn.net/Luoshengyang/article/details/7884628
https://blog.csdn.net/freekiteyu/article/details/79483406

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

推荐阅读更多精彩内容