1. 程式人生 > >詳解Android SurfaceFinger服務

詳解Android SurfaceFinger服務

概述

SurfaceFlinger是android平臺的顯示服務,為移動網際網路時代的內容呈現和互動提供了平臺級的基礎。本文以Android4.2的原始碼和架構為例,詳細介紹SurfaceFlinger服務。

相關類圖


啟動

SurfaceFlinger服務的原始碼位於frameworks/native/cmds/surfaceflinger下:

int main(int argc, char** argv) {
    SurfaceFlinger::publishAndJoinThreadPool(true);
    // When SF is launched in its own process, limit the number of
    // binder threads to 4.
    ProcessState::self()->setThreadPoolMaxThreadCount(4);
    return 0;
}

為android平臺上最常見的native BinderService啟動方式。

下邊結合binder上層介面粗略分析該段程式。

將"SurfaceFlinger::publishAndJoinThreadPool(true);"

擴充套件開變為:

        sp<IServiceManager> sm(defaultServiceManager());
        sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated); // 向servicemanager註冊SurfaceFinger服務,以“SurfaceFlinger”作為名字/標識
        ProcessState::self()->startThreadPool();
        IPCThreadState::self()->joinThreadPool();

ProcessState為每程序的記錄binder程序狀態的類。主要職責在於:

  1. 開啟binder裝置並將binder事務記憶體對映到本程序地址空間的最開始,尺寸為BINDER_VM_SIZE
  2. 記錄contextobject(一般為servicemanager代理物件)
  3. 孵化執行緒/管理執行緒池
  4. IBinder和handle之間的轉換和查詢
ProcessState::self()->startThreadPool();

通過建立一個額外執行緒(自動進入looper狀態)來啟動執行緒池,
IPCThreadState::self()->joinThreadPool();

IPCThreadState為每執行緒(通過程式設計本地儲存實現)的管理binder thread狀態的類,同時負責與binder裝置之間的資料交換,其成員:
            Parcel              mIn;
            Parcel              mOut;

承擔著binder的flat/unflat、發出請求到binder、從binder裝置接收client端的請求等任務。

這樣子主執行緒也進入looper模式,現在進入joinThreadPool方法:

binder通訊的主要細節就在此方法中,主要思想便是通過talkWithDriver來取到本程序接收到的binder請求並將其反序列化為mIn身上,讀出cmd並執行之,摘取幾個重要的cmd如下:

BR_TRANSACTION:代表一次binder事務,最常見的便是RPC呼叫了

            binder_transaction_data tr;
            ......
            if (tr.target.ptr) {
                sp<BBinder> b((BBinder*)tr.cookie);
                const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);
                if (error < NO_ERROR) reply.setError(error);

            } else {
                const status_t error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
                if (error < NO_ERROR) reply.setError(error);
            }


binder_transaction_data身上帶有服務端的BBinder(client端第一次從servicemanager查詢到服務端時被告知並由binder driver記錄),

當tr.target.ptr非空時,通過該BBinder物件的transact函式來完成RPC。否則意味著對context_object(通常為本程序內的BpServiceManager物件,且對應handle為0 )的請求。

BBinder的子類通過onTransact函式來服務各種RPC呼叫。在本文中,便是SurfaceFlinger物件的onTransact函式來應對client的請求。

BR_SPAWN_LOOPER:

前邊啟動過程中,binder thread包括主執行緒(SurfaceFlinger物件構造過程中也建立了額外輔助程序,但不是binder thread,排除在外,在本文後半部分分析)一共是兩個。當有多個client請求時,勢必binder thread不夠用(binder driver簿記binder thread的各種資訊),此時binder driver便post BR_SPAWN_LOOPER型別的cmd,讓本程序預先孵化下一個binder thread,且此後孵化的執行緒不會進入looper模式(主要處理執行緒),只是登記為looper(目前在driver中未看出來兩者明顯區別)

另外,當本程序需要其他服務的協助的時候呢,本程序也需要作為client來發起binder請求,此時便用到了BpBinder::transact()函式,BpBinder成員mHandle用來引用遠端物件,作為引數傳遞給IPCThreadState::self()->transact()來完成。其原理與前述接受binder請求的過程相反,不再贅述。

SurfaceFlinger構造

此步驟是前述啟動步驟中的一小步,但也是展現出特定service與眾不同的最大一步。

如檔案第一部分所列類圖所示,SurfaceFlinger繼承自多個基類:

class SurfaceFlinger : public BinderService<SurfaceFlinger>,
                       public BnSurfaceComposer,
                       private IBinder::DeathRecipient,
                       private Thread,
                       private HWComposer::EventHandler

建構函式非常輕量級,只獲取了幾個系統debug設定。

在ServiceManager addservice時第一次引用剛建立的SurfaceFinger物件,其基類RefBase的onFirstRef被呼叫:

void SurfaceFlinger::onFirstRef()
{
    mEventQueue.init(this);

    run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);

    // Wait for the main thread to be done with its initialization
    mReadyToRunBarrier.wait();
}

初始化EventQueue,並建立Looper/Handler這對好基友。

接下來啟動自己(SurfaceFlinger也是Thread物件),

然後主執行緒阻塞住直到ReadyToRun(Thread真正啟動前的一次性初始化函式)被呼叫。

接下來咱們轉到ReadyToRun函式,鑑於該函式如一枚知性的熟女——深有內涵:

    ALOGI(  "SurfaceFlinger's main thread ready to run. "
            "Initializing graphics H/W...");

    // initialize EGL for the default display
    mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    eglInitialize(mEGLDisplay, NULL, NULL);

    // Initialize the H/W composer object.  There may or may not be an
    // actual hardware composer underneath.
    mHwc = new HWComposer(this,
            *static_cast<HWComposer::EventHandler *>(this));

    // initialize the config and context
    EGLint format = mHwc->getVisualID();
    mEGLConfig  = selectEGLConfig(mEGLDisplay, format);
    mEGLContext = createGLContext(mEGLDisplay, mEGLConfig);

    LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
            "couldn't create EGLContext");

    // initialize our non-virtual displays
    for (size_t i=0 ; i<DisplayDevice::NUM_DISPLAY_TYPES ; i++) {
        DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i);
        mDefaultDisplays[i] = new BBinder();
        wp<IBinder> token = mDefaultDisplays[i];

        // set-up the displays that are already connected
        if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) {
            // All non-virtual displays are currently considered secure.
            bool isSecure = true;
            mCurrentState.displays.add(token, DisplayDeviceState(type));
            sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i);
            sp<SurfaceTextureClient> stc = new SurfaceTextureClient(
                        static_cast< sp<ISurfaceTexture> >(fbs->getBufferQueue()));
            sp<DisplayDevice> hw = new DisplayDevice(this,
                    type, isSecure, token, stc, fbs, mEGLConfig);
            if (i > DisplayDevice::DISPLAY_PRIMARY) {
                // FIXME: currently we don't get blank/unblank requests
                // for displays other than the main display, so we always
                // assume a connected display is unblanked.
                ALOGD("marking display %d as acquired/unblanked", i);
                hw->acquireScreen();
            }
            mDisplays.add(token, hw);
        }
    }

    //  we need a GL context current in a few places, when initializing
    //  OpenGL ES (see below), or creating a layer,
    //  or when a texture is (asynchronously) destroyed, and for that
    //  we need a valid surface, so it's convenient to use the main display
    //  for that.
    sp<const DisplayDevice> hw(getDefaultDisplayDevice());

    //  initialize OpenGL ES
    DisplayDevice::makeCurrent(mEGLDisplay, hw, mEGLContext);
    initializeGL(mEGLDisplay);

    // start the EventThread
    mEventThread = new EventThread(this);
    mEventQueue.setEventThread(mEventThread);

    // initialize our drawing state
    mDrawingState = mCurrentState;


    // We're now ready to accept clients...
    mReadyToRunBarrier.open();

    // set initial conditions (e.g. unblank default device)
    initializeDisplays();

    // start boot animation
    startBootAnim();

    return NO_ERROR;


我們將其曼妙身段劃分為如下:

  1. EGL初始化
  2. Hardware Composer初始化
  3. 選擇EGLConfig並建立EGLContext
  4. 初始化各個DisplayDevice
  5. 初始化OpenGL ES並繫結到當前程序,初始化EGLDisplay
  6. 建立EventThread用於為mEventQueue身上的Handler/Looper搞基提供上下文
  7. 通知主執行緒,讓其繼續執行
  8. 初始化顯示,並顯示啟動動畫(通過“property_set("ctl.start", "bootanim")”)

下邊摘取其中一些關鍵步驟分析:

EGL初始化

EGL初始化主要通過eglGetDisplay()來實現,其引數為EGL_DEFAULT_DISPLAY(一個handle值,意義依賴於具體平臺):

EGLDisplay eglGetDisplay(EGLNativeDisplayType display)
{
    clearError();

    uint32_t index = uint32_t(display);
    if (index >= NUM_DISPLAYS) {
        return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
    }

    if (egl_init_drivers() == EGL_FALSE) {
        return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
    }

    EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display);
    return dpy;
}

接下來的呼叫棧為:egl_init_drivers->egl_init_drivers_locked,egl_init_drivers_locked中主要就是根據/system/lib/egl/egl.cfg檔案中配置資訊(其中便指定了{tag}的值)執行時裝載libGLESv1_CM_{tag}.so,libGLESv2_{tag}.so libEGL_{tag}.so,並將egl_entries.in中的egl函式簇的地址全部找到並繫結到egl_connection_t的egl成員上,將entries.in中的gl函式簇的地址全部找到並繫結到egl_connection_t的hooks上,所以最終的egl的一堆東西都儲存在了程序全域性變數:
egl_connection_t gEGLImpl;
gl_hooks_t gHooks[2];

上(gEGLImpl成員含有對gHooks的指標)。

接下來便是拿到EGLDisplay的過程,包含在egl_display_t::getFromNativeDisplay(display)中,其實現是呼叫上一步中裝載的EGL庫中的"eglGetDisplay"函式來獲得真正實現並設定給egl_display_t::sDisplay[NUM_DISPLAYS].dpy,返回egl_display_t::sDisplay陣列中第一個invalid項的索引作為EGLDisplay handle

接下來便是EGL初始化的過程:

EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
{
    clearError();

    egl_display_ptr dp = get_display(dpy);
    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);

    EGLBoolean res = dp->initialize(major, minor);

    return res;
}
其中關鍵步驟體現在dp->initialize中,展開它的實現:
EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) {

    Mutex::Autolock _l(lock);

    if (refs > 0) {
        if (major != NULL)
            *major = VERSION_MAJOR;
        if (minor != NULL)
            *minor = VERSION_MINOR;
        refs++;
        return EGL_TRUE;
    }

#if EGL_TRACE

    // Called both at early_init time and at this time. (Early_init is pre-zygote, so
    // the information from that call may be stale.)
    initEglTraceLevel();
    initEglDebugLevel();

#endif

    setGLHooksThreadSpecific(&gHooksNoContext); // 將前邊從egl庫中取出來的glhooks繫結到thread的TLS上,Note:bionic c為OpenGL預留了專用的TLS,see:

    // initialize each EGL and
    // build our own extension string first, based on the extension we know
    // and the extension supported by our client implementation

    egl_connection_t* const cnx = &gEGLImpl;
    cnx->major = -1;
    cnx->minor = -1;
    if (cnx->dso) {

#if defined(ADRENO130)
#warning "Adreno-130 eglInitialize() workaround"
        /*
         * The ADRENO 130 driver returns a different EGLDisplay each time
         * eglGetDisplay() is called, but also makes the EGLDisplay invalid
         * after eglTerminate() has been called, so that eglInitialize()
         * cannot be called again. Therefore, we need to make sure to call
         * eglGetDisplay() before calling eglInitialize();
         */
        if (i == IMPL_HARDWARE) {
            disp[i].dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
        }
#endif

        EGLDisplay idpy = disp.dpy;
        if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) { // 呼叫egl庫中的eglInitialize
            //ALOGD("initialized dpy=%p, ver=%d.%d, cnx=%p",
            //        idpy, cnx->major, cnx->minor, cnx);

            // display is now initialized
            disp.state = egl_display_t::INITIALIZED;

            // get the query-strings for this display for each implementation
            disp.queryString.vendor = cnx->egl.eglQueryString(idpy, // 查詢一些meta資訊
                    EGL_VENDOR);
            disp.queryString.version = cnx->egl.eglQueryString(idpy,
                    EGL_VERSION);
            disp.queryString.extensions = cnx->egl.eglQueryString(idpy,
                    EGL_EXTENSIONS);
            disp.queryString.clientApi = cnx->egl.eglQueryString(idpy,
                    EGL_CLIENT_APIS);

        } else {
            ALOGW("eglInitialize(%p) failed (%s)", idpy,
                    egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
        }
    }

    // the query strings are per-display
    mVendorString.setTo(sVendorString);
    mVersionString.setTo(sVersionString);
    mClientApiString.setTo(sClientApiString);

    // we only add extensions that exist in the implementation
    char const* start = sExtensionString; // 裝配擴充套件資訊
    char const* end;
    do {
        // find the space separating this extension for the next one
        end = strchr(start, ' ');
        if (end) {
            // length of the extension string
            const size_t len = end - start;
            if (len) {
                // NOTE: we could avoid the copy if we had strnstr.
                const String8 ext(start, len);
                // now look for this extension
                if (disp.queryString.extensions) {
                    // if we find it, add this extension string to our list
                    // (and don't forget the space)
                    const char* match = strstr(disp.queryString.extensions, ext.string());
                    if (match && (match[len] == ' ' || match[len] == 0)) {
                        mExtensionString.append(start, len+1);
                    }
                }
            }
            // process the next extension string, and skip the space.
            start = end + 1;
        }
    } while (end);

    egl_cache_t::get()->initialize(this); // 初始化egl_cache

    char value[PROPERTY_VALUE_MAX];
    property_get("debug.egl.finish", value, "0");
    if (atoi(value)) {
        finishOnSwap = true;
    }

    property_get("debug.egl.traceGpuCompletion", value, "0");
    if (atoi(value)) {
        traceGpuCompletion = true;
    }

    refs++;
    if (major != NULL)
        *major = VERSION_MAJOR;
    if (minor != NULL)
        *minor = VERSION_MINOR;

    mHibernation.setDisplayValid(true); // Hibernation相關

    return EGL_TRUE;
}

Hardware Composer初始化

Hardware Composer的建構函式如下:

HWComposer::HWComposer(
        const sp<SurfaceFlinger>& flinger,
        EventHandler& handler)
    : mFlinger(flinger),
      mFbDev(0), mHwc(0), mNumDisplays(1),
      mCBContext(new cb_context),
      mEventHandler(handler),
      mVSyncCount(0), mDebugForceFakeVSync(false)
{
    for (size_t i =0 ; i<MAX_DISPLAYS ; i++) {
        mLists[i] = 0;
    }

    char value[PROPERTY_VALUE_MAX];
    property_get("debug.sf.no_hw_vsync", value, "0");
    mDebugForceFakeVSync = atoi(value);

    bool needVSyncThread = true;

    // Note: some devices may insist that the FB HAL be opened before HWC.
    loadFbHalModule(); // load gralloc HAL模組
    loadHwcModule(); // load hwcomposer HAL模組

    if (mFbDev && mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
        // close FB HAL if we don't needed it.
        // FIXME: this is temporary until we're not forced to open FB HAL
        // before HWC.
        framebuffer_close(mFbDev);
        mFbDev = NULL;
    }

    // If we have no HWC, or a pre-1.1 HWC, an FB dev is mandatory.
    if ((!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
            && !mFbDev) {
        ALOGE("ERROR: failed to open framebuffer, aborting");
        abort();
    }

    // these display IDs are always reserved
    for (size_t i=0 ; i<HWC_NUM_DISPLAY_TYPES ; i++) {
        mAllocatedDisplayIDs.markBit(i);
    }

    if (mHwc) {
        ALOGI("Using %s version %u.%u", HWC_HARDWARE_COMPOSER,
              (hwcApiVersion(mHwc) >> 24) & 0xff,
              (hwcApiVersion(mHwc) >> 16) & 0xff);
        if (mHwc->registerProcs) { // 有hardware composer的情形下,需要註冊一些callback函式給它,來接受通知
            mCBContext->hwc = this;
            mCBContext->procs.invalidate = &hook_invalidate; // invalidate hook
            mCBContext->procs.vsync = &hook_vsync; // vsync hook
            if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
                mCBContext->procs.hotplug = &hook_hotplug; // hotplug hook
            else
                mCBContext->procs.hotplug = NULL;
            memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));
            mHwc->registerProcs(mHwc, &mCBContext->procs); // 真正註冊
        }

        // don't need a vsync thread if we have a hardware composer
        needVSyncThread = false; // 因為hardware composer存在,VSync由它來trigger,在SurfaceFlinger服務程序無需自己建立Vsync執行緒
        // always turn vsync off when we start
        eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);

        // the number of displays we actually have depends on the
        // hw composer version
        if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_2)) {
            // 1.2 adds support for virtual displays
            mNumDisplays = MAX_DISPLAYS;
        } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
            // 1.1 adds support for multiple displays
            mNumDisplays = HWC_NUM_DISPLAY_TYPES;
        } else {
            mNumDisplays = 1;
        }
    }
    // 從gralloc模組獲取一些顯示輸出相關資訊
    if (mFbDev) {
        ALOG_ASSERT(!(mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)),
                "should only have fbdev if no hwc or hwc is 1.0");

        DisplayData& disp(mDisplayData[HWC_DISPLAY_PRIMARY]);
        disp.connected = true;
        disp.width = mFbDev->width;
        disp.height = mFbDev->height;
        disp.format = mFbDev->format;
        disp.xdpi = mFbDev->xdpi;
        disp.ydpi = mFbDev->ydpi;
        if (disp.refresh == 0) {
            disp.refresh = nsecs_t(1e9 / mFbDev->fps);
            ALOGW("getting VSYNC period from fb HAL: %lld", disp.refresh);
        }
        if (disp.refresh == 0) {
            disp.refresh = nsecs_t(1e9 / 60.0);
            ALOGW("getting VSYNC period from thin air: %lld",
                    mDisplayData[HWC_DISPLAY_PRIMARY].refresh);
        }
    } else if (mHwc) {
        // here we're guaranteed to have at least HWC 1.1
        for (size_t i =0 ; i<HWC_NUM_DISPLAY_TYPES ; i++) {
            queryDisplayProperties(i);
        }
    }

    if (needVSyncThread) { // 如果Hardware composer不存在,則需要在SurfaceFlinger程序中建立VSync執行緒
        // we don't have VSYNC support, we need to fake it
        mVSyncThread = new VSyncThread(*this);
    }
}

SurfaceFlinger實現了HWComposer::EventHandler介面,所以最終的VSync和Hotplug處理在SurfaceFlinger::onVSyncReceived()和SurfaceFlinger::onHotplugReceived()中。

選擇EGLConfig並建立EGLContext

    // initialize the config and context
    EGLint format = mHwc->getVisualID(); // 從hardware composer取到顏色空間
    mEGLConfig  = selectEGLConfig(mEGLDisplay, format); // 生成EGLConfig
    mEGLContext = createGLContext(mEGLDisplay, mEGLConfig); //生成EGLContext(通過呼叫egl庫的eglCreateContext函式,然後封裝成egl_context_t物件)

初始化各個DisplayDevice

    // initialize our non-virtual displays
    for (size_t i=0 ; i<DisplayDevice::NUM_DISPLAY_TYPES ; i++) {
        DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i);
        mDefaultDisplays[i] = new BBinder();
        wp<IBinder> token = mDefaultDisplays[i];

        // set-up the displays that are already connected
        if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) {
            // All non-virtual displays are currently considered secure.
            bool isSecure = true;
            mCurrentState.displays.add(token, DisplayDeviceState(type));
            sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i);
            sp<SurfaceTextureClient> stc = new SurfaceTextureClient(
                        static_cast< sp<ISurfaceTexture> >(fbs->getBufferQueue()));
            sp<DisplayDevice> hw = new DisplayDevice(this,
                    type, isSecure, token, stc, fbs, mEGLConfig);
            if (i > DisplayDevice::DISPLAY_PRIMARY) {
                // FIXME: currently we don't get blank/unblank requests
                // for displays other than the main display, so we always
                // assume a connected display is unblanked.
                ALOGD("marking display %d as acquired/unblanked", i);
                hw->acquireScreen();
            }
            mDisplays.add(token, hw);
        }
    }

DisplayDevice封裝了一個顯示裝置,組合了之前分析過的hardware composer, framebuffer surface, SurfaceTextureClient, EGLConfig.在SurfaceFlinger的合成和顯示的每個點上都會遍歷這個DisplayDevice集合。

初始化OpenGL ES並繫結到當前程序,初始化EGLDisplay

    //  initialize OpenGL ES
    DisplayDevice::makeCurrent(mEGLDisplay, hw, mEGLContext);
    initializeGL(mEGLDisplay);

ReadyToRun終於執行完了,接下來便進入真正的threadloop:
bool SurfaceFlinger::threadLoop() {
    waitForEvent(); // 通過Looper等待事件
    return true;
}

建立Surface

Android中建立建立一個Activity時建立Surface的流程:
● Activity Thread calls on attach() and makeVisible()
● makeVisible does wm.addView()
● vm.addView() - this also called by StatusBar to display itself
● Creates a new ViewRootImpl
● Call on its setView()
● setView() calls on sWindowSession.add(...)
● This results in call to WM's addWindow()
● ViewRootImpl's performTraversals()
● Calls on relayoutWindow()
● Calls to WM session's relayout()
● Call to WM's relayoutWindow()
● Call to createSurfaceLocked()
● new Surface(...)  // Surface Object @java-layer

Surface建構函式呼叫了一個nativeCreate的native方法,其實現位於:

static void nativeCreate(JNIEnv* env, jobject surfaceObj, jobject sessionObj,
        jstring nameStr, jint w, jint h, jint format, jint flags) {
    ScopedUtfChars name(env, nameStr);
    sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));

    sp<SurfaceControl> surface = client->createSurface(
            String8(name.c_str()), w, h, format, flags);
    if (surface == NULL) {
        jniThrowException(env, OutOfResourcesException, NULL);
        return;
    }

    setSurfaceControl(env, surfaceObj, surface);
}

與此類似,接下來貼上一段Native層建立Surface的Sample程式碼:

        mComposerClient = new SurfaceComposerClient;
        ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());

        sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
                ISurfaceComposer::eDisplayIdMain));
        DisplayInfo info;
        SurfaceComposerClient::getDisplayInfo(display, &info); // 獲取顯示引數

        ssize_t displayWidth = info.w;
        ssize_t displayHeight = info.h;

        // Background surface
        mBGSurfaceControl = mComposerClient->createSurface( // 建立Surface,後文將詳細分析其squence
                String8("BG Test Surface"), displayWidth, displayHeight,
                PIXEL_FORMAT_RGBA_8888, 0);
        ASSERT_TRUE(mBGSurfaceControl != NULL);
        ASSERT_TRUE(mBGSurfaceControl->isValid());
        fillSurfaceRGBA8(mBGSurfaceControl, 63, 63, 195); 

// Fill an RGBA_8888 formatted surface with a single color.
static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc,
        uint8_t r, uint8_t g, uint8_t b) {
    Surface::SurfaceInfo info;
    sp<Surface> s = sc->getSurface();
    ASSERT_TRUE(s != NULL);
    ASSERT_EQ(NO_ERROR, s->lock(&info));
    uint8_t* img = reinterpret_cast<uint8_t*>(info.bits);
    for (uint32_t y = 0; y < info.h; y++) {
        for (uint32_t x = 0; x < info.w; x++) {
            uint8_t* pixel = img + (4 * (y*info.s + x));
            pixel[0] = r;
            pixel[1] = g;
            pixel[2] = b;
            pixel[3] = 255;
        }
    }
    ASSERT_EQ(NO_ERROR, s->unlockAndPost());
}

其中CreateSurface過程的時序圖如下:


queueBuffer的過程時序圖如下:


VSync的時序圖:

在dequeue了新的GraphicBuffer之後,SurfaceFlinger就需要對它管理的layer進行合成。合成的過程主要包含了以下幾個重要的步驟:
handleMessageTransaction:處理系統顯示屏以及應用程式視窗的屬性變化。並把SurfaceFlinger::mDrawingStat更新為SurfaceFlinger::mCurrentState,新建立的layer(surface)都是儲存在mCurrentState中的。
handlePageFlip:更新每個layer的active buffer。
rebuildLayerStacks:為每個DisplayDevice設定可見、按Z-order排序的layers
setUpHWComposer:根據在step3設定的SurfaceFlinger的DisplayDevice中的active layers來設定HWComposer的DisplayData資料,然後呼叫hwc模組的prepare函式
doComposition:使用OpenGL ES或者hwc模組來合成

在合成完後,就需要推送到螢幕上顯示。有3個重要的類用來管理顯示裝置:

DisplayDeviceFramebufferSurfaceSurfaceTextureClient

Android系統支援多個顯示裝置,每一個顯示裝置在SurfaceFlinger程序中都有一個DisplayDevice物件來管理它。

FramebufferSurface繼承於ConsumerBase,當其連線的BufferQueue有新幀時,其onFrameAvailable方法會被呼叫,來處理這個新幀。

SurfaceTextureClient繼承於ANativeWindow,在SurfaceFlinger程序中,它引用了FramebufferSurfaceBufferQueue;同時又因為它是一個ANativeWindow,它被EGL封裝為EGLSurface儲存在DisplayDevice 中,用來顯示改裝置的新幀。

DisplayDevice的初始化過程在SurfaceFlinger::readyToRun()裡實現。

下面重點介紹兩種不同情況下的顯示流程:

在沒有hwc模組時的顯示流程 在有hwc模組並且使用hwc模組來進行合成的顯示流程
沒有HWC模組時:

有HWC模組時:


相關推薦

Android SurfaceFinger服務

概述 SurfaceFlinger是android平臺的顯示服務,為移動網際網路時代的內容呈現和互動提供了平臺級的基礎。本文以Android4.2的原始碼和架構為例,詳細介紹SurfaceFlinger服務。 相關類圖 啟動 SurfaceFlinger服務的原始碼位於

Android 的 Activity 組件

lag 基本 詳細說明 email tco use you 鎖定 多態 本文詳細介紹了 Android 應用編程中 Activity 的生命周期、通信方式和 Intent Filter 等內容,並提供了一些日常開發中經常用到的關於 Activity 的技巧和方法

postfix郵箱服務器安裝、配置及其工作原理(內附源碼包)

zhang 關閉防火墻 互聯 分享 接收郵件 目錄 ifconfig shutdown 數字 簡介 postfix是Wietse Venema在IBM的GPL協議之下開發的MTA(郵件傳輸代理)軟件。postfix是Wietse Venema想要為使用最廣泛的sendmai

區塊鏈服務——部署區塊鏈

eve 內置 登錄 參數 icloud 部分匹配 容器集群 鍵值 數量 部署區塊鏈服務 步驟1:資源準備為了更穩定的運行區塊鏈服務需準備2臺8u16g機器來進行服務的部署。註冊並登陸華為雲賬號,進入華為雲管理控制臺, 選擇計算/雲容器引擎服務(見圖2)。 點擊創建Kub

區塊鏈服務——業務層區塊鏈應用開發

proc mage follow tex content 證書 一個 用戶 vpd 開發業務層區塊鏈應用 [Hyperledger fabric(https://www.huaweicloud.com/product/bcs.html) 目前支持java,nodejs

Android數據存儲技術

應用 接收 delete gets 數據庫版本 data文件夾 upgrade 占位符 講解 前言 學習Android相關知識,數據存儲是其中的重點之一,如果不了解數據,那麽讓你跟一款沒有數據的應用玩,你能玩多久呢?答案是這和沒有手機幾乎是差不多的。我們聊QQ,聊微信,看

Android/IOS平臺下抓包工具使用以及抓取API介面

抓包工具 Charles 主機允許代理模式 客戶端設定代理 截獲資料包 HTTPS 模仿一個app

Android SDK 目錄和作用

Android SDK 目錄和作用的分析詳解 1、add-ons這裡面儲存著附加庫,比如GoogleMaps,當然你如果安裝了OphoneSDK,這裡也會有一些類庫在裡面。 2、docs這裡面是Android SDKAPI參考文件,所有的API都可以在這裡查到。 3、market_lic

Android View的事件體系 之View基礎(二)

前言 掌握View的事件體系是Android 向高階邁向的必經之路,本片部落格講解Android View的相關基礎知識第二部分,後面我們會為大家講解View事件體系、View事件分發等知識內容。View相關知識第一部分https://blog.csdn.net/huangliniqng/a

Android使用Cordova系列-android專案整合Cordova模組

Cordova簡介 在客戶端app開發的過程中,許多變動的業務需要前端來處理,隨著業務的不斷變動,前端和客戶端需要支援複雜的互動來滿足業務的增長. 如今大部分的app都有自己的前端和客戶端互動框架,大公司都會自己開發搭建JSBridge來滿足,也有一些開

Android Selinux 許可權及問題

由於現做的是MTK平臺,原始碼路徑基於MTK, 不過高通大同小異 說明 Android 5.0以後完全引入了 SEAndroid/SELinux 安全機制,這樣即使擁有 root 許可權或 chmod 777 ,仍然無法再JNI以上訪問核心節點。 其實在 Android 4.4 就有限制

Android中的build.gradle檔案

一、什麼是Gradle 簡單的說,Gradle是一個構建工具,它是用來幫助我們構建app的,構建包括編譯、打包等過程。我們可以為Gradle指定構建規則,然後它就會根據我們的“命令”自動為我們構建app。Android Studio中預設就使用Gradle來完成應用的構建。有些同學可能會有疑問:”我用AS不記

Android Studio Git分支實踐

新公司有些專案是用的 Git,以前公司都是 svn,為了練手 Git,我個人 APP 用到了,但是僅簡單的 git pull/push 的使用,並未用到 Git 精髓,只有當專案中用到,才會緊迫去全面學習,所以說,在專案中進步是最快的。 開發場景:遠端有主分支 mast

Android介面Interface的使用和意義

本文介紹是Android的一個重要的東西,介面Interface,詳解兩個方面: (1)Java是繼承的,介面Interface是可以多個的,恰恰彌補了這個缺點。 (2)回撥,介面Interface裡面的是抽象方法,需要回調進行相應操作。 通俗地講講上面兩點講的是什麼(懂了就不用看了,

Android View的事件體系 之View基礎(一)

前言 掌握View的事件體系是Android 向高階邁向的必經之路,本片部落格講解Android View的相關基礎知識第一部分,後面我們會為大家講解基礎知識第二部分、VIew事件體系、View事件分佈等知識內容。 1.View基礎 1.1 什麼是View 簡單的說V

AlarmManager:android中的定時任務

1.概述 AlarmManager通常用途是用來開發手機鬧鐘,但是AlarmManager的用處並只是這個。AlarmManager其實是一個全域性定時器,它可以在指定時間或指定週期啟動其他元件,在特定的時刻為我們廣播一個指定的Intent。簡單的說就是我們設

Android劉海屏適配

Apple一直在引領設計的潮流,自從 iPhone X 釋出之後,”劉海屏” 就一直存在爭議,本以為是一個美麗的錯誤(Bug),卻早就了一時間“劉海屏”的模仿潮。目前,國內已經推出的劉海屏”手機有 OPPO R15 和 華為 P20,並且Google也在IO大會

Android Drawable

1 Drawable概述 Drawable是一種影象的概念,但又不全是圖片,也可能是各種顏色組合而成的影象。通常將Drawable作為View的背景,而這些Drawable我們一般通過XML來定義,當

Android中回撥機制與RecyclerView的Item點選事件實現

總是看書上寫著回調回調,以為就是函式呼叫換了個名字,尤其是看了Button的點選事件實現後,覺得不就是觸發機制。 A事件發生->後臺處理邏輯->告訴前臺怎麼做->結束。 Android常見button點選事件: loginB

Android廣播機制

謹以文章記錄學習歷程,如有錯誤還請指明。 前言 我們上學時都有過這樣的經歷,當我們在火車站列車候車室中等待時,每當有某次列車開始檢票或者進站上車時,就會播放通知來告知在候車室等待的人們該訊息。 為了便於進行系統級別的訊息通知,Android引入