深刻Android系統(十二)Android圖形顯示系統-1-顯示原理與Surface

關於圖形顯示部分能夠參考官網:Graphicsjava

圖像顯示原理

Linux一般使用Framebuffer來用做顯示輸出(Framebuffer知識詳解在這裏),Framebuffer就是一塊內存區域,它一般是顯示驅動的內部緩衝區在內存中的映射。android

一旦用戶進程把圖像數據複製到Framebuffer中,顯示驅動會一個像素一個像素地掃描整個Framebuffer,並根據其中的值更新屏幕上像素點的顏色。api

驅動中這個更新屏幕的動做是固定的,它的週期就是咱們常說的刷新率數組

Android關於圖像渲染顯示的架構圖以下:
image緩存

結合這張圖,咱們須要重點關注的是:markdown

  • Native Framework中的Surfacesession

    • 不管開發者使用什麼渲染API,一切內容都會渲染到Surface
    • Surface中會關聯一個BufferQueue用於提供圖像數據緩存
    • 大多數客戶端使用OpenGL ESVulkan渲染到Surface
    • 有些客戶端使用Canvas渲染到Surface
  • Image Stream Producer的定義是可以生成圖形緩衝區以供消耗的任何對象。每一個Producer都會關聯一個Surface,例如數據結構

    • Canvas 2DJava層主要是經過View中建立的Surface對象來進行操做
      • Surface對象會與SurfaceFlinger進行關聯,並經過lockCanavas()接口獲取Canvas對象
      • lockCanvas()會將CPU渲染程序鏈接到BufferQueue的生產方,直到Surface被銷燬時纔會斷開鏈接
    • mediaserver視頻解碼器:經過MediaPlayersetSurfaceHolder()接口與SurfaceView中的Surface進行綁定
  • 對於Image Stream Consumer來講,主要是SurfaceFlinger,該系統服務會消耗當前可見的Surface,並使用WindowManager中提供的信息將它們合成到顯示部分。架構

    • SurfaceFlinger是能夠修改所顯示部份內容的惟一服務。SurfaceFlinger使用OpenGLHardware Composer 來合成一組Surface
    • 當應用進入前臺時,它會從WindowManager請求緩衝區。而後,WindowManager會從SurfaceFlinger請求layer
      • layersurface(包含BufferQueue)和SurfaceControl(包含屏幕框架等層元數據)的組合。
    • SurfaceFlinger建立layer並將其發送至WindowManager
    • 而後,WindowManagerSurface發送至應用,但會保留SurfaceControl來操控應用在屏幕上的外觀。
  • Window Positioning中的WindowManager主要是用來控制Window對象app

    • Window對象是用來存放View對象的容器,每一個Window對象都會關聯Surface對象
    • WindowManager監視Window對象的生命週期、輸入和焦點事件、屏幕方向、轉換、動畫、位置、變換、z順序等
    • 而後將全部Window元數據發送給SurfaceFlingerSurfaceFlinger利用這些元數據把本身管理的全部Surface組合成layer
    • 而後交給Hardware Composer作進一步處理
  • HAL層中的Hardware Composer(HWC)會根據當前硬件來進一步進行緩衝區的組合,它的具體實現依賴於特定的顯示設備

    • 官網關於HWC的數據流以下:

    image

    • SurfaceFlinger做爲clientHWC提供一個完整的layer列表,而後詢問HWC計劃如何處理
    • HWC會將這些layer標記爲client合成或者device合成並告知SurfaceFlinger
    • SurfaceFlinger將處理標記爲client合成layer,而後經過BufferQueue傳遞給HWC
    • 餘下的layerHWC自行處理

網上一篇頗有趣的渲染總結(文中有些錯誤,但瑕不掩瑜):Android渲染原理

VSYNC信號

前面提到Linux使用Framebuffer來用做顯示輸出。可是,若是在屏幕更新到一半時,用戶進程更新了Framebuffer中的數據,將致使屏幕上畫面的上半部分是前一幀的畫面,下半部分變成了新的畫面。固然這種異常會在下次刷新時糾正過來,可是在用戶感知上畫面會出現閃爍感

  • 針對這種狀況,早期的解決方法是使用雙緩衝機制,雙緩衝就是提供兩塊Framebuffer,一塊用於顯示,另外一塊用於數據更新,數據準備好後,經過ioctl操做告訴顯示設備切換用於顯示的Framebuffer,這樣圖像就能快速的顯示出來了
  • 可是雙緩衝並無徹底解決問題,雖然雙緩衝切換的速度很快,可是若是切換的時間點不對,在畫面更新一半的時候進行切換,仍是會出現單緩衝區遇到的閃爍問題
  • 固然,能夠在底層進行控制,當收到切換請求後內部並不立刻執行,而是等到刷新完成後再切換,這樣能夠徹底避免畫面重疊的問題
  • 可是,這樣作會帶來新的問題,若是ioctl操做完成後緩衝區沒有切換,應用就不能肯定什麼時候能夠再使用緩存區,只能經過ioctl不停地查詢緩衝區狀態,直到切換完成。這種CPU主動查詢的方式很低效

爲此Android讓底層固定地發送信號給用戶進程,通知進程切換的時機,這樣就避免了用戶進程主動查詢的操做。而這個信號就是VSYNC信號

官方傳送門:VSYNC

官方描述以下:VSYNC信號用來同步整個顯示流程(Display Pipeline)顯示流程包括app渲染、SurfaceFlinger合成、HWC(硬件渲染)組成

(這部分感受原文更容易理解)VSYNC synchronizes the time apps wake up to start rendering, the time SurfaceFlinger wakes up to composite the screen, and the display refresh cycle.

VSYNC信號應該由顯示驅動產生,這樣才能達到最佳效果。可是Android爲了能運行在不支持VSYNC機制的設備上,也提供了用軟件來模擬產生VSYNC信號的手段

官網描述:經過HWC來產生VSYNC信號,並經過接口回調將事件進行發送(主要是SurfaceFlinger進行事件接收)

基礎知識鋪墊完成,咱們先來看看Surface

Surface

官網對Surface的描述是:A surface is an interface for a producer to exchange buffers with a consumer.

上面描述的是一種生產者-消費者的模式,而Surface充當了中間銜接的角色。

ActivityUI顯示爲例:

  • 生產者的任務就是把圖形繪製在Surface對象上

    • 比較出名的生產者就是SurfaceView組件了
  • SurfaceFlinger做爲消費者會把全部Surface對應的圖像層混合在一塊兒

  • 最後消費者將其輸出到FrameBuffer中,這樣在屏幕上就看到最後合成的圖像了

下面咱們從Java層開始分析Surface

應用中Surface的建立過程

應用開發中不多直接使用Surface,由於每一個Activity中都已經建立好了各自的Surface對象,一般只有一些特殊的應用才須要在Activity以外再去建立Surface,例如相機、視頻播放應用。

不過,一般這些應用也是經過建立SurfaceView來使用Surface

須要注意的是,在應用中不能直接去建立一個可用的Surface對象(也能夠說直接建立出的對象沒什麼實際用途),由於這樣建立出的Surface對象和SurfaceFlinger之間沒有任何關聯。

該如何創見一個可用的Surface對象呢?
咱們看下Surface類的定義:

public class Surface implements Parcelable {
    long mNativeObject;
    // 一個無參構造,空實現
    public Surface() {
    }
    public Surface(SurfaceTexture surfaceTexture) {
        if (surfaceTexture == null) {
            throw new IllegalArgumentException("surfaceTexture must not be null");
        }
        mIsSingleBuffered = surfaceTexture.isSingleBuffered();
        synchronized (mLock) {
            mName = surfaceTexture.toString();
            setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
        }
    }
}
複製代碼

Surface類對外有兩個構造方法:

  • 一個是無參構造,實現也是空的

    • 註釋中說這個主要是給readFromParcel()反序列化用的
    • 那咱們看下readFromParcel()方法
    public void readFromParcel(Parcel source) {
        if (source == null) {
            throw new IllegalArgumentException("source must not be null");
        }
        synchronized (mLock) {
            mName = source.readString();
            mIsSingleBuffered = source.readInt() != 0;
            setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
        }
    }
    複製代碼
  • 另外一個須要傳遞SurfaceTexture對象做爲參數

    • 這就複雜了,還要準備一個SurfaceTexture對象

聰明的咱們會發現,readFromParcel()new Surface(SurfaceTexture surfaceTexture)都會執行一個setNativeObjectLocked()方法,咱們看下方法實現:

private void setNativeObjectLocked(long ptr) {
        if (mNativeObject != ptr) {
            ...
            mNativeObject = ptr;
            ...
        }
    }
複製代碼

setNativeObjectLocked()方法很簡單,只是更新了mNativeObject變量的數值,重點就是參數了:

  • setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
  • setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));

這兩個setNativeObjectLocked()方法的調用從參數的命名來看是針對不一樣數據來源的處理。

看來要看下native的實現了,以nativeReadFromParcel()爲例來看下:

static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz, jlong nativeObject, jobject parcelObj) {
    Parcel* parcel = parcelForJavaObject(env, parcelObj);
    ...
    android::view::Surface surfaceShim;
    // 解析 Parcel 數據,並填充到 native層 的 Surface對象 surfaceShim
    surfaceShim.readFromParcel(parcel, /*nameAlreadyRead*/true);
    // 將傳入的指針轉換爲 native層 的 Surface對象 self
    sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
    // 比對 surfaceShim 和 self 中的 Binder 對象 IGraphicBufferProducer
    if (self != nullptr
            && (IInterface::asBinder(self->getIGraphicBufferProducer()) ==
                    IInterface::asBinder(surfaceShim.graphicBufferProducer))) {
        // 判斷是同一個 IGraphicBufferProducer ,直接返回當前指針
        return jlong(self.get());
    }
    sp<Surface> sur;
    if (surfaceShim.graphicBufferProducer != nullptr) {
        // IGraphicBufferProducer 不一樣
        // 且 surfaceShim 的 IGraphicBufferProducer 不爲空
        // 建立一個新的 Surface 對象 sur
        sur = new Surface(surfaceShim.graphicBufferProducer, true);
        sur->incStrong(&sRefBaseOwner);
    }
    ...
    // 將 sur 的指針返回給 Java 層
    return jlong(sur.get());
}
複製代碼

到這裏咱們不難看出

  • Java層Surface對象最重要的數據是mNativeObject變量
    • mNativeObject是一個指針,指向的native層的Surface對象
  • native層在判斷是否新建Surface對象的邏輯依賴的是IGraphicBufferProducer對象
    • IGraphicBufferProducer對象是一個Binder引用對象

那麼接下來咱們重點就是這個IGraphicBufferProducer了。

咱們先看下native層Surface類的繼承關係:

class Surface : public ANativeObjectBase<ANativeWindow, Surface, RefBase>
複製代碼

ANativeObjectBase的定義以下:

template <typename NATIVE_TYPE, typename TYPE, typename REF,
        typename NATIVE_BASE = android_native_base_t>
class ANativeObjectBase : public NATIVE_TYPE, public REF
{...}
複製代碼

整理成繼承關係圖就是:
image

再看下Surface的構造方法:

Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp)
      : mGraphicBufferProducer(bufferProducer),
        mCrop(Rect::EMPTY_RECT),
        mBufferAge(0),
        ...
        mFrameEventHistory(std::make_unique<ProducerFrameEventHistory>()) {
        ... // 初始化各類成員變量
}
複製代碼

從構造函數的參數能夠看到,native層SurfaceIGraphicBufferProducer對象保存到了mGraphicBufferProducer變量中。

暫時仍是不清楚mGraphicBufferProducer哪裏來的,咱們去WMS中看看

WMSSurface的建立過程

此處要從ActivityonResume()生命週期提及

onResume()WMS.relayoutWindow()

咱們已經知道,當AMS觸發onResume()生命週期時會調用到ActivityThread類的handleResumeActivity()方法,代碼以下:

public void handleResumeActivity(...) {
        ...
        // 此處會觸發 onResume 聲明週期回調
        final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
        ...
        ViewManager wm = a.getWindowManager();
        ...// 省略不少 Window 處理邏輯
        wm.addView(decor, l);
        ...
    }
複製代碼

從方法中能夠看到,執行完onResume()後調用了ViewManageraddView(decor, l)方法

知識點:onResume方法調用後才真正進行View的添加

ViewManager是一個接口類,真正的實現類是WindowManagerImpladdView()方法實現也很簡單:

public void addView(...) {
        applyDefaultToken(params);
        mGlobal.addView(...);
    }
複製代碼

調用了mGlobaladdView()方法方法,mGlobal的類型是WindowManagerGlobal,代碼以下:

public void addView(...) {
        ...
        ViewRootImpl root;
        synchronized (mLock) {
            ...
            root = new ViewRootImpl(view.getContext(), display);
            view.setLayoutParams(wparams);
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
            try {
                root.setView(view, wparams, panelParentView);
            }
            ...
        }
    }
複製代碼

WindowManagerGlobal類的addView()先是建立了一個新的ViewRootImpl對象,而後調用了ViewRootImpl對象的setView()方法。

ViewRootImpl類中setView()調用流程以下:

class ViewRootImpl{
    /** * 這裏也是直接 new 出來的對象 Surface * 前面已經介紹過,這個對象須要和 native層進行綁定後才能正常使用 */
    public final Surface mSurface = new Surface();
    ViewRootImpl(Context context, Display display){
        ...
        // 此方法會建立 Session 對象
        mWindowSession = WindowManagerGlobal.getWindowSession();
        ...
    }
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                mView = view;
                ...
                // 內部方法調用
                requestLayout();
                ...
                // 此方法會建立 SurfaceSession
                res = mWindowSession.addToDisplay(...);
                ...
            }
        }
    }
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            ...
            scheduleTraversals();
        }
    }
    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            ...
            // 異步執行 mTraversalRunnable
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            ...
        }
    }
    final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }
    void doTraversal() {
        if (mTraversalScheduled) {
            ...
            performTraversals();
            ...
        }
    }
    private void performTraversals() {
        ...
        relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
        ...
    }
    private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility, boolean insetsPending) throws RemoteException {
        ...
        // 調用 mWindowSession 的 relayout 方法,並將 mSurface 對象傳遞過去
        int relayoutResult = mWindowSession.relayout(..., mSurface);
        ...
        return relayoutResult;
    }
}
複製代碼

setView()方法最後調用的是mWindowSessionrelayout()方法。

mWindowSession類型是IWindowSession,是一個Binder引用對象。真正的Binder服務實現是com.android.server.wm.Session類:

class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
    public Session(WindowManagerService service, ...) {
        mService = service;
        ...
    }
    public int relayout(..., Surface outSurface) {
        ...
        int res = mService.relayoutWindow(..., outSurface);
        ...
        return res;
    }
}
複製代碼

終於走到了WMS中,調用的是WMSrelayoutWindow()方法

WMS.relayoutWindow()SurfaceControl.nativeCreate()

Surface相關的調用關係以下:

class WindowManagerService{
    public int relayoutWindow(..., Surface outSurface) {
        ...
        result = createSurfaceControl(outSurface, ...);
        ...
        return result;
    }
    private int createSurfaceControl(Surface outSurface, ...) {
        ...
        WindowSurfaceController surfaceController;
        ...
        surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type, win.mOwnerUid);
        ...
        if (surfaceController != null) {
            surfaceController.getSurface(outSurface);
        } else {
            ...
            outSurface.release();
        }
        return result;
    }
}
class WindowSurfaceController{
    public WindowSurfaceController(...) {
        ...
        final SurfaceControl.Builder b = win.makeSurface()
                ...
                .setMetadata(windowType, ownerUid);
        mSurfaceControl = b.build();
    }
    void getSurface(Surface outSurface) {
        outSurface.copyFrom(mSurfaceControl);
    }
}
class Surface{
    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(
                    "null SurfaceControl native object. Are you using a released SurfaceControl?");
        }
        long newNativeObject = nativeGetFromSurfaceControl(surfaceControlPtr);
        synchronized (mLock) {
            if (mNativeObject != 0) {
                nativeRelease(mNativeObject);
            }
            setNativeObjectLocked(newNativeObject);
        }
    }
}
複製代碼

在上面的relayoutWindow()方法中

  • WMS先經過winAnimatorcreateSurfaceLocked()方法獲得了一個WindowSurfaceController對象
    • WindowSurfaceController對象封裝了SurfaceControl對象
  • 而後WMS調用WindowSurfaceController對象的getSurface()方法來對Surface對象進行填充
    • getSurface()對象只是利用自身保存的mSurfaceControl對象
    • 經過SurfacecopyFrom()方法對Surface對象進行填充處理
  • copyFrom()方法
    • 調用nativeGetFromSurfaceControl()方法獲得一個native層的Surface對象指針
    • 而後經過setNativeObjectLocked()方法將指針保存到成員變量mNativeObject

關鍵點又回到了native層的nativeGetFromSurfaceControl()方法,它的代碼以下:

static jlong nativeGetFromSurfaceControl(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());
}
複製代碼

nativeGetFromSurfaceControl()方法是經過native層的SurfaceControlgetSurface()方法來獲取Surface對象。咱們再看下getSurface()方法:

sp<Surface> SurfaceControl::getSurface() const {
    Mutex::Autolock _l(mLock);
    if (mSurfaceData == 0) {
        return generateSurfaceLocked();
    }
    return mSurfaceData;
}
sp<Surface> SurfaceControl::generateSurfaceLocked() const {
    mSurfaceData = new Surface(mGraphicBufferProducer, false);
    return mSurfaceData;
}
複製代碼

SurfaceControlgetSurface()方法中

  • mSurfaceData指針爲空時纔會經過generateSurfaceLocked()方法建立一個新的Surface對象
    • Surface對象中很關鍵的IGraphicBufferProducer在這裏傳入的是SurfaceControl的成員變量mGraphicBufferProducer
  • 不然直接返回mSurfaceData指針

getSurface()方法的邏輯中咱們不難看出,SurfaceControl對象和Surface對象是關聯在一塊兒的,一對一的關係

更關鍵的是構造Surface對象的核心參數居然是SurfaceControl中的成員變量。。。。。。。。

沒辦法,要先搞定SurfaceControl的建立過程才能夠

前面已經講過,WMS經過winAnimator.createSurfaceLocked()方法建立了WindowSurfaceController對象,WindowSurfaceController對象初始化時就會建立SurfaceControl,咱們看下建立過程:

class WindowStateAnimator{
    WindowSurfaceController createSurfaceLocked(int windowType, int ownerUid) {
        ...
        // mSession 的類型就是前面提到的 Session 類,IWindowSession Binder服務類
        mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession, ...);
        ...
        return mSurfaceController;
    }
}
class WindowSurfaceController{
    public WindowSurfaceController(SurfaceSession s, ...) {
        ...
        final SurfaceControl.Builder b = win.makeSurface()
                ...
                .setMetadata(windowType, ownerUid);
        // 經過 Builder 模式建立的
        mSurfaceControl = b.build();
    }
}
class SurfaceControl{
    public static class Builder {
        ...
        public SurfaceControl build() {
            ...
            // 調用私有構造方法
            return new SurfaceControl(mSession, ...);
        }
        ...
    }
    private SurfaceControl(SurfaceSession session, ...) throws OutOfResourcesException, IllegalArgumentException {
        ...
        mNativeObject = nativeCreate(session, ...);
        if (mNativeObject == 0) {
            throw new OutOfResourcesException(
                    "Couldn't allocate SurfaceControl native object");
        }
        ...
    }
}
複製代碼

能夠看到

  • 建立SurfaceControl對象的全程都攜帶着一個SurfaceSession對象。
  • 同時這個SurfaceSession對象在SurfaceControl的構造方法中經過nativeCreate()傳遞到了native層,用來建立native層的對象
  • Java層Surface對象同樣,SurfaceControl對象也會將native層對象的指針保存到mNativeObject

關鍵仍是在nativeCreate()方法,咱們繼續。。

nativeCreate()方法以下:

static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj, ...) {
    ScopedUtfChars name(env, nameStr);
    sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
    ...
    sp<SurfaceControl> surface;
    status_t err = client->createSurfaceChecked(
            String8(name.c_str()), w, h, format, &surface, flags, parent, windowType, ownerUid);
    ...
    return reinterpret_cast<jlong>(surface.get());
}
複製代碼

nativeCreate()方法中又出現了一個新的類型SurfaceComposerClient,並且native層SurfaceControl對象就是經過它的createSurfaceChecked()來建立的

耐心、耐心、耐心。。。。 崩潰的時候多說幾回

上面方法中的SurfaceComposerClient對象是經過android_view_SurfaceSession_getClient()方法獲得的,看JNI的命名格式能夠推算它和SurfaceSession類也有關係,內容以下:

sp<SurfaceComposerClient> android_view_SurfaceSession_getClient( JNIEnv* env, jobject surfaceSessionObj) {
    return reinterpret_cast<SurfaceComposerClient*>(
            env->GetLongField(surfaceSessionObj, gSurfaceSessionClassInfo.mNativeClient));
}
複製代碼

android_view_SurfaceSession_getClient()方法中的參數surfaceSessionObj是在Java層調用nativeCreate()方法時傳遞的參數,類型是SurfaceSession

這裏其實是將SurfaceSession對象中成員變量mNativeClient的值取出來後,轉換爲SurfaceComposerClient對象返回

這說明SurfaceComposerClient對象和SurfaceSession對象也是一塊兒建立出來的,咱們繼續看下SurfaceSessionSurfaceComposerClient的建立過程

SurfaceControl.nativeCreateComposerService

須要知道的一個重要前提:每一個用戶進程在WMS中都有且只有一個對應的Session對象,前面已經介紹Session是一個實現了IWindowSession接口的Binder服務類

Session的成員變量mSurfaceSession是在Session對象初始化時建立的,那麼Session對象在何時建立的呢?
跟蹤代碼發現流程以下:

  • ViewRootImpl初始化時會調用WindowManagerGlobal.getWindowSession()方法
  • WindowManagerGlobal.getWindowSession()會調用WMSopenSession()方法
  • openSession()方法中便會在WMS中建立一個新的Session對象

對於SurfaceSession的初始化,是在Session對象的windowAddedLocked()方法中,那麼windowAddedLocked()方法又是在哪裏調用的呢?
一樣,咱們跟蹤下方法調用:

  • ViewRootImplsetView()方法中會調用mWindowSession.addToDisplay(...)方法
  • mWindowSession.addToDisplay(...)方法會調用WMSaddWindow()方法
  • WMSaddWindow()方法會調用WindowStateattach()方法
  • attach()方法會調用SessionwindowAddedLocked()方法

這樣就串起來了,如今咱們能夠繼續學習SurfaceSession的構造方法了:

/** Create a new connection with the surface flinger. */
    public SurfaceSession() {
        mNativeClient = nativeCreate();
    }
複製代碼

很簡潔,源碼註釋也很關鍵。咱們看下SurfaceSessionnativeCreate()方法:

static jlong nativeCreate(JNIEnv* env, jclass clazz) {
    SurfaceComposerClient* client = new SurfaceComposerClient();
    // 請注意此方法的調用
    // 該方法會觸發 onFirstRef() 的執行
    client->incStrong((void*)nativeCreate);
    return reinterpret_cast<jlong>(client);
}
複製代碼

nativeCreate()直接建立了一個SurfaceComposerClient對象,也沒有參數。不過SurfaceComposerClient類是從RefBase類派生出來的,咱們看下它的構造函數和onFirstRef函數:

SurfaceComposerClient::SurfaceComposerClient()
    : mStatus(NO_INIT)
{
}
// onFirstRef() 是 RefBase 提供的回調接口
// 當首次調用 incStrong() 方法時便會執行此方法
void SurfaceComposerClient::onFirstRef() {
    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
    if (sf != 0 && mStatus == NO_INIT) {
        // 此處 rootProducer 應該爲 null
        auto rootProducer = mParent.promote();
        sp<ISurfaceComposerClient> conn;
        // 因此在此處執行的是 sf->createConnection() 方法
        conn = (rootProducer != nullptr) ? sf->createScopedConnection(rootProducer) :
                sf->createConnection();
        if (conn != 0) {
            mClient = conn;
            mStatus = NO_ERROR;
        }
    }
}
複製代碼

構造方法很簡單,只是將mStatus設置爲NO_INIT

重點是在onFirstRef()方法中

  • 先調用了ComposerServicegetComposerService()方法來獲得一個ISurfaceComposer的指針
  • 而後調用它的createConnection()方法建立一個ISurfaceComposerClient對象
  • 而後將mClient指向這個ISurfaceComposerClient對象

咳咳咳,按照上面的調用流程咱們尚未找到關於IGraphicBufferProducer的信息,如今又多出來了一個ISurfaceComposerClient。。。

好吧好吧,梳理下這部分關係先

WMSSurface關係總結

上面介紹的WMS中涉及和Surface有關的類關係以下: image

看上去就挺複雜的:

  • SurfaceControlSurface是成對建立的,考慮到繪製等需求,它們的數量會比較多
  • SessionSurfaceSessionSurfaceComposerClient對象是和鏈接WMS的用戶進程的數量相同
  • SurfaceComposerClient的做用是建立Surface
  • SurfaceControl經過SurfaceComposerClient來獲取Surface
  • SurfaceComposerClientComposerService的具體實現類

ComposerService再到SurfaceFlinger

ComposerService是一個單例模式的普通類,定義以下:

class ComposerService : public Singleton<ComposerService>
{
    sp<ISurfaceComposer> mComposerService;
    sp<IBinder::DeathRecipient> mDeathObserver;
    Mutex mLock;

    ComposerService();
    void connectLocked();
    void composerServiceDied();
    friend class Singleton<ComposerService>;
public:
    static sp<ISurfaceComposer> getComposerService();
};
複製代碼

前面的onFirstRef()方法中調用了ComposerService類的靜態方法getComposerService(),咱們看下它的實現:

/*static*/ sp<ISurfaceComposer> ComposerService::getComposerService() {
    ComposerService& instance = ComposerService::getInstance();
    Mutex::Autolock _l(instance.mLock);
    if (instance.mComposerService == NULL) {
        ComposerService::getInstance().connectLocked();
        ...
    }
    return instance.mComposerService;
}
複製代碼

getComposerService()經過調用父類SingletongetInstance()方法來取得實例對象,而後調用ComposerServiceconnectLocked()方法:

void ComposerService::connectLocked() {
    const String16 name("SurfaceFlinger");
    while (getService(name, &mComposerService) != NO_ERROR) {
        usleep(250000);
    }
    ...
}
複製代碼

connectLocked()方法中鏈接了SurfaceFlinger服務對象,而後把對象指針保存到mComposerService中。

ComposerService其實只是SurfaceFlinger的代理,它把SurfaceFlinger服務接口包裝了起來

getComposerService()返回的就是mComposerService對象指針,也就是SurfaceFlingerBinder對象。

前面提到,SurfaceComposerClient對象的onFirstRef()方法中

  • 在經過ComposerService::getComposerService()得到了mComposerService指針後
  • 調用了mComposerService對象的createConnection()方法。
  • 按照剛纔的邏輯,其實調用是SurfaceFlinger服務的相關函數接口。

SurfaceFlinger中接口實現以下:

sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() {
    return initClient(new Client(this));
}
static sp<ISurfaceComposerClient> initClient(const sp<Client>& client) {
    status_t err = client->initCheck();
    if (err == NO_ERROR) {
        return client;
    }
    return nullptr;
}
複製代碼

createConnection()函數中建立了一個Client類型對象,而後將其返回給調用者,關於Client類的定義以下:

class Client : public BnSurfaceComposerClient
複製代碼

Client是一個Binder服務類,雖然叫Client。而mComposerService保存的也就是這個服務對象的指針

咱們再回到SurfaceControl的建立過程

  • nativeCreate()方法中調用了SurfaceComposerClientcreateSurfaceChecked()方法
status_t SurfaceComposerClient::createSurfaceChecked(...) {
    sp<SurfaceControl> sur;
    status_t err = mStatus;
    if (mStatus == NO_ERROR) {
        sp<IBinder> handle;
        sp<IBinder> parentHandle;
        sp<IGraphicBufferProducer> gbp;

        if (parent != nullptr) {
            parentHandle = parent->getHandle();
        }
        err = mClient->createSurface(name, w, h, format, flags, parentHandle,
                windowType, ownerUid, &handle, &gbp);
        ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
        if (err == NO_ERROR) {
            *outSurface = new SurfaceControl(this, handle, gbp, true /* owned */);
        }
    }
    return err;
}
複製代碼

createSurfaceChecked()方法

  • 先是調用了SurfaceFlinger::Client對象的createSurface()方法去進行建立操做
    • 請留意傳遞的參數,handlegbpparentHandle都是Binder對象
      • sp<IGraphicBufferProducer> gbp就是咱們找尋已久的參數。。。。
      • 這些參數都會在SurfaceFlinger中進行設置
  • 最後確認SurfaceFlinger::Client對象的createSurface()執行完成沒有錯誤,建立SurfaceControl對象

SurfaceFlinger中建立Surface

SurfaceFlinger::Client對象的createSurface()方法以下:

status_t Client::createSurface(..., sp<IGraphicBufferProducer>* gbp) {
    ...
    return mFlinger->createLayer(..., gbp, &parent);
}
複製代碼

調用的是SurfaceFlingercreateLayer()方法,代碼以下:

status_t SurfaceFlinger::createLayer(..., sp<IGraphicBufferProducer>* gbp, sp<Layer>* parent) {
    ...
    status_t result = NO_ERROR;
    sp<Layer> layer;
    String8 uniqueName = getUniqueLayerName(name);
    // 這裏分紅了兩種建立模式:Normal 和 Color
    switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
        case ISurfaceComposerClient::eFXSurfaceNormal: // normal
            result = createBufferLayer(client,
                    uniqueName, w, h, flags, format,
                    handle, gbp, &layer);
            break;
        case ISurfaceComposerClient::eFXSurfaceColor: // color
            result = createColorLayer(client,
                    uniqueName, w, h, flags,
                    handle, &layer);
            break;
        default:
            result = BAD_VALUE;
            break;
    }
    ...
    return result;
}
複製代碼

createLayer()方法按照兩種模式進行建立

  • 一種是eFXSurfaceNormal模式,經過createBufferLayer()方法建立,方法以下:

    status_t SurfaceFlinger::createBufferLayer(..., sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer) {
        // initialize the surfaces
        switch (format) {
        case PIXEL_FORMAT_TRANSPARENT:
        case PIXEL_FORMAT_TRANSLUCENT:
            // 透明或半透明設置格式爲 RGBA
            format = PIXEL_FORMAT_RGBA_8888;
            break;
        case PIXEL_FORMAT_OPAQUE:
            // 不透明設置格式爲 RGBX
            format = PIXEL_FORMAT_RGBX_8888;
            break;
        }
        sp<BufferLayer> layer = new BufferLayer(this, client, name, w, h, flags);
        status_t err = layer->setBuffers(w, h, format, flags);
        if (err == NO_ERROR) {
            *handle = layer->getHandle();
            // 咱們關注的 IGraphicBufferProducer 在這裏賦值了
            *gbp = layer->getProducer();
            *outLayer = layer;
        }
        return err;
    }
    複製代碼
    • 方法中先是肯定相應的像素格式,而後建立新的BufferLayer對象,調用對象的setBuffers()設置寬高和像素格式
    • Surface中重要的gdp等參數也會在這裏進行設置
  • 一種是eFXSurfaceColor模式,經過createColorLayer()方法建立:看參數傳入和gdp沒啥關係,不用太過關注

    status_t SurfaceFlinger::createColorLayer(...,
            sp<IBinder>* handle, sp<Layer>* outLayer)
    {
        *outLayer = new ColorLayer(this, client, name, w, h, flags);
        *handle = (*outLayer)->getHandle();
        return NO_ERROR;
    }
    複製代碼
    • 方法比較簡單只是建立了一個ColorLayer對象,也沒有setBuffers()等操做

咱們重點關注eFXSurfaceNormal模式的建立邏輯

終於,咱們找到了sp<IGraphicBufferProducer>* gbp的來源,是經過layer->getProducer()方法

layer->getProducer()方法以下:

sp<IGraphicBufferProducer> BufferLayer::getProducer() const {
    return mProducer;
}
複製代碼

layer->getProducer()方法比較簡單,只是返回了一個mProducer對象的指針

mProducer對象的建立是在BufferLayer::onFirstRef()方法中

void BufferLayer::onFirstRef() {
    Layer::onFirstRef();
    // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
    sp<IGraphicBufferProducer> producer;
    sp<IGraphicBufferConsumer> consumer;
    // 經過 BufferQueue 的 createBufferQueue 方法建立 producer 和 consumer
    BufferQueue::createBufferQueue(&producer, &consumer, true);
    // 建立 mProducer
    mProducer = new MonitoredProducer(producer, mFlinger, this);
    ...
}
複製代碼

onFirstRef()方法中

  • 經過BufferQueue::createBufferQueue()方法建立producerconsumer
    void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer, sp<IGraphicBufferConsumer>* outConsumer, bool consumerIsSurfaceFlinger) {
        sp<BufferQueueCore> core(new BufferQueueCore());
        sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core, consumerIsSurfaceFlinger));
        sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
    
        *outProducer = producer;
        *outConsumer = consumer;
    }
    複製代碼
  • 利用建立好的producer對象建立MonitoredProducer對象

MonitoredProducer頭文件定義以下:

class MonitoredProducer : public BnGraphicBufferProducer {
public:
    MonitoredProducer(const sp<IGraphicBufferProducer>& producer,
            const sp<SurfaceFlinger>& flinger,
            const wp<Layer>& layer);
    virtual ~MonitoredProducer();
    ...
private:
    // 在 BufferLayer 的 onFirstRef() 中經過 BufferQueue::createBufferQueue() 建立
    sp<IGraphicBufferProducer> mProducer;
    sp<SurfaceFlinger> mFlinger;
    wp<Layer> mLayer;
}
複製代碼

雖然MonitoredProducer是一個Binder實體對象,但從業務上來說它僅僅是個代理

真正管理圖像緩衝區的是經過BufferQueue::createBufferQueue()方法建立的BufferQueueProducer producer對象

終於接近IGraphicBufferProducer的本質了,到這裏咱們其實能夠結束WMSSurface的建立流程了。先回顧下整個建立流程:
image 上圖分了三部分

  • 綠色部分:SurfaceSession的初始化
  • 藍色部分:ViewRootImplsetView()中執行performTraversals()
    • 這部分主要是建立SurfaceControl對象
    • 而後對Surface對象進行填充
    • scheduleTraversals()調用流程來看,這是一個異步過程
  • 青色部分:ViewRootImplsetView()中執行session.addToDisplay()
    • 這部分主要是建立SurfaceSession對象
    • native層建立SurfaceComposerClient對象

須要注意的一點是SurfaceControl對象的建立須要SurfaceSession對象做爲參數。但setView()方法中SurfaceSession對象的建立放在了SurfaceControl對象的後面
一開始其實挺疑惑的,核心仍是在scheduleTraversals()的異步調用過程,感興趣的同窗能夠參考:scheduleTraversals到底作了什麼

管理圖像緩衝區IGraphicBufferProducer

咱們一直強調Surface中最重要的對象是IGraphicBufferProducer,最後咱們也找到了它對應的Binder實體對象MonitoredProducer對象

  • 對於MonitoredProducer對象來講,它又關聯了一個sp<IGraphicBufferProducer>對象mProducer
    • mProducer對象具體的實現類是BufferQueueProducer

前面說Surface像一張畫布,那麼Surface爲何要和BufferQueue關聯呢?

  • 對於圖像顯示設備而言,它的刷新週期是固定的,必須在它須要圖像的時候把數據準備好
  • 播放動畫時,每秒要播放至少24幀畫面才能造成比較真實的動畫效果
    • 而這些圖像數據都是CPU解碼獲得的,準備它們須要時間
  • 播放視頻時的每一幀也須要在指定時間播放
  • 所以解碼器會提早準備好一批數據,這些數據保存在解碼器內部的緩衝區中
  • 當時間到達時,解碼器會把內部緩衝區的圖像數據複製到Surface
  • 可是顯示設備並不能馬上把數據取走,所以Surface須要緩衝區來臨時保存數據

BufferQueue操做官方圖解以下:
image

從前面的BufferQueue::createBufferQueue()中能夠看出:

  • MonitoredProducer對象也只是一個代理,真正的業務處理對象是在createBufferQueue()方法中建立的BufferQueueProducer對象
  • 除此以外方法中還涉及了BufferQueueCoreBufferQueueConsumer對象的建立

BufferQueue-Core|Producer|Consumer

前面已經介紹,在BufferLayeronFirstRef()方法中經過BufferQueue::createBufferQueue()方法建立了三個對象:BufferQueueCoreBufferQueueConsumerBufferQueueProducer

其中BufferQueueCore是核心,把BufferQueueConsumerBufferQueueProducer對象鏈接在了一塊兒

關於BufferQueue的工做方式,官網有個比較直觀的敘述,翻譯以下:

  • Consumer建立並擁有BufferQueue數據結構,而且可存在於與其Producer不一樣的進程中
  • Producer須要緩衝區時,它會經過調用dequeueBuffer()BufferQueue請求一個可用的緩衝區,並指定緩衝區的寬度、高度、像素格式和用法標誌。
  • 而後,Producer填充緩衝區並經過調用queueBuffer()將緩衝區返回到隊列
  • 接下來,Consumer經過acquireBuffer()獲取該緩衝區並使用該緩衝區的內容
  • Consumer操做完成後,它會經過調用releaseBuffer()將該緩衝區返回到隊列

流程較爲清晰,咱們從源碼層面再看下,首先是BufferQueueCore中的關鍵定義:

class BufferQueueCore : public virtual RefBase {
    friend class BufferQueueProducer;
    friend class BufferQueueConsumer;
    ...
private:
    BufferQueueDefs::SlotsType mSlots;
}
複製代碼

C++中的friend在這裏用來使ProducerConsumer能夠訪問Core中的成員變量。mSlots是一個64長度的BufferSlot數組,稍後細講

再看下BufferQueueProducer類的定義:

class BufferQueueProducer : public BnGraphicBufferProducer,
                            private IBinder::DeathRecipient {
...
private:
    sp<BufferQueueCore> mCore;                                
}
複製代碼

再看看BufferQueueConsumer類的定義:

class BufferQueueConsumer : public BnGraphicBufferConsumer {
...
private:
    sp<BufferQueueCore> mCore;
}
複製代碼

不難看出,Producer對象和Consumer對象經過mCore對象鏈接在一塊兒,查看ProducerConsumer這兩個對象的具體方法咱們就會發現,不少操做都是直接經過mCore對象的函數來實現的。

ConsumerProducer的接口定義

繼續看下BufferQueueConsumerBufferQueueProducer的基類,分別是BnGraphicBufferProducerBnGraphicBufferConsumer,定義以下:

class BnGraphicBufferProducer : public BnInterface<IGraphicBufferProducer>
class BnGraphicBufferConsumer : public SafeBnInterface<IGraphicBufferConsumer>
複製代碼

它們主要是實現了兩套IGraphicBufferProducerIGraphicBufferConsumerBinder接口,主要都是操做BufferQueue的相關接口,定義以下:

  • IGraphicBufferProducer
    class IGraphicBufferProducer : public IInterface
    {
    public:
        ...
        virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h, PixelFormat format, uint64_t usage, uint64_t* outBufferAge, FrameEventHistoryDelta* outTimestamps) = 0;
        ...
        virtual status_t queueBuffer(int slot, const QueueBufferInput& input, QueueBufferOutput* output) = 0;
        ...
        virtual status_t connect(const sp<IProducerListener>& listener, int api, bool producerControlledByApp, QueueBufferOutput* output) = 0;
        virtual status_t disconnect(int api, DisconnectMode mode = DisconnectMode::Api) = 0;
        ...
    };
    複製代碼
    • BufferQueueProducer類是IGraphicBufferProducer的實現
    • 使用Producer相關功能時須要先經過connect()方法創建鏈接
    • Producer使用完畢後須要調用disconnect()斷開鏈接
  • IGraphicBufferConsumer
    class IGraphicBufferConsumer : public IInterface {
        public:
            ...
            virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen, uint64_t maxFrameNumber = 0) = 0;
            virtual status_t detachBuffer(int slot) = 0;
            virtual status_t attachBuffer(int* outSlot, const sp<GraphicBuffer>& buffer) = 0;
            virtual status_t releaseBuffer(int buf, uint64_t frameNumber, EGLDisplay display, EGLSyncKHR fence, const sp<Fence>& releaseFence) = 0;
            virtual status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) = 0;
            virtual status_t consumerDisconnect() = 0;
            ...
    };
    複製代碼
    • BufferQueueConsumer是接口IGraphicBufferConsumer的實現
    • 使用Consumer相關功能時,需經過consumerConnect()方法創建鏈接
      • 這裏需傳入IConsumerListener對象,這是一個回調接口
      • 當數據準備好了就會調用這個對象的onFrameAvailable()函數來通知Consumer來取數據
    • 取數據須要調用函數acquireBuffer()
    • 使用完數據後,需調用releaseBuffer()來把緩衝區歸還給BufferQueueCore

BufferQueue的狀態轉換

前面提到BufferQueueCore類中定義了一個64項的數組mSlots

static constexpr int NUM_BUFFER_SLOTS = 64;
namespace BufferQueueDefs {
    typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];
} 
BufferQueueDefs::SlotsType mSlots;
複製代碼

mSlots數組元素類型是BufferSlot,關鍵定義以下:

struct BufferSlot {
    ...
    sp<GraphicBuffer> mGraphicBuffer;
    ...
    BufferState mBufferState;
    ...
};
複製代碼
  • mGraphicBuffer指向圖像緩衝區GraphicBuffer的指針
    • GraphicBuffer對應的即是真正的圖像緩存數據
  • mBufferState表示圖像緩衝區的狀態

BufferState定義以下:

struct BufferState {
    uint32_t mDequeueCount;
    uint32_t mQueueCount;
    uint32_t mAcquireCount;
    bool mShared;
}
複製代碼

BufferState中4個變量對應的狀態以下:

狀態\變量 mShared mDequeueCount mQueueCount mAcquireCount
FREE false 0 0 0
DEQUEUED false 1 0 0
QUEUED false 0 1 0
ACQUIRED false 0 0 1
SHARED true any any any

狀態之間的轉換關係以下:
image

結合前面提到的接口,咱們看下整個狀態轉換過程的時序圖: image

到這裏,咱們已經大致瞭解了從SurfaceSurfaceFlinger的數據通道,dequeueBuffer()等方法的細節就不深刻分析了,其中會涉及GraphicBuffer的初始化過程,不影響咱們對總體的掌握(主要是太難了。。。。。),不過如下幾點須要注意:

  • GraphicBuffer初始化時便會執行Gralloc模塊的allocate()方法申請共享內存緩衝區
  • 而且在硬件設備支持FrameBuffer緩衝區的狀況下,申請到的就是FrameBuffer的緩衝區

顯示原理和Surface相關的內容到此結束了,還有不少不完善的地方,後面再來找補吧(又挖一坑)

關於Android圖形顯示的學習還剩下SurfaceFlinger和圖像輸出過程兩部分,但願清明節前搞定,(ง •̀_•́)ง

相關文章
相關標籤/搜索