Android Surface创建

转载请标注来处: http://www.jianshu.com/p/64e5c866b4ae

一、 OverView

Android Surface的创建涉及三个进程

  1. App 进程
    Surface本质上是一个Native Window, 并且保存着需要在屏幕上显示的数据(buffer), 它通常包含 triple-buffers 以防止Jank。
    那么谁要创建Surface呢? 当然是App了,App需要将自己的内容显示在屏幕上,所以App负责发起Surface创建请求,创建好Surface后, 就可以直接可以在canvas上画图等,最终都会保存到Surface里的buffer里,最后由SurfaceFlinger合成并显示。

  2. System_Server进程
    主要是其中的WindowManagerService, 负责接收APP请求,向SurfaceFlinger发起具体的请求创建Surface, 且WMS需要创建Surface的辅助管理类,如SurfaceControl。
    为什么需要与system进程打交道呢?App直接通知SurfaceFlinger创建Surface不就行了?为什么还需要通过system进程呢?个人猜想可能是统一由WMS管理,以及当前系统中的窗口的Z -order计算, 减轻SurfaceFlinger的负担。

  3. SurfaceFlinger
    为App进程创建具体的Surface, 在SurfaceFlinger里对应成Layer, 然后负责管理、合成显示。

本文以这三个进程创建Surface过程来写。 先来一张 OverView 图

Surface overview

二、 与App进程相关的类

2.1 WMS中Session类的代理 IWindowSession

IWindowSession主要是App与WMS进行交互的类,它在ViewRootImpl中声明, 在ViewRootImpl构造函数中实例化, 如下代码

final IWindowSession mWindowSession;

public ViewRootImpl(Context context, Display display) {
    mWindowSession = WindowManagerGlobal.getWindowSession();
}

而mWindowSession具体又是通过 WindowManagerGlobal的静态函数 getWindowSession()获得

public static IWindowSession getWindowSession() {
    synchronized (WindowManagerGlobal.class) {
        if (sWindowSession == null) {
             ...
             IWindowManager windowManager = getWindowManagerService();
             sWindowSession = windowManager.openSession(...) //在WMS中打开一个Session 
             ...
        }
        return sWindowSession;
    }
}

由定义可知, sWindowSession声明为静态变量,可知在整个App的生命中,只有一个sWindowSession实例。
另外 App端的 sWindowSession拿到的是IWindowSession.Stub.Proxy即 WMS中Session的代理, 如 图P1所示。

2.2 Surface类

Surface是定义在ViewRootImpl中的成员,定义时并实例化了,如下

final Surface mSurface = new Surface();

由于 ViewRootImpl的个数与addView的调用次数相关,一个Activity可以多次调用addView, 也就是说一个Activity可以有多个Surface.

另外Surface被定义成final,也就是说mSurface不能重新再赋值了。

注意: 在ViewRootImpl中声明的Surface只是一个空壳,它并没有与真正的Surface映射起来,所以此时它是无效的Surface.

App进程通过 relayout 函数去创建真实Surface。

mWindowSession.relayout(..., mSurface);

三、System_Server进程中的Surface

system_server是一大块,而与Surface相关的操作主要由WMS完成的。

3.1 Session和SurfaceSession

3.1.1 Session类

由第二节可知, Session是通过openSession创建的

public IWindowSession openSession(...) {
    Session session = new Session(this, callback, client, inputContext);
    return session;
}

3.1.2 SurfaceSession类

SurfaceSession的创建是在WindowState生成后创建的, 如

win.attach()   //在WMS的addWindow()
void attach() { //WindowState类
    mSession.windowAddedLocked();
}
void windowAddedLocked() {  //在Session类中
    if (mSurfaceSession == null) {
        mSurfaceSession = new SurfaceSession();
        mService.mSessions.add(this);
    }
    mNumWindow++;
}

可以把Session类理解APP与WMS之间的已经连接好的会话层。WMS将所有的Session加入到 mSessions里。

Session和SurfaceSession可以参见图中的P2

3.1.3 SurfaceSession的native层

接着上面看SurfaceSession的构造函数,

private long mNativeClient; // SurfaceComposerClient的Jni对象指针
public SurfaceSession() {
    mNativeClient = nativeCreate();
}

调用nativeCreate在JNI中进行创建,具体是创建什么呢? 从mNativeClient的定义注释可以猜测应该是创建一个SurfaceComposerClient,并且将其JNI对象地址保存到mNativeClient中,

static jlong nativeCreate(JNIEnv* env, jclass clazz) {
    SurfaceComposerClient* client = new SurfaceComposerClient();
    ...
    return reinterpret_cast<jlong>(client);  //获得SurfaceComposerClient的地址
}

SurfaceComposerClient::SurfaceComposerClient()
    : mStatus(NO_INIT), mComposer(Composer::getInstance())  { }

SurfaceComposerClient的相关UML可以参考图中 P3所示。
另外SurfaceComposerClient继承RefBase,所以在初始化后会调用一次onFirstRef

void SurfaceComposerClient::onFirstRef() {
    sp<ISurfaceComposer> sm(ComposerService::getComposerService()); //获得SurfaceFlinger service
     sp<ISurfaceComposerClient> conn = sm->createConnection(); 
     //在SurfaceFlinger中创建Connection,也就是一个SurfaceFlinger的一个Client
}

createConnection会返回SurfaceFlingerClient类的Binder代理BpSurfaceComposerClient, 见P4所示。

注意: Session/SurfaceSession/SurfaceComposerClient 都是与APP相关的而非与某个Activity相关, 也就是它们相对于具体APP来说有且仅有一个实例。

3.2 SurfaceControl

当与APP相关的WMS(Session/SurfaceSession/BpSurfaceComposerClient),SurfaceFlinger(Client/BnSurfaceComposerClient 见第四节)相关类已经建立好后,此时就可以创建Surface了。

具体是在 ViewRootImpl的relayoutWindow(), 由performTraversals()调用

private void performTraversals() {
    ...
    boolean hadSurface = mSurface.isValid(); // 此时mSurface是空壳
    relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
    if (!hadSurface) {
        if (mSurface.isValid()) {  //mSurface有了正确的引用了
        ...
      }
    }
}

在relayoutWindow之前, mSurface仅是一个空壳,而在relayoutWindow之后, mSurface就已经创建好了,且有效。

private int relayoutWindow(...)
    int relayoutResult = mWindowSession.relayout(..., mSurface);
}

relayoutWindow “直接” 调用了WMS的relayoutWindow()

public int relayoutWindow(..., Surface outSurface) {
         //获得WindowState, 表示一个Window
    WindowState win = windowForClientLocked(session, client, false); 
    WindowStateAnimator winAnimator = win.mWinAnimator; 
        //创建SurfaceControl
    result = createSurfaceControl(outSurface, result, win, winAnimator); 
}

3.2.1 创建java侧的SurfaceControl

调用WindowStateAnimator的createSurfaceControl

private int createSurfaceControl(Surface outSurface, int result, WindowState win,
        WindowStateAnimator winAnimator) {
    WindowSurfaceController surfaceController = winAnimator.createSurfaceLocked();
    if (surfaceController != null) {
        surfaceController.getSurface(outSurface); 
    } 
    ...
    return result;
}

--- in WindowStateAnimator
WindowSurfaceController createSurfaceLocked() {
    mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession, ...);
    ...
    mSurfaceController.setPositionAndLayer(mTmpSize.left, mTmpSize.top, layerStack, mAnimLayer);
}

public WindowSurfaceController(SurfaceSession s, ...) {
  mSurfaceControl = new SurfaceControl(...)
}

它们之间建立的关系图参考P5所示,


3.2.2 创建Native的SurfaceControl

现在看下SurfaceControl的构造函数,

public SurfaceControl(SurfaceSession session,...){
    mNativeObject = nativeCreate(session, name, w, h, format, flags);
}

调用jni层的nativeCreate函数来创建native层的SurfaceControl

static jlong nativeCreate(...) {
    sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
    sp<SurfaceControl> surface = client->createSurface(String8(name.c_str()), w, h, format, flags);
    return reinterpret_cast<jlong>(surface.get());
}

代码中 client拿到的是 SurfaceComposerClient, 如P6所示,

sp<SurfaceControl> SurfaceComposerClient::createSurface(...)
{    
    sp<SurfaceControl> sur;
    if (mStatus == NO_ERROR) {
        sp<IBinder> handle;
        sp<IGraphicBufferProducer> gbp;
        status_t err = mClient->createSurface(name, w, h, format, flags, &handle, &gbp);
        if (err == NO_ERROR) {
            sur = new SurfaceControl(this, handle, gbp); //创建SurfaceControl
        }
    }
    return sur;
}

接着通过SurfaceComposerClient在SurfaceFlinger中创建Surface, 并且会返回SurfaceFlinger中的Handle以及IGraphicsBufferProducer的代理,如P7所示。

当SurfaceFlinger中创建好Surface后,在WMS的JNI层创建一个SurfaceControl, SurfaceControl顾名思义就是控制、操作Surface的类.

但是特别注意,这里的SurfaceControl实际上是WMS控制、操作Surface(比如Surface的Z order值,以及position, 透明度等的设置)的而非APP.

3.2.3 创建Native层的Surface

在Java端的SurfaceControl创建好后,就开始创建真正的Native的Surface。回忆一下之前说的App端的Surface只是一个空壳,因为它还没有与真正的Native端的Surface联系起来。在这一小节将会把App端的Surface与真正的Surface联系起来。

--- in WindowSurfaceController
WindowSurfaceController surfaceController = winAnimator.createSurfaceLocked();
if (surfaceController != null) {
    surfaceController.getSurface(outSurface);  //获得surface
}

void getSurface(Surface outSurface) {
    outSurface.copyFrom(mSurfaceControl);
}

这里的outSurface是哪个surface??, 从Session中的relayout定义来看

    public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int requestedWidth, int requestedHeight, int viewFlags,
            int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
            Rect outVisibleInsets, Rect outStableInsets, Rect outsets, Rect outBackdropFrame,
            Configuration outConfig, Surface outSurface) {

这个outSurface会是App端传过来的Surface么?之前我一直以为该Surface是App的Surface, 然而并不是

App调用relayout,实际上是IWindowSession的Proxy类中的relayout,代码如下

public int relayout(android.view.IWindow window, int seq, android.view.WindowManager.LayoutParams attrs,  ... , 
        android.view.Surface outSurface) throws android.os.RemoteException {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    int _result;
    try {
        ...
        mRemote.transact(Stub.TRANSACTION_relayout, _data, _reply, 0);
        _reply.readException();
        _result = _reply.readInt();
        ...
        if ((0 != _reply.readInt())) {
            outSurface.readFromParcel(_reply);
        }
    } finally {
        _reply.recycle();
        _data.recycle();
    }
    return _result;
}

从代码来看App端的outSurface并没有传到_data里,也就是并没有传递给Server端,相反,它是从_reply这个Parcel里读出来的。

现在来看下Server端的处理,在IWindowSession.Stub的onTransact里

case TRANSACTION_relayout: {
    ...
    android.view.Surface _arg15;
    _arg15 = new android.view.Surface();
    int _result = this.relayout(...);
    reply.writeNoException();
    reply.writeInt(_result);
    ...
    if ((_arg15 != null)) {
        reply.writeInt(1);
        _arg15.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
    } else {
        reply.writeInt(0);
    }
    return true;
}

_arg15这个参数就是Surface, 原来是在Server端(SystemServer进程中)生成的Surface, 也就是图1中那个临时在System_server创建的Surface. 最后将该临时生成的Surface写入到reply的Parcel中。


下面的函数就是将native的surface引用到system_serve临时产生的那个surface里

--- in Surface.java
public void copyFrom(SurfaceControl other) {
    long surfaceControlPtr = other.mNativeObject; //获得native surfacecontrol的地址
    long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr); //创建native surface
    synchronized (mLock) {
        setNativeObjectLocked(newNativeObject); //将native surface的地址保存到App端的Surface里
    }
}

通过将Native Surface的地址保存到SystemServer进程Java侧的临时Surface里

static jlong nativeCreateFromSurfaceControl(JNIEnv* env, jclass clazz,
        jlong surfaceControlNativeObj) {
    sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));
    sp<Surface> surface(ctrl->getSurface());   
    return reinterpret_cast<jlong>(surface.get());
}

sp<Surface> SurfaceControl::getSurface() const 
{
    if (mSurfaceData == 0) {
        mSurfaceData = new Surface(mGraphicBufferProducer, false); //创建Surface
    }   
    return mSurfaceData;
}

最后看下App端的Surface是怎么引用到正确的值的呢?
由上面可知App端的Surface通过是outSurface.readFromParcel(_reply);引用的

----- in Surface.java
public void readFromParcel(Parcel source) {
    synchronized (mLock) {
        mName = source.readString();
        setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
    }
}

static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz,
        jlong nativeObject, jobject parcelObj) {
    Parcel* parcel = parcelForJavaObject(env, parcelObj);

    android::view::Surface surfaceShim;

    // Calling code in Surface.java has already read the name of the Surface
    // from the Parcel
    surfaceShim.readFromParcel(parcel, /*nameAlreadyRead*/true);
    sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
    ...
    sp<Surface> sur;
    if (surfaceShim.graphicBufferProducer != nullptr) {
         //生成正确的Surface
        sur = new Surface(surfaceShim.graphicBufferProducer, true);
        sur->incStrong(&sRefBaseOwner);
    }
        
    return jlong(sur.get());
}

//获得 GraphicBufferProducer binder对象
status_t Surface::readFromParcel(const Parcel* parcel, bool nameAlreadyRead) { 
    sp<IBinder> binder;
    status_t res = parcel->readStrongBinder(&binder);
    graphicBufferProducer = interface_cast<IGraphicBufferProducer>(binder);
    return OK;
}

具体的类图参见 P8, P9

3.3 设置position与Layer

事实上这步发生在3.2.3之前

mSurfaceController.setPositionAndLayer(mTmpSize.left, mTmpSize.top, layerStack, mAnimLayer);
void setPositionAndLayer(float left, float top, int layerStack, int layer) {
    SurfaceControl.openTransaction();  
    try {
        mSurfaceX = left;
        mSurfaceY = top;
        try {
            mSurfaceControl.setPosition(left, top);
            mSurfaceControl.setLayerStack(layerStack);
            mSurfaceControl.setLayer(layer);
            mSurfaceControl.setAlpha(0);
            mSurfaceShown = false;
        } catch (RuntimeException e) {
        }
    } finally {
        SurfaceControl.closeTransaction();
    }
}

openTransaction与closeTransaction是成对出现的,本质上是为了一次性提交多个属性,而非一次一个一个的提交,这样performance会相对高些,另外frame也会相对稳定些(这个待续).

setPosition/setLayer这些函数调用流程如下

SurfaceControl(java) -> SurfaceControl(jni) -> SurfaceComposerClient -> Composer
以setPosition为例

bool Layer::setPosition(float x, float y, bool immediate) {
    if (mCurrentState.requested.transform.tx() == x && mCurrentState.requested.transform.ty() == y)
        return false;
    mCurrentState.sequence++;
    mCurrentState.requested.transform.set(x, y);
    if (immediate && !mFreezePositionUpdates) {
        mCurrentState.active.transform.set(x, y);
    }    
    mFreezePositionUpdates = mFreezePositionUpdates || !immediate;

    mCurrentState.modified = true;
    setTransactionFlags(eTransactionNeeded);
    return true;
}
}

getLayerStateLocked首先拿到ComposerState, 如果没有,则新创建一个,最后放到 mComposerStates track起来,最后把相关的属性存放到 CompserState中。最后通过SurfaceControl.closeTransaction();一并将ComposerState提交到SurfaceFlinger中对应的Layer类中的mCurrentState中, 并通过 Layer->setPosition将Surface的position设置到Layer中

注意: setPositionAndLayer通过setLayer将 Window的Z -order传递下去,这里是WindowStateAnimator的mAnimLayer,

四、SurfaceFlinger中的Surface

4.1 创建APP对应的Client

sp<ISurfaceComposerClient> SurfaceFlinger::createConnection()
{
    sp<ISurfaceComposerClient> bclient;
    sp<Client> client(new Client(this)); 
    ...
    return bclient;
}

Client继承BnSurfaceComposerClient, 与WMS中的BpSurfaceComposerClient相对应。

4.2 创建Surface

WMS通过SurfaceFlinger的Client来创建相应的Surface

Client通过MessageCreateLayer将创建Surface的请求放到队列中, 遵循先入先出的原则。 当Message被执行时,会调用SurfacefFlinger的createLayer()函数,咦,这里的 surface就变成了Layer??

status_t SurfaceFlinger::createLayer(...) {
    createNormalLayer(...); //其实有两种选择一个是Normal Layer, 另一种是Dim Layer
    addClientLayer(...)
}

创建Layer分两步,一步是创建Layer, 另一步是将Layer track起来

4.2.1 创建 Layer

status_t SurfaceFlinger::createNormalLayer(...)
{
    ...
    *outLayer = new Layer(this, client, name, w, h, flags);
    if (err == NO_ERROR) { 
        *handle = (*outLayer)->getHandle(); 
        *gbp = (*outLayer)->getProducer();
    }
    return err;
}

实例化Layer, 而由于Layer继承于RefBase, 在实例化后会调用一次 onFirstRef

void Layer::onFirstRef() {
    sp<IGraphicBufferProducer> producer;
    sp<IGraphicBufferConsumer> consumer;
    BufferQueue::createBufferQueue(&producer, &consumer);
    mProducer = new MonitoredProducer(producer, mFlinger);
    mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName);
}

在 onFirstRef里会为 Layer创建 BufferQueue模型 也就是典型的生产者/消费者模式,这个在后续讲。
具体可以参考 P11, P12, P13, P14

4.2.2 SurfaceFlinger Tracks Layer

status_t SurfaceFlinger::addClientLayer(...)
{
        if (mCurrentState.layersSortedByZ.size() >= MAX_LAYERS) {
            return NO_MEMORY;
        }
        mCurrentState.layersSortedByZ.add(lbc);
        mGraphicBufferProducerList.add(IInterface::asBinder(gbc));
    client->attachLayer(handle, lbc);
    return NO_ERROR;
}

具体可以参考P15, P16所示

五、小结

至此,整个Surface的UML图已经建立起来了。
但是仅仅是很生硬的把UML图画出来,是吧? 下面来小结一下,

5.1 APP/WMS/SurfaceFlinger通信流程创建

App启动Main Activity,

  1. 首先创建好与WMS通信的媒介Session,
  2. 然后通过Session将Window加入到WMS中,这时会触发 SurfaceSession的创建
  3. SurfaceSession的创建又会在WMS Native创建SurfaceComposerClient,
  4. 最终在SurfaceFlinger里创建与SurfaceComposerClient对应的Client
    至此 整个通信通道(APP(Session) -> WMS, WMS(SurfaceComposerClient) -> SurfaceFlinger(Client))已经建立起来了。

5.2 对Window进行布局(relayout)

Choreographer会接收 SurfaceFlinger 的Vsync信号, 参考Android SurfaceFlinger SW Vsync模型
然后执行 doFrame -> performTraverals()
接着通过 Session去请求WMS 对Window布局 (relayout)

relayout 主要是

  1. 创建 Jave/Native端的 SurfaceControl
  2. 通过 SurfaceComposerClient 通知 Client(SurfaceFlinger中)去创建 Layer, 并由SurfaceFlinger管理起来
  3. SurfaceControl创建好后就开始创建真正的 native的Surface
  4. App Surface通过relayout返回的parcel创建出App端的Surface

整体代码流程如下图所示

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

推荐阅读更多精彩内容