主頁 > 移動端開發 > Android回爐系列之Surfaceflinger

Android回爐系列之Surfaceflinger

2021-01-01 13:46:21 移動端開發

Android回爐系列之Surfaceflinger

文章目錄

  • Android回爐系列之Surfaceflinger
    • 前言
    • 1. Surfaceflinger是什么?
    • 2. Surfaceflinger
      • 2.1 特點一
      • 2.2 特點二
      • 2.3 特點三
      • 2.4 特點四
      • 2.5 特點五
    • 3. 小結
    • 4. Surfaceflinger初始化
      • 4.1 初始化涉及檔案
      • 4.2 Android.bp瀏覽
      • 4.3 Surfaceflinger.rc
      • 4.4 main_surfaceflinger.cpp
      • 4.5 Surfaceflinger實體化
        • 4.5.1 DispSync初始化
        • 4.5.2 圖元佇列調度
      • 4.6 Surfaceflinger初始化
        • 4.6.1 EventThread|DispSyncSource的初始化
        • 4.6.2 EventThread實體化
        • 4.6.3 Surfaceflinger的EventThread初始化
        • 4.6.4 監聽
        • 4.6.5 BitTube
        • 4.6.6 事件監聽程序
      • 4.7 RenderEngine初始化
      • 4.8 HWComposer初始化
        • 4.8.1 HWComposer初始化
        • 4.8.2 HWComposer監聽
      • 4.8 Surfaceflinger的run

前言

很早開始就有想寫寫博客的想法,畢竟好記心不如爛筆頭,這段時間公司業務要求,對音視頻、渲染等要有深度理解,突然之間發現自己腦袋是空空的,沒辦法就只有系統性的回爐一遍,同時也做好存檔,以便于后期的復習、升華做鋪墊!好了廢話不多說了,我們首先從界面繪制渲染開始,竟然是繪制那么針對我們Android系統而言我們是怎么把視圖呈現給用戶的呢?帶著這個疑惑,我們就從surfaceflinger開始一一決議,


1. Surfaceflinger是什么?

通過查閱原始碼發現surfaceflinger幾乎貫通了Android所有領域的知識,從硬體抽象層到framework層,CPU回應處理到OpenGL等等硬體繪制,復雜~,,,所以本文不針對細則邏輯做描述,我們從架構決議開始,來了解它的設計思想,
surfaceflinger是整個Android系統渲染的核心行程,所有的應用的渲染邏輯最后都會來到surfaceflinger進行處理,最有在把處理后的影像資料交給CPU/GPU繪制在螢屏上,


2. Surfaceflinger

在學習之前給出其總結的五個特點,以便后面的細則理解和設計結構的理解,

2.1 特點一

surfaceflinger在Android系統中并不是擔當渲染角色,而是一個工具(“傳輸機器”),把每個應用傳輸過來的圖元資料處理后交給CPU||GPU做繪制處理,

2.2 特點二

由于針對每個應用而言都是以Surface做為一個圖元為傳輸單位,向surfaceflinger傳輸圖元資料,如下圖:
在這里插入圖片描述

2.3 特點三

通過閱讀發現Surfaceflinger設計核心思想就是以生產者和消費者的模式,會把每一個應用的Surface圖元保存到SufaceflingerQueue佇列中,Surfaceflinger作為消費者會根據一定的邏輯規則把生產者放入Surface一一處理,如下圖:
在這里插入圖片描述

2.4 特點四

由于應用行程和Surfaceflinger是兩個獨立的行程,那么圖元資料是怎么實作傳輸的呢?這里就需要跨行程通信,這里就會連鎖反應想到socket和binder但是由于socket需要拷貝兩次在效率上不可取,binder又有大小限制好像是1M不到還要包括其它的通信也不可取,所以為了解決這個問題,Android系統使用了共享記憶體(匿名共享記憶體ion),匿名共享記憶體也只需要拷貝一次的行程通信方式,聽大神說比較接近Linux共享記憶體,具體實作方式后期在學習~如下圖:

在這里插入圖片描述

2.5 特點五

Surfaceflinger底層有一個時間鐘在不斷回圈,從硬體中發出或者從軟體模擬發出記時喚起,每個一段時間(16ms)都會獲取Surfaceflinger中的圖元佇列通過CPU/GPU繪制到螢屏上,這個特點有點繞,因為此特點應用有辦法通知Surfaceflinger渲染模式,Surfaceflinger繪制螢屏有自身回呼自身特點等,如下圖:
在這里插入圖片描述
PS:對于相位和Vsync(垂直信號)的介紹我們會在后續同步,

3. 小結

上述五點就是Surfaceflinger的設計核心特點,按照這五個特點閱讀可以降低其復雜性,那么Surfaceflinger和skia有什么關系呢?和頂層View的繪制又有什么關系呢?

我們通過層級區分如下:

  1. framework面向應用開發者的View是便于開發的控制元件,里面提供了當前控制的屬性以及功能,
  2. Skia是Android對于螢屏的畫筆,經過View的onDraw方法回呼,把需要繪制的東西通過Skia繪制成像素圖元保存起來,
  3. Surfaceflinger是最后接收Skia的繪制結果,最后同步到螢屏上,

所以,Skia是Android渲染的核心,最終Skia和系統結合起來才是一個完整的渲染體系,如下圖:
在這里插入圖片描述


4. Surfaceflinger初始化

針對初始化我們通過代碼結合形式來分析代碼來至版本9.0,在閱讀原始碼做下鋪墊,首先我們先弄清楚EGL/OPENGL ES,Displayhardware,Gralloc,FramcbuffernativeWindow等等之間的關系,如下圖:
在這里插入圖片描述

  • Android HAL層提供了Gralloc,包括fb和gralloc兩個設備,前者負責打開內核中的framebuffer、初始化配置,提供Post,setSwapInsterval等操作介面;后者者管理針緩沖區的分配和釋放,這就意味著上層元素只能通過Gralloc來訪問幀緩沖區,從而保證系統對framebuffer的有序使用和統一管理,
  • 另外HAL層的另一個重要模塊Conposer它是為廠商自制UI合成提供介面,它的直接使用者是surfaceflinger中的HWConposer,同時還負責VSync信號的產生和控制,VSync是一種同步機制,可以是硬體產生,也可以通過軟體來模擬Thread,
  • 由于OpenGL ES是一個通用的函式庫,在不同的平臺系統上需要被本地化及就是把它具體的平臺視窗系統聯系起來,FramebufferNativeWindow主要就是負責OpenGL ES在Android平臺上本地化的中介之一,還有一個本地視窗Surface,為OpenGL ES配置本地視窗的是EGL,
  • OpenGL ES 只是一個介面協議,具體實作既可以采用軟體,也可以依托于硬體,那么OpenGLES 動態運行時是如何取舍的?這個就是EGL的作用之一,它回去讀取egl.cfg這個組態檔,然后根據設定動態加贊libagl||libhgl,
  • surfaceflinger中持有一個陣列mDisplays來描述系統中支持的顯示設備及Display,它是由surfaceflinger在readyToRun中判斷并賦值,并且在DisplayDevice在初始化時還將呼叫eglgetDisplay,eglcreateWindowSurface等,并利用EGL來完成OpenGLES的環境搭建,,,

4.1 初始化涉及檔案

  • /frameworks/native/services/surfaceflinger/Android.bp
  • /frameworks/native/services/surfaceflinger/surfaceflinger.rc
  • /frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp
  • /frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
  • /frameworks/native/services/surfaceflinger/DispSync.cpp
  • /frameworks/native/services/surfaceflinger/MessageQueue.cpp
  • /frameworks/native/services/surfaceflinger/EventThread.cpp
  • /frameworks/native/services/surfaceflinger/MessageQueue.cpp
  • /frameworks/native/libs/gui/BitTube.cpp
  • /frameworks/native/services/surfaceflinger/EventThread.cpp
  • /frameworks/native/libs/gui/DisplayEventReceiver.cpp
  • /frameworks/native/services/surfaceflinger/MessageQueue.cpp
  • /frameworks/native/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
  • /frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer.cpp
  • /frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer.cpp
  • /frameworks/native/services/surfaceflinger/DisplayHardware/HWC2.cpp
  • /frameworks/native/services/surfaceflinger/EventControlThread.cpp
  • /frameworks/native/services/surfaceflinger/MessageQueue.cpp

4.2 Android.bp瀏覽

需要明白Surfaceflinger的啟動需要先了解其涉及的模塊,bp檔案路徑: /frameworks/native/services/surfaceflinger/Android.bp
對應代碼如下:

cc_defaults {
    name: "libsurfaceflinger_defaults",
    defaults: ["surfaceflinger_defaults"],
    cflags: [
        "-DGL_GLEXT_PROTOTYPES",
        "-DEGL_EGLEXT_PROTOTYPES",
    ],
    shared_libs: [
        "android.frameworks.vr.composer@1.0",
        "android.hardware.configstore-utils",
        "android.hardware.configstore@1.0",
        "android.hardware.configstore@1.1",
        "android.hardware.graphics.allocator@2.0",
        "android.hardware.graphics.composer@2.1",
        "android.hardware.graphics.composer@2.2",
        "android.hardware.power@1.0",
        "libbase",
        "libbinder",
        "libbufferhubqueue",
        "libcutils",
        "libdl",
        "libEGL",
        "libfmq",
        "libGLESv1_CM",
        "libGLESv2",
        "libgui",
        "libhardware",
        "libhidlbase",
        "libhidltransport",
        "libhwbinder",
        "liblayers_proto",
        "liblog",
        "libpdx_default_transport",
        "libprotobuf-cpp-lite",
        "libsync",
        "libtimestats_proto",
        "libui",
        "libutils",
        "libvulkan",
    ],
    static_libs: [
        "libserviceutils",
        "libtrace_proto",
        "libvkjson",
        "libvr_manager",
        "libvrflinger",
    ],
    header_libs: [
        "android.hardware.graphics.composer@2.1-command-buffer",
        "android.hardware.graphics.composer@2.2-command-buffer",
    ],
    export_static_lib_headers: [
        "libserviceutils",
    ],
    export_shared_lib_headers: [
        "android.hardware.graphics.allocator@2.0",
        "android.hardware.graphics.composer@2.1",
        "android.hardware.graphics.composer@2.2",
        "libhidlbase",
        "libhidltransport",
        "libhwbinder",
    ],
}
cc_library_headers {
...
}

filegroup {
    name: "libsurfaceflinger_sources",
    srcs: [
       ...
    ],
}
cc_library_shared {
    name: "libsurfaceflinger",
    defaults: ["libsurfaceflinger_defaults"],
   ...
}
cc_binary {
    name: "surfaceflinger",
    defaults: ["surfaceflinger_defaults"],
    init_rc: ["surfaceflinger.rc"],
    srcs: ["main_surfaceflinger.cpp"],
     ...
}
...

Surfaceflinger中涉及的幾個核心:

  • android.hardware.graphics.allocator@2.0 (圖元生成器抽象硬體層的實作)
  • android.hardware.graphics.composer@2.x(hwc圖層合成抽象硬體層實作)
  • binder,OpenGL es,hwbinder(抽象硬體層的binder)等等
  • 設定了SurfaceFlinger的在Android啟動初期需要加載的init.rc檔案:surfaceflinger.rc
  • SurfaceFlinger的主函式入口main_surfaceflinger.cpp

PS:針對硬體抽象層不好理解,我們先把這個疑問預留這里,后期在學習總結,

4.3 Surfaceflinger.rc

檔案路徑: /frameworks/native/services/surfaceflinger/surfaceflinger.rc
對應代碼如下:

service surfaceflinger /system/bin/surfaceflinger
    class core animation
    user system
    group graphics drmrpc readproc
    onrestart restart zygote
    writepid /dev/stune/foreground/tasks
    socket pdx/system/vr/display/client     stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0
    socket pdx/system/vr/display/manager    stream 0666 system graphics u:object_r:pdx_display_manager_endpoint_socket:s0
    socket pdx/system/vr/display/vsync      stream 0666 system graphics u:object_r:pdx_disp

上面代碼在啟動surfaceflinger服務、系統之外,同步還啟動了三個socket-跨行程通信的,具體作用不是當前重點后續在做研究,

4.4 main_surfaceflinger.cpp

Surfaceflinger啟動入口其檔案路徑:
/frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp

int main(int, char**) {
	//忽略了SIGPIPE信號,因為在SurfaceFlinger的Client-Server模型中,或者說IPC機制中,很可能會觸發SIGPIPE信號,而這個信號的默認動作是終止行程
	//當客戶端/服務端的socket關閉時,防止行程退出
    signal(SIGPIPE, SIG_IGN);
    hardware::configureRpcThreadpool(1 /* maxThreads */,
            false /* callerWillJoin */);
    startGraphicsAllocatorService();//初始化Hal層的圖元生成器服務
    //設定surfaceflinger行程的binder執行緒池個數上限為4,并啟動binder執行緒池;
    ProcessState::self()->setThreadPoolMaxThreadCount(4);

    //開啟執行緒
    //大多數程式都是需要IPC的,這里也需要,但是使用Binder機制是很繁瑣的,所以Android為程式行程使用Binder機制封裝了兩個實作類:ProcessState、IPCThreadState
  //其中ProcessState負責打開Binder驅動,進行mmap等準備作業;IPCThreadState負責具體執行緒跟Binder驅動進行命令互動,
    sp<ProcessState> ps(ProcessState::self());
    ps->startThreadPool();

    // 實體化
    sp<SurfaceFlinger> flinger = new SurfaceFlinger();

    //設定surfaceflinger行程為高優先級以及前臺調度策略;
    setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);

    set_sched_policy(0, SP_FOREGROUND);

    // Put most SurfaceFlinger threads in the system-background cpuset
    // Keeps us from unnecessarily using big cores
    // Do this after the binder thread pool init
    if (cpusets_enabled()) set_cpuset_policy(0, SP_SYSTEM);

    // 執行surfaceflinger初始化方法
    flinger->init();

    //將surfaceflinger添加到ServiceManager
    //sp是strongponiter強指標(sp物件的解構式呼叫RefBase的decStrong來減少強弱參考指標計數)
    sp<IServiceManager> sm(defaultServiceManager());
    sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
                   IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL);

    // 注冊GPU
    sp<GpuService> gpuservice = new GpuService();
    sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);

    startDisplayService(); // 啟動圖形處理相關服務

    struct sched_param param = {0};
    param.sched_priority = 2;
    if (sched_setscheduler(0, SCHED_FIFO, &param) != 0) {
        ALOGE("Couldn't set SCHED_FIFO");
    }

    // 運行當前執行緒
    flinger->run();

    return 0;
}

在上面方法中我們抽離幾個核心方法解讀:

  • startGraphicsAllocatorService初始化hal層的圖元生成器
  • 初始化ProcessState,把該行程映射到Binder驅動程式
  • Surfaceflinger實體化
  • set_sched_policy設定前臺行程
  • Surfaceflinger初始化
  • 由于Surfaceflinger本質是Binder服務,所以需要添加到ServiceManager行程中
  • 初始化GpuService,添加到ServiveManager行程中
  • 啟動圖形處理相關服務DisplayService
  • sched_setscheduler把行程調度模式設定為實時行程的FIFO
  • 呼叫Surfaceflinger的run方法

PS:由于Surfaceflinger不像應用行程一樣是前臺應用,它是運行云后臺的為了保證它不被干掉,為了CPU不斷的優先把資源傳遞給Surfaceflinger,為了讓得到的渲染機會在16ms完成,
這里有一個FIFO就是實時調度策略,細則感興趣的桐學可以學習下linux的行程調度,
Surfaceflinger被設定為SP_FOREGROUND,設定為前臺行程,加入到前臺行程陣列中,接著SCHED_FIFO優先級策略,這樣就能保證Surfaceflinger是在較高優先級下運行,同時保證只要每一次遍歷行程調度類的時候,必定會先讓渡給Surfaceflinger,接著讓調渡給Ap應用,

4.5 Surfaceflinger實體化

創建SurfaceFlinger物件,在其建構式中,主要是一些成員變數的初始化作業核心是提供的surfaceflinger的binder能力,提供layer創建等能力,系統提供的監聽Binder行程死亡的事件回呼,HWComper提供的監聽顯示幕變化事件回呼以及Hwcomposer中的Vsync信號,
代碼路徑:/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

SurfaceFlinger::SurfaceFlinger(SurfaceFlinger::SkipInitializationTag)
      : BnSurfaceComposer(),
        mTransactionFlags(0),
        mTransactionPending(false),
        mAnimTransactionPending(false),
        mLayersRemoved(false),
        mLayersAdded(false),
        mRepaintEverything(0),
        mBootTime(systemTime()),
        mBuiltinDisplays(),
        mVisibleRegionsDirty(false),
        mGeometryInvalid(false),
        mAnimCompositionPending(false),
        mDebugRegion(0),
        mDebugDDMS(0),
        mDebugDisableHWC(0),
        mDebugDisableTransformHint(0),
        mDebugInSwapBuffers(0),
        mLastSwapBufferTime(0),
        mDebugInTransaction(0),
        mLastTransactionTime(0),
        mBootFinished(false),
        mForceFullDamage(false),
        mPrimaryDispSync("PrimaryDispSync"),
        mPrimaryHWVsyncEnabled(false),
        mHWVsyncAvailable(false),
        mHasPoweredOff(false),
        mNumLayers(0),
        mVrFlingerRequestsDisplay(false),
        mMainThreadId(std::this_thread::get_id()),
        mCreateBufferQueue(&BufferQueue::createBufferQueue),
        mCreateNativeWindowSurface(&impl::NativeWindowSurface::create) {}
  • BnSurfaceComposer,IBinder::DeathRecipient,HWComposer::EventHandler SurfaceFlinger的父類
  • mPrimaryDispSync 主要的信號同步處理器
  • BufferQueue 圖元消費佇列
SurfaceFlinger::SurfaceFlinger() : SurfaceFlinger(SkipInitialization) {
    ALOGI("SurfaceFlinger is starting");

    vsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs,
            &ISurfaceFlingerConfigs::vsyncEventPhaseOffsetNs>(1000000);

    sfVsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs,
            &ISurfaceFlingerConfigs::vsyncSfEventPhaseOffsetNs>(1000000);

    hasSyncFramework = getBool< ISurfaceFlingerConfigs,
            &ISurfaceFlingerConfigs::hasSyncFramework>(true);

    dispSyncPresentTimeOffset = getInt64< ISurfaceFlingerConfigs,
            &ISurfaceFlingerConfigs::presentTimeOffsetFromVSyncNs>(0);

    useHwcForRgbToYuv = getBool< ISurfaceFlingerConfigs,
            &ISurfaceFlingerConfigs::useHwcForRGBtoYUV>(false);

    maxVirtualDisplaySize = getUInt64<ISurfaceFlingerConfigs,
            &ISurfaceFlingerConfigs::maxVirtualDisplaySize>(0);

    // Vr flinger is only enabled on Daydream ready devices.
    useVrFlinger = getBool< ISurfaceFlingerConfigs,
            &ISurfaceFlingerConfigs::useVrFlinger>(false);

    maxFrameBufferAcquiredBuffers = getInt64< ISurfaceFlingerConfigs,
            &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2);

    hasWideColorDisplay =
            getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);

    V1_1::DisplayOrientation primaryDisplayOrientation =
        getDisplayOrientation< V1_1::ISurfaceFlingerConfigs, &V1_1::ISurfaceFlingerConfigs::primaryDisplayOrientation>(
            V1_1::DisplayOrientation::ORIENTATION_0);

    switch (primaryDisplayOrientation) {
        case V1_1::DisplayOrientation::ORIENTATION_90:
            mPrimaryDisplayOrientation = DisplayState::eOrientation90;
            break;
        case V1_1::DisplayOrientation::ORIENTATION_180:
            mPrimaryDisplayOrientation = DisplayState::eOrientation180;
            break;
        case V1_1::DisplayOrientation::ORIENTATION_270:
            mPrimaryDisplayOrientation = DisplayState::eOrientation270;
            break;
        default:
            mPrimaryDisplayOrientation = DisplayState::eOrientationDefault;
            break;
    }
    ALOGV("Primary Display Orientation is set to %2d.", mPrimaryDisplayOrientation);

    mPrimaryDispSync.init(SurfaceFlinger::hasSyncFramework, SurfaceFlinger::dispSyncPresentTimeOffset);

    // debugging stuff...
    char value[PROPERTY_VALUE_MAX];

    property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
    mGpuToCpuSupported = !atoi(value);

    property_get("debug.sf.showupdates", value, "0");
    mDebugRegion = atoi(value);

    property_get("debug.sf.ddms", value, "0");
    mDebugDDMS = atoi(value);
    if (mDebugDDMS) {
        if (!startDdmConnection()) {
            // start failed, and DDMS debugging not enabled
            mDebugDDMS = 0;
        }
    }
    ALOGI_IF(mDebugRegion, "showupdates enabled");
    ALOGI_IF(mDebugDDMS, "DDMS debugging enabled");

    property_get("debug.sf.disable_backpressure", value, "0");
    mPropagateBackpressure = !atoi(value);
    ALOGI_IF(!mPropagateBackpressure, "Disabling backpressure propagation");

    property_get("debug.sf.enable_hwc_vds", value, "0");
    mUseHwcVirtualDisplays = atoi(value);
    ALOGI_IF(!mUseHwcVirtualDisplays, "Enabling HWC virtual displays");

    property_get("ro.sf.disable_triple_buffer", value, "1");
    mLayerTripleBufferingDisabled = atoi(value);
    ALOGI_IF(mLayerTripleBufferingDisabled, "Disabling Triple Buffering");

    const size_t defaultListSize = MAX_LAYERS;
    auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
    mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;

    property_get("debug.sf.early_phase_offset_ns", value, "0");
    const int earlyWakeupOffsetOffsetNs = atoi(value);
    ALOGI_IF(earlyWakeupOffsetOffsetNs != 0, "Enabling separate early offset");
    mVsyncModulator.setPhaseOffsets(sfVsyncPhaseOffsetNs - earlyWakeupOffsetOffsetNs,
            sfVsyncPhaseOffsetNs);

	//我們應該讀取'persist.sys.sf ',color_saturation‘這
	//但是由于/data可能被加密,我們需要等到vold之后
	//讀取屬性屬性是
	//在啟動影片之后讀取
    if (useTrebleTestingOverride()) {
        //如果沒有覆寫SurfaceFlinger就不能連接到HIDL
        //艙單上沒有列出的服務,被認為是
        //從set服務名派生設定,但是它
        //如果使用的名稱不是'default',則是易碎的
        //用于以后的生產目的,
        setenv("TREBLE_TESTING_OVERRIDE", "true", true);
    }
}

Surfaceflinger實體化實作如下特點:

  • 初始化了vsyncPhaseOffsetNs,sfVsyncPhaseOffsetNs兩個相位差,分別是指app的以及sf的相位差,關于相位差后面在學習
  • 設定Surfaceflinger的渲染方向,是哪一個角度
  • mPrimaryDispSync 主顯示屏信號同步器初始化
  • 根據Android的全域配置,判斷是否需要打開三重緩沖,HWC合成機制

4.5.1 DispSync初始化

void DispSync::init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset) {
    mIgnorePresentFences = !hasSyncFramework;
    mPresentTimeOffset = dispSyncPresentTimeOffset;
    mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);

    // set DispSync to SCHED_FIFO to minimize jitter
    struct sched_param param = {0};
    param.sched_priority = 2;
    if (sched_setscheduler(mThread->getTid(), SCHED_FIFO, &param) != 0) {
        ALOGE("Couldn't set SCHED_FIFO for DispSyncThread");
    }

    reset();
    beginResync();

    if (kTraceDetailedInfo) {
		//如果我們沒有得到現在的柵欄,那么零相位示蹤劑
		//將阻止HW垂直同步事件被關閉,
		//即使我們只是忽略了柵欄,零相位跟蹤也是
		//不需要,因為任何時候有一個事件注冊我們將
		//打開HW垂直同步事件,
        if (!mIgnorePresentFences && kEnableZeroPhaseTracer) {
            mZeroPhaseTracer = std::make_unique<ZeroPhaseTracer>();
            addEventListener("ZeroPhaseTracer", 0, mZeroPhaseTracer.get());
        }
    }
}

在這個程序中初始化了DispSyncThread這個執行緒并且運行起來,并且初始化一些簡單的資料,同時設定這個執行緒調度的優先類為FIFO,相位計算?

4.5.2 圖元佇列調度

因為這里的SurfaceFlinger物件是一個StrongPointer強指標,所以首先會走到RefBase的onFirstRef方法,故

 void SurfaceFlinger::onFirstRef()
{
    mEventQueue->init(this);
}

查看surfaceFlinger.h,發現mEventQueue是MessqgeQueue創建的物件,

 // these are thread safe
    mutable std::unique_ptr<MessageQueue> mEventQueue{std::make_unique<impl::MessageQueue>()};  

檔案路勁/frameworks/native/services/surfaceflinger/MessageQueue.cpp
所以初始化會創建訊息佇列需要的Handler、Looper,

  void MessageQueue::init(const sp<SurfaceFlinger>& flinger) {
    mFlinger = flinger;
    mLooper = new Looper(true);
    mHandler = new Handler(*this);
} 

此處MessageQueue不是常見的訊息佇列,在SurfaceFlinger目錄單獨撰寫,mEventQueue更像是訊息回圈機制的管理者,其中包含了一個looper,在looper中的mMessageEnvelopes這個容器才是真正存盤訊息的地方,
waitMessage主要通過呼叫mLooper的pollOnce方法來監聽訊息

 void MessageQueue::waitMessage() {
    do {
        IPCThreadState::self()->flushCommands();
        int32_t ret = mLooper->pollOnce(-1);
         switch (ret) {
            case Looper::POLL_WAKE:
            case Looper::POLL_CALLBACK:
                continue;
            case Looper::POLL_ERROR:
                ALOGE("Looper::POLL_ERROR");
                continue;
            case Looper::POLL_TIMEOUT:
                // timeout (should not happen)
                continue;
            default:
                // should not happen
                ALOGE("Looper::pollOnce() returned unknown status %d", ret);
                continue;
        }
    } while (true);
}

handler也不是常見的那個Handler,而是Messagequeue中自定義的一個事件處理器,是專門為Surfaceflinger設計的,handler收到訊息,進一步回呼Surfaceflinger中的onMessageReceived,

 void MessageQueue::Handler::handleMessage(const Message& message) {
    switch (message.what) {
        case INVALIDATE:
            android_atomic_and(~eventMaskInvalidate, &mEventMask);
            mQueue.mFlinger->onMessageReceived(message.what);
            break;
        case REFRESH:
            android_atomic_and(~eventMaskRefresh, &mEventMask);
            mQueue.mFlinger->onMessageReceived(message.what);
            break;
    }
}

上面代碼注冊了兩種不同的圖元重繪監聽,一個是invalidate區域重繪,一個是refresh重新重繪,最后都會回呼到Surfaceflinger的onMessageReceived中,換句話說,每當我們需要圖元重繪的時候,就會通過mEventQueue的post方法,把資料異步加載到Handler中進行重繪,

在這里插入圖片描述

4.6 Surfaceflinger初始化

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

    ALOGI("Phase offest NS: %" PRId64 "", vsyncPhaseOffsetNs);

    Mutex::Autolock _l(mStateLock);

    // start the EventThread當應用和sf的vsync偏移量一致時,則只創建一個EventThread執行緒
    // std::make_unique比較新,它是在c++14里加入標準庫的,
    //template<typename T, typename... Ts>
    //std::unique_ptr<T> make_unique(Ts&&... params)
    //{
    //return std::unique_ptr<T>(new T(std::forward<Ts>(params)...));
    //}
    //make_unique只是把引數完美轉發給,要創建物件的建構式,再從new出來的原生指標,構造std::unique_ptr,
    //這種形式的函式,不支持陣列和自定義洗掉器,
    //make_unique函式:把任意集合的引數,完美轉發給動態分配物件的建構式,
    //然后回傳一個指向那物件的智能指標,
    mEventThreadSource =
            std::make_unique<DispSyncSource>(&mPrimaryDispSync, SurfaceFlinger::vsyncPhaseOffsetNs,
                                             true, "app");
    mEventThread = std::make_unique<impl::EventThread>(mEventThreadSource.get(),
                                                       [this]() { resyncWithRateLimit(); },
                                                       impl::EventThread::InterceptVSyncsCallback(),
                                                       "appEventThread");
    mSfEventThreadSource =
            std::make_unique<DispSyncSource>(&mPrimaryDispSync,
                                             SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf");

    mSFEventThread =
            std::make_unique<impl::EventThread>(mSfEventThreadSource.get(),
                                                [this]() { resyncWithRateLimit(); },
                                                [this](nsecs_t timestamp) {
                                                    mInterceptor->saveVSyncEvent(timestamp);
                                                },
                                                "sfEventThread");
    //設定EventThread
    mEventQueue->setEventThread(mSFEventThread.get());
    mVsyncModulator.setEventThread(mSFEventThread.get());

    //獲取RenderEngine引擎,渲染引擎,通過工廠模式實作對于不同版本的OpenGL分裝. 詳細實作下面接下來再進行分析
    getBE().mRenderEngine =
            RE::impl::RenderEngine::create(HAL_PIXEL_FORMAT_RGBA_8888,
                                           hasWideColorDisplay
                                                   ? RE::RenderEngine::WIDE_COLOR_SUPPORT
                                                   : 0);
    LOG_ALWAYS_FATAL_IF(getBE().mRenderEngine == nullptr, "couldn't create RenderEngine");

    LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
            "Starting with vr flinger active is not currently supported.");
    getBE().mHwc.reset(//初始化硬體composer物件, hwcomposer實體化,主要是監聽顯示幕硬體變化, hard抽象層,
            new HWComposer(std::make_unique<Hwc2::impl::Composer>(getBE().mHwcServiceName)));
    //監聽
	getBE().mHwc->registerCallback(this, getBE().mComposerSequenceId);
    //處理任何初始熱插拔和結果顯示更改,
    //該方法第一次進來無效,這是SF重啟發現有螢屏插進來,一般不會走進來
    processDisplayHotplugEventsLocked();
    LOG_ALWAYS_FATAL_IF(!getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY),
            "Registered composer callback but didn't create the default primary display");

    //將默認的顯示GLContext設定為當前,這樣我們就可以創建紋理
    //當我們創建圖層時(可能會在渲染之前發生)
    //第一次進來還沒有鏈接進來的Display的Binder物件,跳過
    getDefaultDisplayDeviceLocked()->makeCurrent();
    //打開vr功能相關模塊
    if (useVrFlinger) {
        auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) {
			//這個回呼函式被vr flinger分派執行緒呼叫,我們
			//需要呼叫signalTransaction(),它需要持有
			//當我們不在主執行緒時mStateLock,收購
			// mStateLock從vr flinger分派執行緒可能觸發一個
			//surface flinger中的死鎖(見b/66916578),因此發布一個訊息
			//改為在主執行緒上處理,
            sp<LambdaMessage> message = new LambdaMessage([=]() {
                ALOGI("VR request display mode: requestDisplay=%d", requestDisplay);
                mVrFlingerRequestsDisplay = requestDisplay;
                signalTransaction();
            });
            postMessageAsync(message);
        };
        mVrFlinger = dvr::VrFlinger::Create(getBE().mHwc->getComposer(),
                getBE().mHwc->getHwcDisplayId(HWC_DISPLAY_PRIMARY).value_or(0),
                vrFlingerRequestDisplayCallback);
        if (!mVrFlinger) {
            ALOGE("Failed to start vrflinger");
        }
    }

    mEventControlThread = std::make_unique<impl::EventControlThread>(
            [this](bool enabled) { setVsyncEnabled(HWC_DISPLAY_PRIMARY, enabled); });

    // //初始化繪圖狀態
    mDrawingState = mCurrentState;

    //初始化顯示設備,以Event事件形式發送
    initializeDisplays();

    getBE().mRenderEngine->primeCache();

    //通知本地圖形api是否支持當前的時間戳:
    if (getHwComposer().hasCapability(
            HWC2::Capability::PresentFenceIsNotReliable)) {
        mStartPropertySetThread = new StartPropertySetThread(false);
    } else {
        mStartPropertySetThread = new StartPropertySetThread(true);
    }

    if (mStartPropertySetThread->Start() != NO_ERROR) {
        ALOGE("Run StartPropertySetThread failed!");
    }

    mLegacySrgbSaturationMatrix = getBE().mHwc->getDataspaceSaturationMatrix(HWC_DISPLAY_PRIMARY,
            Dataspace::SRGB_LINEAR);

    ALOGV("Done initializing");
}

在init程序中初始化不少重要的物件:

  • DispSyncSource 的初始化
  • EventThread 的初始化
  • EventQueue 監聽初始化
  • RenderEngine渲染引擎的初始化
  • 初始化HWComposer監聽顯示幕硬體變化
  • EventControlThread初始化
  • 初始化和鏈接DisplayService

4.6.1 EventThread|DispSyncSource的初始化

檔案路徑:/frameworks/native/services/surfaceflinger/EventThread.cpp

mEventThreadSource =std::make_unique<DispSyncSource>(&mPrimaryDispSync, SurfaceFlinger::vsyncPhaseOffsetNs,true, "app");
mEventThread = std::make_unique<impl::EventThread>(mEventThreadSource.get(),[this]() { resyncWithRateLimit(); },impl::EventThread::InterceptVSyncsCallback(),"appEventThread");

能看到實際上mEventThread本質上就是一個DisSyncSource物件,我們看看他的建構式:

class DispSyncSource final : public VSyncSource, private DispSync::Callback {
public:
    DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
        const char* name) :
            mName(name),
            mValue(0),
            mTraceVsync(traceVsync),
            mVsyncOnLabel(String8::format("VsyncOn-%s", name)),
            mVsyncEventLabel(String8::format("VSYNC-%s", name)),
            mDispSync(dispSync),
            mCallbackMutex(),
            mVsyncMutex(),
            mPhaseOffset(phaseOffset),
            mEnabled(false) {}

    ~DispSyncSource() override = default;
    ...

在這個中設定兩個關鍵引數,一個是上面初始化好的DispSync顯示同步信號,一個是app的DispSyncSource(相位差)

4.6.2 EventThread實體化

其邏輯流程大概如下:
在這里插入圖片描述

把app的DispSyncSource作為引數,進行實體化

EventThread::EventThread(VSyncSource* src, ResyncWithRateLimitCallback resyncWithRateLimitCallback,
                         InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
      : mVSyncSource(src),
        mResyncWithRateLimitCallback(resyncWithRateLimitCallback),
        mInterceptVSyncsCallback(interceptVSyncsCallback) {
    for (auto& event : mVSyncEvent) {
        event.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
        event.header.id = 0;
        event.header.timestamp = 0;
        event.vsync.count = 0;
    }

    mThread = std::thread(&EventThread::threadMain, this);

    pthread_setname_np(mThread.native_handle(), threadName);

    pid_t tid = pthread_gettid_np(mThread.native_handle());

    // Use SCHED_FIFO to minimize jitter
    constexpr int EVENT_THREAD_PRIORITY = 2;
    struct sched_param param = {0};
    param.sched_priority = EVENT_THREAD_PRIORITY;
    if (pthread_setschedparam(mThread.native_handle(), SCHED_FIFO, &param) != 0) {
        ALOGE("Couldn't set SCHED_FIFO for EventThread");
    }

    set_sched_policy(tid, SP_FOREGROUND);
}

能夠看到在這個程序中做的事情和DispSync的方法很相似,首先實體化一個內部執行緒,并且設定這個執行緒的啟動后的方法,以及設定該執行緒為FIFO策略并且設定為前臺執行緒,使用更高的優先級,

void EventThread::threadMain() NO_THREAD_SAFETY_ANALYSIS {
    std::unique_lock<std::mutex> lock(mMutex);
    while (mKeepRunning) {
        DisplayEventReceiver::Event event;
        Vector<sp<EventThread::Connection> > signalConnections;
        signalConnections = waitForEventLocked(&lock, &event);

        // dispatch events to listeners...
        const size_t count = signalConnections.size();
        for (size_t i = 0; i < count; i++) {
            const sp<Connection>& conn(signalConnections[i]);
            // now see if we still need to report this event
            status_t err = conn->postEvent(event);
            if (err == -EAGAIN || err == -EWOULDBLOCK) {
                // The destination doesn't accept events anymore, it's probably
                // full. For now, we just drop the events on the floor.
                // FIXME: Note that some events cannot be dropped and would have
                // to be re-sent later.
                // Right-now we don't have the ability to do this.
                ALOGW("EventThread: dropping event (%08x) for connection %p", event.header.type,
                      conn.get());
            } else if (err < 0) {
                // handle any other error on the pipe as fatal. the only
                // reasonable thing to do is to clean-up this connection.
                // The most common error we'll get here is -EPIPE.
                removeDisplayEventConnectionLocked(signalConnections[i]);
            }
        }
    }
}

能看到在這個程序中,會通過waitForEventLocked阻塞等待外部鏈接進來的EventThread的Connection,鏈接進來,一般是應用程式注冊了Choreographer之后,就會注冊DisplayEventReceiver,此時會對應DisplayEventReceiverDispatch一個Looper的callback,同時會通過Binder把當前為當前物件注冊一個Connect給Surfaceflinger行程的EventThread,當喚醒之后,經過檢測將會呼叫postEvent把同步信號同步給Ap應用,

在waitForEventLocked等待回圈的程序中,每一次同步信號的發出都會呼叫建構式進來的回呼interceptVSyncsCallback,也就是:

resyncWithRateLimit();

同時會根據條件判斷,當前是否打開同步信號,

4.6.3 Surfaceflinger的EventThread初始化

 mSfEventThreadSource =
            std::make_unique<DispSyncSource>(&mPrimaryDispSync,
                                             SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf");

    mSFEventThread =
            std::make_unique<impl::EventThread>(mSfEventThreadSource.get(),
                                                [this]() { resyncWithRateLimit(); },
                                                [this](nsecs_t timestamp) {
                                                    mInterceptor->saveVSyncEvent(timestamp);
                                                },
                                                "sfEventThread");
    //設定EventThread
    mEventQueue->setEventThread(mSFEventThread.get());
    mVsyncModulator.setEventThread(mSFEventThread.get());

Surfaceflinger的EventThread監聽的是本行程的,其先去看看mEventQueue這個Surfaceflinger中的MessageQueue的setEventThread方法

void MessageQueue::setEventThread(android::EventThread* eventThread) {
    if (mEventThread == eventThread) {
        return;
    }

    if (mEventTube.getFd() >= 0) {
        mLooper->removeFd(mEventTube.getFd());
    }

    mEventThread = eventThread;
    mEvents = eventThread->createEventConnection();
    mEvents->stealReceiveChannel(&mEventTube);
    mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
                   this);
}

在這個程序中能看到和Ap應用極其相似的邏輯,首先通過eventThread的createEventConnection創建一個Connection,EventThread可以從waitForEventLocked能夠監聽到這個鏈接,

sp<BnDisplayEventConnection> EventThread::createEventConnection() const {
    return new Connection(const_cast<EventThread*>(this));
}
EventThread::Connection::Connection(EventThread* eventThread)
      : count(-1), mEventThread(eventThread), mChannel(gui::BitTube::DefaultSize) {}

EventThread::Connection::~Connection() {
	//這里什么都不做——清理將自動發生
	//當主執行緒喚醒時

}

void EventThread::Connection::onFirstRef() {
    //注意:mEventThread對我們沒有強參考
    mEventThread->registerDisplayEventConnection(this);
}

初始化了一個BitTube物件,以及把當前的Connection注冊到EventThread中,讓waitForEvent可以監聽到新的監聽進來了,

4.6.4 監聽

status_t EventThread::registerDisplayEventConnection(
        const sp<EventThread::Connection>& connection) {
    std::lock_guard<std::mutex> lock(mMutex);
    mDisplayEventConnections.add(connection);
    mCondition.notify_all();
    return NO_ERROR;
}

4.6.5 BitTube

封裝過的socketpair,是一個全雙工的通道,可以從1號寫入,0號讀取,也可以從0號寫入,1號讀取,在BitTube中設定了0是接受,1是寫入其實就和管道一樣的,
檔案路徑:/frameworks/native/libs/gui/BitTube.cpp

static const size_t DEFAULT_SOCKET_BUFFER_SIZE = 4 * 1024;

BitTube::BitTube(size_t bufsize) {
    init(bufsize, bufsize);
}

BitTube::BitTube(DefaultSizeType) : BitTube(DEFAULT_SOCKET_BUFFER_SIZE) {}

BitTube::BitTube(const Parcel& data) {
    readFromParcel(&data);
}

void BitTube::init(size_t rcvbuf, size_t sndbuf) {
    int sockets[2];
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) {
        size_t size = DEFAULT_SOCKET_BUFFER_SIZE;
        setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));
        setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf));
        // since we don't use the "return channel", we keep it small...
        setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
        setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
        fcntl(sockets[0], F_SETFL, O_NONBLOCK);
        fcntl(sockets[1], F_SETFL, O_NONBLOCK);
        mReceiveFd.reset(sockets[0]);
        mSendFd.reset(sockets[1]);
    } else {
        mReceiveFd.reset();
        ALOGE("BitTube: pipe creation failed (%s)", strerror(errno));
    }
}

4.6.6 事件監聽程序

接著呼叫EventThread::Connection的stealReceiveChannel

status_t EventThread::Connection::stealReceiveChannel(gui::BitTube* outChannel) {
     //重置這個位管的接收檔案描述符為receiveFd
    outChannel->setReceiveFd(mChannel.moveReceiveFd());
    return NO_ERROR;
}

當waitForEvent接觸等待后,將會呼叫Connection的postEvent方法:
檔案路徑:/frameworks/native/services/surfaceflinger/EventThread.cpp

status_t EventThread::Connection::postEvent(const DisplayEventReceiver::Event& event) {
    ssize_t size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);
    return size < 0 ? status_t(size) : status_t(NO_ERROR);
}

檔案路徑:/frameworks/native/libs/gui/DisplayEventReceiver.cpp

ssize_t DisplayEventReceiver::sendEvents(gui::BitTube* dataChannel,
        Event const* events, size_t count)
{
    return gui::BitTube::sendObjects(dataChannel, events, count);
}

這樣就完成了從發送端到接收端的程序監聽,當有資料喚醒時候就會進入到MessageQueue的回呼中,
檔案路徑:/frameworks/native/services/surfaceflinger/MessageQueue.cpp

int MessageQueue::cb_eventReceiver(int fd, int events, void* data) {
    MessageQueue* queue = reinterpret_cast<MessageQueue*>(data);
    return queue->eventReceiver(fd, events);
}

int MessageQueue::eventReceiver(int /*fd*/, int /*events*/) {
    ssize_t n;
    DisplayEventReceiver::Event buffer[8];
    while ((n = DisplayEventReceiver::getEvents(&mEventTube, buffer, 8)) > 0) {
        for (int i = 0; i < n; i++) {
            if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
                mHandler->dispatchInvalidate();
                break;
            }
        }
    }
    return 1;
}

此時MessageQueue就會呼叫Handler中的dispatchInvalidate,也就呼叫到了Surfaceflinger的onMessageReceived回呼,

4.7 RenderEngine初始化

//獲取RenderEngine引擎,渲染引擎,通過工廠模式實作對于不同版本的OpenGL分裝. 詳細實作下面接下來再進行分析
getBE().mRenderEngine =RE::impl::RenderEngine::create(HAL_PIXEL_FORMAT_RGBA_8888,hasWideColorDisplay?RE::RenderEngine::WIDE_COLOR_SUPPORT:0);

getBE其實是SurfaceflingerBE,它控制所有硬體介面,理解為Surfaceflinger縮影,Surfaceflinger是對整個系統的視圖重繪控制,

std::unique_ptr<RenderEngine> RenderEngine::create(int hwcFormat, uint32_t featureFlags) {
    //初始化EGL,作為默認的顯示
    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    if (!eglInitialize(display, nullptr, nullptr)) {
        LOG_ALWAYS_FATAL("failed to initialize EGL");
    }
	//初始化EGL的版本
    GLExtensions& extensions = GLExtensions::getInstance();
    extensions.initWithEGLStrings(eglQueryStringImplementationANDROID(display, EGL_VERSION),
                                  eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS));

    // The code assumes that ES2 or later is available if this extension is
    // supported.
	//選擇處理EGL的配置
    EGLConfig config = EGL_NO_CONFIG;
    if (!extensions.hasNoConfigContext()) {
        config = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
    }
    //初始化EGL背景關系
    EGLint renderableType = 0;
    if (config == EGL_NO_CONFIG) {
        renderableType = EGL_OPENGL_ES2_BIT;
    } else if (!eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType)) {
        LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE");
    }
	//設定GL版本號
    EGLint contextClientVersion = 0;
    if (renderableType & EGL_OPENGL_ES2_BIT) {
        contextClientVersion = 2;
    } else if (renderableType & EGL_OPENGL_ES_BIT) {
        contextClientVersion = 1;
    } else {
        LOG_ALWAYS_FATAL("no supported EGL_RENDERABLE_TYPEs");
    }
    //獲取屬性
    std::vector<EGLint> contextAttributes;
    contextAttributes.reserve(6);
    contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
    contextAttributes.push_back(contextClientVersion);
    bool useContextPriority = overrideUseContextPriorityFromConfig(extensions.hasContextPriority());
    if (useContextPriority) {
        contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
        contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
    }
    contextAttributes.push_back(EGL_NONE);
	//初始化EGL背景關系
    EGLContext ctxt = eglCreateContext(display, config, nullptr, contextAttributes.data());

    // if can't create a GL context, we can only abort.
    LOG_ALWAYS_FATAL_IF(ctxt == EGL_NO_CONTEXT, "EGLContext creation failed");

    // now figure out what version of GL did we actually get
    // NOTE: a dummy surface is not needed if KHR_create_context is supported

    EGLConfig dummyConfig = config;
    if (dummyConfig == EGL_NO_CONFIG) {
        dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
    }
    EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE};
	//創建一個dump的Surface
    EGLSurface dummy = eglCreatePbufferSurface(display, dummyConfig, attribs);
    LOG_ALWAYS_FATAL_IF(dummy == EGL_NO_SURFACE, "can't create dummy pbuffer");
	//把EGLDisplay和dump鏈接起來
    EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt);
    LOG_ALWAYS_FATAL_IF(!success, "can't make dummy pbuffer current");

    extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER),
                                 glGetString(GL_VERSION), glGetString(GL_EXTENSIONS));

    GlesVersion version = parseGlesVersion(extensions.getVersion());

    // initialize the renderer while GL is current

    std::unique_ptr<RenderEngine> engine;
    switch (version) {
        case GLES_VERSION_1_0:
        case GLES_VERSION_1_1:
            LOG_ALWAYS_FATAL("SurfaceFlinger requires OpenGL ES 2.0 minimum to run.");
            break;
        case GLES_VERSION_2_0:
        case GLES_VERSION_3_0:
            engine = std::make_unique<GLES20RenderEngine>(featureFlags);
            break;
    }
	//設定EGLDisplay
    engine->setEGLHandles(display, config, ctxt);

    ALOGI("OpenGL ES informations:");
    ALOGI("vendor    : %s", extensions.getVendor());
    ALOGI("renderer  : %s", extensions.getRenderer());
    ALOGI("version   : %s", extensions.getVersion());
    ALOGI("extensions: %s", extensions.getExtensions());
    ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize());
    ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims());
    //把EGLDisplay設定為當前OpenGL es的環境
    eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    eglDestroySurface(display, dummy);

    return engine;
}
  • 初始化EGLDisplay ,獲得當前系統默認的顯示屏物件
  • 初始化EGL的版本
  • chooseEglConfig選擇處理EGL的配置,通過eglGetConfigs查找可回傳的EGL配置的數目,接著呼叫eglChooseConfig從所有配置項中得到最為推薦的配置陣列,最后通過遍歷查詢,把系統中符合當前配置項中所有的配置都添加進來
  • eglCreateContext 初始化EGL背景關系
  • 設定GL版本號
  • eglCreatePbufferSurface創建一個dump的Surface,開辟一段可以快取幀資料的空間,并用eglMakeCurrent把EGLDisplay和dump鏈接起來,其目的就是為了檢查OpenGL es是否有問題,
  • setEGLHandles 設定EGLDisplay,背景關系和配置為全域配置
  • eglMakeCurrent 把EGLDisplay設定為當前OpenGL es的環境,銷毀dump這個Surface

4.8 HWComposer初始化

它聯通的硬體抽象層Conposer,他是被HWComposer直接使用的,HWComposer除了直接管理Composer以外還負責VSync信號的生成和控制,

    getBE().mHwc.reset(//初始化硬體composer物件, hwcomposer實體化,主要是監聽顯示幕硬體變化, hard抽象層,
            new HWComposer(std::make_unique<Hwc2::impl::Composer>(getBE().mHwcServiceName)));

能看到HWComposer中傳入一個Hwc2::impl::Composer物件,先看看這個物件:檔案路徑:/frameworks/native/services/surfaceflinger/DisplayHardware/ComposerHal.cpp

Composer::Composer(const std::string& serviceName)
    : mWriter(kWriterInitialSize),
      mIsUsingVrComposer(serviceName == std::string("vr"))
{
    mComposer = V2_1::IComposer::getService(serviceName);

    if (mComposer == nullptr) {
        LOG_ALWAYS_FATAL("failed to get hwcomposer service");
    }

    mComposer->createClient(
            [&](const auto& tmpError, const auto& tmpClient)
            {
                if (tmpError == Error::NONE) {
                    mClient = tmpClient;
                }
            });
    if (mClient == nullptr) {
        LOG_ALWAYS_FATAL("failed to create composer client");
    }

    // 2.2 support is optional
    sp<IComposer> composer_2_2 = IComposer::castFrom(mComposer);
    if (composer_2_2 != nullptr) {
        mClient_2_2 = IComposerClient::castFrom(mClient);
        LOG_ALWAYS_FATAL_IF(mClient_2_2 == nullptr, "IComposer 2.2 did not return IComposerClient 2.2");
    }

    if (mIsUsingVrComposer) {
        sp<IVrComposerClient> vrClient = IVrComposerClient::castFrom(mClient);
        if (vrClient == nullptr) {
            LOG_ALWAYS_FATAL("failed to create vr composer client");
        }
    }
}

能看到Composer物件中又會持有一個mComposer物件,這個物件可以暫且理解類似為Binder,從抽象層(hal)服務端傳送過來的IComposer介面物件,之后所有要和硬體層進行互動,只需要操作這個IComposer物件即可,接著呼叫IComposer的createClient創建開一個Client物件,如果里面有2.2版本的IComposer物件則會把2.1版本的IComposer轉化過去,這樣軟體層Composer就和硬體抽象層的Composer對應起來,等待HWComposer的操作,

4.8.1 HWComposer初始化

HWComposer::HWComposer(std::unique_ptr<android::Hwc2::Composer> composer)
      : mHwcDevice(std::make_unique<HWC2::Device>(std::move(composer))) {}

初始化一個HWC2::Device物件,hal層的對應的物件,

4.8.2 HWComposer監聽

   //監聽
	getBE().mHwc->registerCallback(this, getBE().mComposerSequenceId);

注冊SF的監聽到HWC中,
檔案路徑:/frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer.cpp

void HWComposer::registerCallback(HWC2::ComposerCallback* callback,
                                  int32_t sequenceId) {
    mHwcDevice->registerCallback(callback, sequenceId);
}

繼續,檔案路徑:/frameworks/native/services/surfaceflinger/DisplayHardware/HWC2.cpp

void Device::registerCallback(ComposerCallback* callback, int32_t sequenceId) {
    if (mRegisteredCallback) {
        ALOGW("Callback already registered. Ignored extra registration "
                "attempt.");
        return;
    }
    mRegisteredCallback = true;
    sp<ComposerCallbackBridge> callbackBridge(
            new ComposerCallbackBridge(callback, sequenceId));
    mComposer->registerCallback(callbackBridge);
}

能看到HWC會借助一callbackBridge物件把物件注冊到hal層中進行監聽…

4.8 Surfaceflinger的run

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/243334.html

標籤:其他

上一篇:appium啟動后報錯

下一篇:GreenDao 3.0 簡介、使用及踩坑

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more