美文网首页android_displaySurfaceFlinger
Android 重学系列 SurfaceFlinger 的HAL

Android 重学系列 SurfaceFlinger 的HAL

作者: yjy239 | 来源:发表于2020-01-21 15:47 被阅读0次

    前言

    上一篇文章我们研究了SF的初始化。但是还有一个很大也是核心的模块没有聊到,那就是HAL层对应的初始化。什么是HAL层,有简单的话来讲就是硬件驱动和软件之间的中间层,为了更好的兼容Android系统而诞生。

    在Android 8.0之后会涉及应用开发及其少接触的一个新类型文件.hal文件。本质上.hal和.aidl文件十分相似,设计初衷和aidl也很相似。aidl为的是Android跨进程通信,而.hal则是为了让android软件层和硬件层通信而做的隔离,因此这种交互方式又称为HIDL。

    闲话不多说,我们先来看看hal文件的用法之后,再去看看SF中IComposer,IComposerClient中都做了什么事情。

    如果遇到什么问题可以来本文讨论:https://www.jianshu.com/p/8e29c3d9b27a

    正文

    在Android 8.0之后,Google为了各大手机厂商的方便,执行了一个名为Treble计划,其目的就是为了让各大手机厂商和硬件商能够在最小代价在Android系统升级的时候,能快速更新硬件相关的特性。

    hal的升级历程.png

    大致可以把hal层的历史分为如下3个时期:

    • 1.Legacy Hal:Android 8.0 之前版本的 HAL 都是编译成 so,然后动态链接到各个 frameworks service 中去。

    • 2.Passthrough Hal:该模式是为了兼容旧版的 HAL,旧版 HAL 实现仍以动态库的方式提供,只是 binder service 链接了动态库 HAL 实现,即 binder service 通过 hw_get_module 链接了旧版的 hal 实现,而用户端通过与 binder service IPC 通信,间接实现了与旧版 HAL 的交互。

    • 3.Binderized HAL:HAL 与 用户调用在不同的进程中,HAL 被写成 binder service,而用户接口如 frameworks 作为 binder client 通过 IPC 机制实现跨进程接口调用。这个是 Google 的最终设计目标。

    能看到,从历史来看,整个hal层的隔离越来越厉害,越来越接近AIDL的方向设计。因此,Google选择和AIDL的方式,构建一个hal文件,让硬件商和系统只需要关注暴露在hal文件中接口的逻辑即可。

    注意一下,这里面的binder 并非是我之前分析的那个Binder,而是hwBinder,不过代码和原理是一摸一样。不过前者负责进程间通信,hwBinder则负责硬件进程和上层进程的通信。

    这样设计其实很简单,如果阅读过我的Binder源码解析就能明白,Binder中有一套复杂的事务传输逻辑,如果把硬件驱动也接进来,就没办法达到软件可以快速响应硬件回调或者软件调用硬件。

    为了更好的理解HIDL语言,我们可以完全把它当作AIDL这种语言进行类比学习。

    本文重点不是hidl的原理,只是作为基础知识和大家介绍。具体的细节,有机会再和大家聊聊。

    hal文件介绍

    我们就以IComposer.hal为例子,先来看看2.1版本。
    文件:/hardware/interfaces/graphics/composer/2.1/IComposer.hal

    package android.hardware.graphics.composer@2.1;
    
    import IComposerClient;
    
    interface IComposer {
    
        enum Capability : int32_t {
            INVALID = 0,
    
            SIDEBAND_STREAM = 1,
    
            SKIP_CLIENT_COLOR_TRANSFORM = 2,
    
            PRESENT_FENCE_IS_NOT_RELIABLE = 3,
        };
    
        @entry
        @exit
        @callflow(next="*")
        getCapabilities() generates (vec<Capability> capabilities);
    
        @entry
        @exit
        @callflow(next="*")
        dumpDebugInfo() generates (string debugInfo);
    
        @entry
        @callflow(next="*")
        createClient() generates (Error error, IComposerClient client);
    };
    

    能看到在hal文件中,只能注意的是,我上一篇文章聊到的createClient方法,创建一个IComposerClient对象返回上层。

    能看到实际上和aidl十分相似不是吗。当我们把它类比成aidl就特别好理解了。一般的,编写了一个hal文件之后,就需要使用hidl-gen工具,类似aidl一样生成一个真正的cpp文件,里面包含着真正的跨进程通信逻辑,以及相关的接口文件。

    当我们写好hal文件之后,并且通过hidl-gen生成的文件中实现接口后,写好Android.bp文件。大致上能得到类似的目录:


    image.png

    当然这是composer 2.2版本,不过从大体设计看来差距不是很大。

    一般的会在default子目录编写好入口方法:


    image.png

    能看到2.2版本下只剩下一个service.cpp。我们再看看2.1版本又是如何:


    image.png

    能看到2.1版本中,多了一个cpp文件passthrough。顾名思义,passthrough就是直通模式,service就是binder service模式。
    文件:/hardware/interfaces/graphics/composer/2.1/default/Android.bp

    cc_library_shared {
        name: "android.hardware.graphics.composer@2.1-impl",
        defaults: ["hidl_defaults"],
        vendor: true,
        relative_install_path: "hw",
        srcs: ["passthrough.cpp"],
        header_libs: [
            "android.hardware.graphics.composer@2.1-passthrough",
        ],
        shared_libs: [
            "android.hardware.graphics.composer@2.1",
            "android.hardware.graphics.mapper@2.0",
            "libbase",
            "libcutils",
            "libfmq",
            "libhardware",
            "libhidlbase",
            "libhidltransport",
            "liblog",
            "libsync",
            "libutils",
            "libhwc2on1adapter",
            "libhwc2onfbadapter",
        ],
        cflags: [
            "-DLOG_TAG=\"ComposerHal\""
        ],
    }
    
    cc_binary {
        name: "android.hardware.graphics.composer@2.1-service",
        defaults: ["hidl_defaults"],
        vendor: true,
        relative_install_path: "hw",
        srcs: ["service.cpp"],
        init_rc: ["android.hardware.graphics.composer@2.1-service.rc"],
        shared_libs: [
            "android.hardware.graphics.composer@2.1",
            "libbinder",
            "libhidlbase",
            "libhidltransport",
            "liblog",
            "libsync",
            "libutils",
        ],
    }
    

    能看到这个bp文件中,有两个cc编译工具,一个是以passthrough.cpp为入口,一个是以service.cpp为入口。也就是说,不同的模式启动Composer,将会打包进不同的入口。

    值得注意的一点是,在share_libs一行中已经打包进了实现的so文件android.hardware.graphics.composer@2.1 以及 图元申请工具android.hardware.graphics.mapper@2.0
    文件:/hardware/interfaces/graphics/composer/2.1/Android.bp

    hidl_interface {
        name: "android.hardware.graphics.composer@2.1",
        root: "android.hardware",
        vndk: {
            enabled: true,
        },
        srcs: [
            "types.hal",
            "IComposer.hal",
            "IComposerCallback.hal",
            "IComposerClient.hal",
        ],
        interfaces: [
            "android.hardware.graphics.common@1.0",
            "android.hidl.base@1.0",
        ],
        types: [
            "Error",
        ],
        gen_java: false,
    }
    

    就能看到这个时候就看是引入了我们之前写入的hal文件。在整个Composer的HAL层包含了三个文件,一个在Composer中的是IComposer对象,一个是IComposerClient对象,还有一个是实现了IComposerCallback进行监听刷新屏幕热插拔的ComposerCallbackBridge。全部都囊括在内。

    当我们选择的是直通模式,将会到下面这个android.hardware.graphics.composer@2.1-passthrough实现中,而这个对应的bp如下:
    文件:/hardware/interfaces/graphics/composer/2.1/utils/passthrough/Android.bp

    cc_library_headers {
        name: "android.hardware.graphics.composer@2.1-passthrough",
        defaults: ["hidl_defaults"],
        vendor: true,
        shared_libs: [
            "libhardware",
            "libhwc2on1adapter",
            "libhwc2onfbadapter",
        ],
        export_shared_lib_headers: [
            "libhardware",
            "libhwc2on1adapter",
            "libhwc2onfbadapter",
        ],
        header_libs: [
            "android.hardware.graphics.composer@2.1-hal",
        ],
        export_header_lib_headers: [
            "android.hardware.graphics.composer@2.1-hal",
        ],
        export_include_dirs: ["include"],
    }
    

    能看到进一步的引入了hal,以及compser2.2转2.1的adapter等。值得注意的是export_include_dirs这个命令,这个命令是指把这个目录下的头文件全部引入到该模块中,而在这个文件夹中,就是hal硬件抽象层的实现代码。


    image.png

    而这两个文件就是Composer在hal中passthrough模式进入到具体业务的入口。

    最后,我们需要在下面如同应用程序注册四大组建一样,注册到Android系统的xml中:
    文件:/device/linaro/hikey/manifest.xml

        <hal format="hidl">
            <name>android.hardware.graphics.composer</name>
            <transport arch="32+64">passthrough</transport>
            <version>2.1</version>
            <interface>
                <name>IComposer</name>
                <instance>default</instance>
            </interface>
        </hal>
    

    能看到的是hikey海思就是这么注册composer的,同时使用的还是passthrough模式。

    当然,还有其他的如Google给的案例:

        <hal format="hidl">
            <name>android.hardware.graphics.composer</name>
            <transport>hwbinder</transport>
            <version>2.1</version>
            <interface>
                <name>IComposer</name>
                <instance>default</instance>
            </interface>
          </hal>
    

    这里则是使用Binder的方式注册hal层逻辑。

    别忘了最后编写一个rc文件,让init进程解析运行起来:
    文件:/hardware/interfaces/graphics/composer/2.1/default/android.hardware.graphics.composer@2.1-service.rc

    service vendor.hwcomposer-2-1 /vendor/bin/hw/android.hardware.graphics.composer@2.1-service
        class hal animation
        user system
        group graphics drmrpc
        capabilities SYS_NICE
        writepid /dev/cpuset/system-background/tasks
    
    on property:init.svc.surfaceflinger=stopped
        restart vendor.hwcomposer-2-1
    
    

    其实了解这么多就可以了,如果想要全面的了解hidl的使用,不妨阅读下面这片文章:

    如果想要探索hwBinder 进程service的方式是如何把Compser hal进程注册到hwServiceManager,又是如何找到对应的进程的,不妨看看下面这篇文章,写的挺好的:

    当我们有了一定的了解之后,我们可以进行对Composer的HAL进行解析。无论是直通模式还是binder service模式,只是启动方式不一样而已,不影响我们研究整个Composer 的HAL核心机制。

    本文就以直通模式来和大家聊聊,其中的原理。

    小结 hidl的启动与注册

    简单的总结一下,Hal进程的启动和HIDL服务注册的原理:
    还记得获得IComposer服务的方式如下:

    mComposer = V2_1::IComposer::getService(serviceName);
    

    通过getService获取。这个函数做的事情有如下几件事情:

    • 1.先通过hwservicemanager 查询已经从manifest解析好的数据,先检查该服务需要以哪种形式启动的也就是Transport类型,是hwbinder的绑定模式还是passthrough的直通模式。

    • 2.当为hwbinder模式时候,将会从hwservicemanager查询服务

    • 3.当为passthrough模式时候,将会从PassthroughServiceManager获取服务

    • 4.如果是passthrough启动,则会先先从系统目录下查找有没有对应的so,接着通过dlopen打开so,并用dlsym查找HIDL_FETCH_I+interface的名字,也就是HIDL_FETCH_IComposer方法获取IComposer对象,并执行起来。

    • 5.拿到IComposer之后,就会注册到hwservicemanager

    HAL passthrough模式的启动入口

    我们先来看IComposer 2.1版本:
    文件:/hardware/interfaces/graphics/composer/2.1/default/passthrough.cpp

    #include <android/hardware/graphics/composer/2.1/IComposer.h>
    #include <composer-passthrough/2.1/HwcLoader.h>
    
    using android::hardware::graphics::composer::V2_1::IComposer;
    using android::hardware::graphics::composer::V2_1::passthrough::HwcLoader;
    
    extern "C" IComposer* HIDL_FETCH_IComposer(const char* /* name */) {
        return HwcLoader::load();
    }
    

    可以看到本质上是HwcLoader调用了load方法实例化出来的。

    HwcLoader使用IComposer 初始化

    文件:/hardware/interfaces/graphics/composer/2.1/utils/passthrough/include/composer-passthrough/2.1/HwcLoader.h

    static IComposer* load() {
            const hw_module_t* module = loadModule();
            if (!module) {
                return nullptr;
            }
    
            auto hal = createHalWithAdapter(module);
            if (!hal) {
                return nullptr;
            }
    
            return createComposer(std::move(hal));
        }
    

    能从该方法初步看到,IComposer初始化分为三个步骤:

    • 1.loadModule 加载hw_module_t 结构体,这个结构体实际上是一个hal模块的结构体。
    • 2.createHalWithAdapter 通过hw_module_t 初始化hwc2_device_t结构体,让其拥有和顶层通信的能力也就是函数指针,并且适配2.1和2.2版本
    • 3.createComposer 把hwc2_device_t转化为IComposer上传给客户端,也就是SF。

    接下来,我们就围绕着着三个方法,来聊聊整个逻辑。

    loadModule 加载 hw_module_t

    #define HWC_HARDWARE_MODULE_ID "hwcomposer"
    
    #define GRALLOC_HARDWARE_MODULE_ID "gralloc"
    
        // load hwcomposer2 module
        static const hw_module_t* loadModule() {
            const hw_module_t* module;
            int error = hw_get_module(HWC_HARDWARE_MODULE_ID, &module);
            if (error) {
                ALOGI("falling back to gralloc module");
                error = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
            }
    
            if (error) {
                ALOGE("failed to get hwcomposer or gralloc module");
                return nullptr;
            }
    
            return module;
        }
    

    能看到这个过程中会调用hw_get_module尝试获取对应名字的模块hwcomposer,如果获取不到则退化成gralloc,整个机制也就蜕化成HWC还没有出现之前的版本.我们先不去探索失败,我们来看看成功。

    hw_get_module 查找 hw_module_t

    文件:/hardware/libhardware/hardware.c

    int hw_get_module_by_class(const char *class_id, const char *inst,
                               const struct hw_module_t **module)
    {
    
    ...
    
    found:
        /* load the module, if this fails, we're doomed, and we should not try
         * to load a different variant. */
        return load(class_id, path, module);
    }
    
    int hw_get_module(const char *id, const struct hw_module_t **module)
    {
        return hw_get_module_by_class(id, NULL, module);
    }
    

    这个过程会根据传进来的id名字来查找是否已经有如下几个路径下的so,

    #define HAL_LIBRARY_PATH1 "/system/lib64/hw"
    #define HAL_LIBRARY_PATH2 "/vendor/lib64/hw"
    #define HAL_LIBRARY_PATH3 "/odm/lib64/hw"
    #else
    #define HAL_LIBRARY_PATH1 "/system/lib/hw"
    #define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
    #define HAL_LIBRARY_PATH3 "/odm/lib/hw"
    

    找到了则执行load方法:

    static int load(const char *id,
            const char *path,
            const struct hw_module_t **pHmi)
    {
        int status = -EINVAL;
        void *handle = NULL;
        struct hw_module_t *hmi = NULL;
    #ifdef __ANDROID_VNDK__
        const bool try_system = false;
    #else
        const bool try_system = true;
    #endif
    
        /*
         * load the symbols resolving undefined symbols before
         * dlopen returns. Since RTLD_GLOBAL is not or'd in with
         * RTLD_NOW the external symbols will not be global
         */
        if (try_system &&
            strncmp(path, HAL_LIBRARY_PATH1, strlen(HAL_LIBRARY_PATH1)) == 0) {
            /* If the library is in system partition, no need to check
             * sphal namespace. Open it with dlopen.
             */
            handle = dlopen(path, RTLD_NOW);
        } else {
            handle = android_load_sphal_library(path, RTLD_NOW);
        }
        if (handle == NULL) {
            char const *err_str = dlerror();
            ALOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
            status = -EINVAL;
            goto done;
        }
    
        /* Get the address of the struct hal_module_info. */
        const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
        hmi = (struct hw_module_t *)dlsym(handle, sym);
        if (hmi == NULL) {
            ALOGE("load: couldn't find symbol %s", sym);
            status = -EINVAL;
            goto done;
        }
    
        /* Check that the id matches */
        if (strcmp(id, hmi->id) != 0) {
            ALOGE("load: id=%s != hmi->id=%s", id, hmi->id);
            status = -EINVAL;
            goto done;
        }
    
        hmi->dso = handle;
    
        /* success */
        status = 0;
    
        done:
        if (status != 0) {
            hmi = NULL;
            if (handle != NULL) {
                dlclose(handle);
                handle = NULL;
            }
        } else {
            ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",
                    id, path, *pHmi, handle);
        }
    
        *pHmi = hmi;
    
        return status;
    }
    

    如果没有打开,则执行dlopen拿到对应so的句柄,接着同dlsym查找HMI字符,这个字符所指向的内存地址就是我们所说的hw_module_t.换算到现在名字可能是hwcomposer.xx.so

    我们随便挑选一个作为源码解析,就以msm8960为例子:
    文件:/hardware/qcom/display/msm8960/libhwcomposer/hwc.cpp

    static struct hw_module_methods_t hwc_module_methods = {
        open: hwc_device_open
    };
    
    hwc_module_t HAL_MODULE_INFO_SYM = {
        .common = {
            .tag = HARDWARE_MODULE_TAG,
            .version_major = 2,
            .version_minor = 0,
            .id = HWC_HARDWARE_MODULE_ID,
            .name = "Qualcomm Hardware Composer Module",
            .author = "CodeAurora Forum",
            .methods = &hwc_module_methods,
            .dso = 0,
            .reserved = {0},
        }
    };
    

    这样就能找到hwc_module_t对应在底层的结构体。

    createHalWithAdapter 生成hw_device_t

      // create a ComposerHal instance, insert an adapter if necessary
        static std::unique_ptr<hal::ComposerHal> createHalWithAdapter(const hw_module_t* module) {
            bool adapted;
            hwc2_device_t* device = openDeviceWithAdapter(module, &adapted);
            if (!device) {
                return nullptr;
            }
            auto hal = std::make_unique<HwcHal>();
            return hal->initWithDevice(std::move(device), !adapted) ? std::move(hal) : nullptr;
        }
    

    这个过程做了两件事情,第一件事情就是openDeviceWithAdapter初始化hwc2_device_t,第二件事情就是实例化HwcHal对象并且设置hwc2_device_t。

        static hwc2_device_t* openDeviceWithAdapter(const hw_module_t* module, bool* outAdapted) {
            if (module->id && std::string(module->id) == GRALLOC_HARDWARE_MODULE_ID) {
                *outAdapted = true;
                return adaptGrallocModule(module);
            }
    
            hw_device_t* device;
            int error = module->methods->open(module, HWC_HARDWARE_COMPOSER, &device);
            if (error) {
                ALOGE("failed to open hwcomposer device: %s", strerror(-error));
                return nullptr;
            }
    
            int major = (device->version >> 24) & 0xf;
            if (major != 2) {
                *outAdapted = true;
                return adaptHwc1Device(std::move(reinterpret_cast<hwc_composer_device_1*>(device)));
            }
    
            *outAdapted = false;
            return reinterpret_cast<hwc2_device_t*>(device);
        }
    

    能够看到,如果失败则会调用adaptGrallocModule,初始化的是gralloc的hal模块。成果则会调用hw_module_t中的open方法。判断如果当前主版本不是2,则调用adaptHwc1Device适配hw_device_t,最后返回。

    这里需要注意一点hw_device_t,会被向下转型成hwc_composer_device_1对象后传入adaptHwc1Device。其原理和类的继承很相似,因为hwc_composer_device_1包裹了一个hw_device_t。又因为struct是连续分配的空间,这样才能够强转(这种设计在socket系统调用到处都是)。

    typedef struct hwc_composer_device_1 {
       
        struct hw_device_t common;
    
    
        int (*prepare)(struct hwc_composer_device_1 *dev,
                        size_t numDisplays, hwc_display_contents_1_t** displays);
    
        int (*set)(struct hwc_composer_device_1 *dev,
                    size_t numDisplays, hwc_display_contents_1_t** displays);
    
        int (*eventControl)(struct hwc_composer_device_1* dev, int disp,
                int event, int enabled);
    
        union {
          
            int (*blank)(struct hwc_composer_device_1* dev, int disp, int blank);
    
            int (*setPowerMode)(struct hwc_composer_device_1* dev, int disp,
                    int mode);
        };
    
    
        int (*query)(struct hwc_composer_device_1* dev, int what, int* value);
    
    
        void (*dump)(struct hwc_composer_device_1* dev, char *buff, int buff_len);
    
        int (*getDisplayConfigs)(struct hwc_composer_device_1* dev, int disp,
                uint32_t* configs, size_t* numConfigs);
    
        int (*getDisplayAttributes)(struct hwc_composer_device_1* dev, int disp,
                uint32_t config, const uint32_t* attributes, int32_t* values);
    
        int (*getActiveConfig)(struct hwc_composer_device_1* dev, int disp);
    
        int (*setActiveConfig)(struct hwc_composer_device_1* dev, int disp,
                int index);
    
        int (*setCursorPositionAsync)(struct hwc_composer_device_1 *dev, int disp, int x_pos, int y_pos);
    
        void* reserved_proc[1];
    
    } hwc_composer_device_1_t;
    

    在上文能看到此时open的方法,指向的是hwc_device_open函数指针。

    hwc_device_open 初始化hw_device_t
    static int hwc_device_open(const struct hw_module_t* module, const char* name,
                               struct hw_device_t** device)
    {
        int status = -EINVAL;
    
        if (!strcmp(name, HWC_HARDWARE_COMPOSER)) {
            struct hwc_context_t *dev;
            dev = (hwc_context_t*)malloc(sizeof(*dev));
            memset(dev, 0, sizeof(*dev));
    
            //Initialize hwc context
            initContext(dev);
    
            //Setup HWC methods
            dev->device.common.tag          = HARDWARE_DEVICE_TAG;
            dev->device.common.version      = HWC_DEVICE_API_VERSION_1_2;
            dev->device.common.module       = const_cast<hw_module_t*>(module);
            dev->device.common.close        = hwc_device_close;
            dev->device.prepare             = hwc_prepare;
            dev->device.set                 = hwc_set;
            dev->device.eventControl        = hwc_eventControl;
            dev->device.blank               = hwc_blank;
            dev->device.query               = hwc_query;
            dev->device.registerProcs       = hwc_registerProcs;
            dev->device.dump                = hwc_dump;
            dev->device.getDisplayConfigs   = hwc_getDisplayConfigs;
            dev->device.getDisplayAttributes = hwc_getDisplayAttributes;
            *device = &dev->device.common;
            status = 0;
        }
        return status;
    }
    

    能看到在这个方法中,为hw_device_t这个结构体每一个函数指针都真正赋予了其含义,最后所有的hal层执行都会走到hwc.cpp这里。

    这里要注意了version的计算并不是上面那个version_major,而是HWC_DEVICE_API_VERSION_1_2。其实他的计算如下

    define HWC_DEVICE_API_VERSION_1_2  HARDWARE_DEVICE_API_VERSION_2(1, 2, HWC_HEADER_VERSION)
    
    #define HARDWARE_MAKE_API_VERSION_2(maj,min,hdr) \
                ((((maj) & 0xff) << 24) | (((min) & 0xff) << 16) | ((hdr) & 0xffff))
    

    很有误导性,其实是1在高24位,5在低16位,最后一个是头信息。因此是其实1.2版本,而不是版本2。

    所以接下来会走到适配的分之adaptHwc1Device。

    adaptHwc1Device 适配hwc2_device_t

        static hwc2_device_t* adaptHwc1Device(hwc_composer_device_1* device) {
            int minor = (device->common.version >> 16) & 0xf;
            if (minor < 1) {
                ALOGE("hwcomposer 1.0 is not supported");
                device->common.close(&device->common);
                return nullptr;
            }
    
            return new HWC2On1Adapter(device);
        }
    

    能看到小版本小于1则非法,只会适配大于等于的版本,就会生成一个HWC2On1Adapter对象。
    文件:/hardware/interfaces/graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp

    其实这个对象就是hwc2_device_t:

    class HWC2On1Adapter : public hwc2_device_t
    

    我们来看看他的构造函数。

    HWC2On1Adapter::HWC2On1Adapter(hwc_composer_device_1_t* hwc1Device)
      : mDumpString(),
        mHwc1Device(hwc1Device),
        mHwc1MinorVersion(getMinorVersion(hwc1Device)),
        mHwc1SupportsVirtualDisplays(false),
        mHwc1SupportsBackgroundColor(false),
        mHwc1Callbacks(std::make_unique<Callbacks>(*this)),
        mCapabilities(),
        mLayers(),
        mHwc1VirtualDisplay(),
        mStateMutex(),
        mCallbacks(),
        mHasPendingInvalidate(false),
        mPendingVsyncs(),
        mPendingHotplugs(),
        mDisplays(),
        mHwc1DisplayMap()
    {
        common.close = closeHook;
        getCapabilities = getCapabilitiesHook;
        getFunction = getFunctionHook;
        populateCapabilities();
        populatePrimary();
        mHwc1Device->registerProcs(mHwc1Device,
                static_cast<const hwc_procs_t*>(mHwc1Callbacks.get()));
    }
    

    在这里面设置两个很核心的东西一个是getFunctionHook,一个调用了hwc_device_t的registerProcs方法。

    前者是一个模版方法,调用hwc_device_t中方法指针。后者是hal层注册监听驱动的核心逻辑。

    首先看看mHwc1Callbacks实际上是HWC2On1Adapter::Callbacks:

    class HWC2On1Adapter::Callbacks : public hwc_procs_t {
        public:
            explicit Callbacks(HWC2On1Adapter& adapter) : mAdapter(adapter) {
                invalidate = &invalidateHook;
                vsync = &vsyncHook;
                hotplug = &hotplugHook;
            }
    
            static void invalidateHook(const hwc_procs_t* procs) {
                auto callbacks = static_cast<const Callbacks*>(procs);
                callbacks->mAdapter.hwc1Invalidate();
            }
    
            static void vsyncHook(const hwc_procs_t* procs, int display,
                    int64_t timestamp) {
                auto callbacks = static_cast<const Callbacks*>(procs);
                callbacks->mAdapter.hwc1Vsync(display, timestamp);
            }
    
            static void hotplugHook(const hwc_procs_t* procs, int display,
                    int connected) {
                auto callbacks = static_cast<const Callbacks*>(procs);
                callbacks->mAdapter.hwc1Hotplug(display, connected);
            }
    
        private:
            HWC2On1Adapter& mAdapter;
    };
    

    可以看到三个十分熟悉的回调,invalidate,vsync,hotplug。那么其实这个回调就是从底层驱动程序上传第一个回调,之后才有其他的。每个方法又会调用HWC2On1Adapter对应的回调方法。

    记住,在这里面同时把hwc_procs_t三个函数指针invalidate,vsync,hotplug都指向了这个回调中的方法。换句话说所有从底层响应上来,都该类中调用所有的回调,最终都会汇总到这个Callback。

    我们暂时把流程停在这里,稍后让我把监听的接进来,再去更加底层看看是怎么回事?

    HwcHal的初始化

    文件:/hardware/interfaces/graphics/composer/2.1/utils/passthrough/include/composer-passthrough/2.1/HwcHal.h

    namespace android {
    namespace hardware {
    namespace graphics {
    namespace composer {
    namespace V2_1 {
    namespace passthrough {
    
    namespace detail {
    
    using android::hardware::graphics::common::V1_0::ColorMode;
    using android::hardware::graphics::common::V1_0::ColorTransform;
    using android::hardware::graphics::common::V1_0::Dataspace;
    using android::hardware::graphics::common::V1_0::Hdr;
    using android::hardware::graphics::common::V1_0::PixelFormat;
    using android::hardware::graphics::common::V1_0::Transform;
    
    // HwcHalImpl implements V2_*::hal::ComposerHal on top of hwcomposer2
    template <typename Hal>
    class HwcHalImpl : public Hal {
       public:
        virtual ~HwcHalImpl() {
            if (mDevice) {
                hwc2_close(mDevice);
            }
        }
    
    ...
        bool initWithDevice(hwc2_device_t* device, bool requireReliablePresentFence) {
            // we own the device from this point on
            mDevice = device;
    
            initCapabilities();
            if (requireReliablePresentFence &&
                hasCapability(HWC2_CAPABILITY_PRESENT_FENCE_IS_NOT_RELIABLE)) {
                ALOGE("present fence must be reliable");
                mDevice->common.close(&mDevice->common);
                mDevice = nullptr;
                return false;
            }
    
            if (!initDispatch()) {
                mDevice->common.close(&mDevice->common);
                mDevice = nullptr;
                return false;
            }
    
            return true;
        }
    
    ...
    
    }  // namespace detail
    
    using HwcHal = detail::HwcHalImpl<hal::ComposerHal>;
    
    }  // namespace passthrough
    }  // namespace V2_1
    }  // namespace composer
    }  // namespace graphics
    }  // namespace hardware
    }  // namespace android
    

    HwcHalImpl 本质上就是继承hal::ComposerHal,也就是说ComposerHal持有
    将会持有一个hw_device_t结构体,作为真正的操作对象。

    第二点,调用initDispatch,为mDispatch结构体中所有的函数指针都初始化。之后所有调用函数都是是通过mDispatch调用hw_device_t的方法

        struct {
            HWC2_PFN_ACCEPT_DISPLAY_CHANGES acceptDisplayChanges;
            HWC2_PFN_CREATE_LAYER createLayer;
            HWC2_PFN_CREATE_VIRTUAL_DISPLAY createVirtualDisplay;
            HWC2_PFN_DESTROY_LAYER destroyLayer;
            HWC2_PFN_DESTROY_VIRTUAL_DISPLAY destroyVirtualDisplay;
            HWC2_PFN_DUMP dump;
            HWC2_PFN_GET_ACTIVE_CONFIG getActiveConfig;
            HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES getChangedCompositionTypes;
            HWC2_PFN_GET_CLIENT_TARGET_SUPPORT getClientTargetSupport;
            HWC2_PFN_GET_COLOR_MODES getColorModes;
            HWC2_PFN_GET_DISPLAY_ATTRIBUTE getDisplayAttribute;
            HWC2_PFN_GET_DISPLAY_CONFIGS getDisplayConfigs;
            HWC2_PFN_GET_DISPLAY_NAME getDisplayName;
            HWC2_PFN_GET_DISPLAY_REQUESTS getDisplayRequests;
            HWC2_PFN_GET_DISPLAY_TYPE getDisplayType;
            HWC2_PFN_GET_DOZE_SUPPORT getDozeSupport;
            HWC2_PFN_GET_HDR_CAPABILITIES getHdrCapabilities;
            HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT getMaxVirtualDisplayCount;
            HWC2_PFN_GET_RELEASE_FENCES getReleaseFences;
            HWC2_PFN_PRESENT_DISPLAY presentDisplay;
            HWC2_PFN_REGISTER_CALLBACK registerCallback;
            HWC2_PFN_SET_ACTIVE_CONFIG setActiveConfig;
            HWC2_PFN_SET_CLIENT_TARGET setClientTarget;
            HWC2_PFN_SET_COLOR_MODE setColorMode;
            HWC2_PFN_SET_COLOR_TRANSFORM setColorTransform;
            HWC2_PFN_SET_CURSOR_POSITION setCursorPosition;
            HWC2_PFN_SET_LAYER_BLEND_MODE setLayerBlendMode;
            HWC2_PFN_SET_LAYER_BUFFER setLayerBuffer;
            HWC2_PFN_SET_LAYER_COLOR setLayerColor;
            HWC2_PFN_SET_LAYER_COMPOSITION_TYPE setLayerCompositionType;
            HWC2_PFN_SET_LAYER_DATASPACE setLayerDataspace;
            HWC2_PFN_SET_LAYER_DISPLAY_FRAME setLayerDisplayFrame;
            HWC2_PFN_SET_LAYER_PLANE_ALPHA setLayerPlaneAlpha;
            HWC2_PFN_SET_LAYER_SIDEBAND_STREAM setLayerSidebandStream;
            HWC2_PFN_SET_LAYER_SOURCE_CROP setLayerSourceCrop;
            HWC2_PFN_SET_LAYER_SURFACE_DAMAGE setLayerSurfaceDamage;
            HWC2_PFN_SET_LAYER_TRANSFORM setLayerTransform;
            HWC2_PFN_SET_LAYER_VISIBLE_REGION setLayerVisibleRegion;
            HWC2_PFN_SET_LAYER_Z_ORDER setLayerZOrder;
            HWC2_PFN_SET_OUTPUT_BUFFER setOutputBuffer;
            HWC2_PFN_SET_POWER_MODE setPowerMode;
            HWC2_PFN_SET_VSYNC_ENABLED setVsyncEnabled;
            HWC2_PFN_VALIDATE_DISPLAY validateDisplay;
        } mDispatch = {};
    

    createComposer 构建IComposer对象

        static IComposer* createComposer(std::unique_ptr<hal::ComposerHal> hal) {
            return hal::Composer::create(std::move(hal)).release();
        }
    

    文件:/hardware/interfaces/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/Composer.h

        static std::unique_ptr<ComposerImpl> create(std::unique_ptr<Hal> hal) {
            return std::make_unique<ComposerImpl>(std::move(hal));
        }
    

    很简单,本质上就是一个ComposerImpl持有了ComposerHal。

    嵌套的层级有点深,接下来让我把整个UML图画出来就清晰了,再结合一下上一篇文章,梳理一下。


    HWC关键数据结构.jpg

    Composer初始化中Hal的工作

    在上一篇文章中有两个hal方法没有进一步的聊,第一个是createClient创建IComposerClient,另一个是注册监听。

    Composer创建ComposerClient

    我们先把视角转移到
    文件:/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);
    
        mComposer->createClient(
                [&](const auto& tmpError, const auto& tmpClient)
                {
                    if (tmpError == Error::NONE) {
                        mClient = tmpClient;
                    }
                });
    ...
    
        // 2.2 support is optional
        sp<IComposer> composer_2_2 = IComposer::castFrom(mComposer);
        if (composer_2_2 != nullptr) {
            mClient_2_2 = IComposerClient::castFrom(mClient);
    ...
        }
    }
    

    mComposer通过getService拿到hal层的IComposer对象。

    文件:/hardware/interfaces/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/Composer.h

        Return<void> createClient(IComposer::createClient_cb hidl_cb) override {
            std::unique_lock<std::mutex> lock(mClientMutex);
            if (!waitForClientDestroyedLocked(lock)) {
                hidl_cb(Error::NO_RESOURCES, nullptr);
                return Void();
            }
    
            sp<IComposerClient> client = createClient();
            if (!client) {
                hidl_cb(Error::NO_RESOURCES, nullptr);
                return Void();
            }
    
            mClient = client;
            hidl_cb(Error::NONE, client);
            return Void();
        }
    
        void onClientDestroyed() {
            std::lock_guard<std::mutex> lock(mClientMutex);
            mClient.clear();
            mClientDestroyedCondition.notify_all();
        }
    
        virtual IComposerClient* createClient() {
            auto client = ComposerClient::create(mHal.get());
            if (!client) {
                return nullptr;
            }
    
            auto clientDestroyed = [this]() { onClientDestroyed(); };
            client->setOnClientDestroyed(clientDestroyed);
    
            return client.release();
        }
    

    实际上还是调用了ComposerClient::create方法实例化一个IComposerClient方法,接着才会把这个这个方法通过回调回调出去。同时让Composer持有一个mClient对象,当销毁的时候,会调用mClient的clear方法,并且唤起阻塞。也就是指销毁一个HWC::Device的mClient对象。

    接下来看看ComposerClient的create方法:
    文件:/hardware/interfaces/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h

        static std::unique_ptr<ComposerClientImpl> create(Hal* hal) {
            auto client = std::make_unique<ComposerClientImpl>(hal);
            return client->init() ? std::move(client) : nullptr;
        }
    
        bool init() {
            mResources = createResources();
            if (!mResources) {
                ALOGE("failed to create composer resources");
                return false;
            }
    
            mCommandEngine = createCommandEngine();
    
            return true;
        }
    
        virtual std::unique_ptr<ComposerResources> createResources() {
            return ComposerResources::create();
        }
    
        virtual std::unique_ptr<ComposerCommandEngine> createCommandEngine() {
            return std::make_unique<ComposerCommandEngine>(mHal, mResources.get());
        }
    

    能看到Client会持有两个对象,一个是ComposerResources,一个是ComposerCommandEngine。

    • ComposerResources 控制整个SF的Hal的资源,如绘制面Layer,如图元
    • ComposerCommandEngine 处理从SF上层到hal层的一些命令,用来实现一些需要直接通信到驱动的命令。

    ComposerResources 初始化

     static std::unique_ptr<ComposerResources> create() {
            auto resources = std::make_unique<ComposerResources>();
            return resources->init() ? std::move(resources) : nullptr;
        }
    
        bool init() { return mImporter.init(); }
    

    在ComposerResources初始化的同时,还会初始化ComposerHandleImporter对象。

    class ComposerHandleImporter {
       public:
        bool init() {
            mMapper = mapper::V2_0::IMapper::getService();
            return mMapper != nullptr;
        }
    

    该对象初始化了一个IMapper的Hal服务,其实该Hal服务就是图元申请器。换句话说Composer将会通过ComposerResources调用ComposerHandleImporter控制图元的状态。

    ComposerCommandEngine 初始化

        ComposerCommandEngine(ComposerHal* hal, ComposerResources* resources)
            : mHal(hal), mResources(resources) {}
    

    这个对象等到用的时候再去理解。

    这两个对象很重要,记住就好,后面会和它们打交道。

    IComposer通过注册监听Hal层实现监听驱动的关键动作

    还记得在SF的init方法中,我们还注册了一个Callback到Hal层中:
    文件:/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);
    }
    

    Device中的mComposer,其实是Composer,而这个对象才是统一处理HIDL对应在客户端的对象。

    void Composer::registerCallback(const sp<IComposerCallback>& callback)
    {
        auto ret = mClient->registerCallback(callback);
        if (!ret.isOk()) {
            ALOGE("failed to register IComposerCallback");
        }
    }
    

    文件:/hardware/interfaces/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h

        Return<void> registerCallback(const sp<IComposerCallback>& callback) override {
            // no locking as we require this function to be called only once
            mHalEventCallback = std::make_unique<HalEventCallback>(callback, mResources.get());
            mHal->registerEventCallback(mHalEventCallback.get());
            return Void();
        }
    

    能看到在这里面会把IComposerCallback再一次包裹成HalEventCallback对象,才会注册到mHal,也就是HwcHalImpl对象。

    来看看HalEventCallback这个包裹类:

        class HalEventCallback : public Hal::EventCallback {
           public:
            HalEventCallback(const sp<IComposerCallback> callback, ComposerResources* resources)
                : mCallback(callback), mResources(resources) {}
    
            void onHotplug(Display display, IComposerCallback::Connection connected) {
                if (connected == IComposerCallback::Connection::CONNECTED) {
                    mResources->addPhysicalDisplay(display);
                } else if (connected == IComposerCallback::Connection::DISCONNECTED) {
                    mResources->removeDisplay(display);
                }
    
                auto ret = mCallback->onHotplug(display, connected);
                ALOGE_IF(!ret.isOk(), "failed to send onHotplug: %s", ret.description().c_str());
            }
    
            void onRefresh(Display display) {
                auto ret = mCallback->onRefresh(display);
                ALOGE_IF(!ret.isOk(), "failed to send onRefresh: %s", ret.description().c_str());
            }
    
            void onVsync(Display display, int64_t timestamp) {
                auto ret = mCallback->onVsync(display, timestamp);
                ALOGE_IF(!ret.isOk(), "failed to send onVsync: %s", ret.description().c_str());
            }
    
           protected:
            const sp<IComposerCallback> mCallback;
            ComposerResources* const mResources;
        };
    

    这个方法本质上就是为了集中IComposerCallback和mResources处理。在HalEventCallback中对应每一种回调都有自己的方法,他除了会调用IComposerCallback对应的回调之外,还会特别处理屏幕的热插拔,如果是插入则将一个屏幕对象添加到ComposerResources,进行管理。

        void registerEventCallback(hal::ComposerHal::EventCallback* callback) override {
            mMustValidateDisplay = true;
            mEventCallback = callback;
    
            mDispatch.registerCallback(mDevice, HWC2_CALLBACK_HOTPLUG, this,
                                       reinterpret_cast<hwc2_function_pointer_t>(hotplugHook));
            mDispatch.registerCallback(mDevice, HWC2_CALLBACK_REFRESH, this,
                                       reinterpret_cast<hwc2_function_pointer_t>(refreshHook));
            mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC, this,
                                       reinterpret_cast<hwc2_function_pointer_t>(vsyncHook));
        }
    

    此时将会调用mDispatch的registerCallback方法。其实这个方法是一个模版方法,其实就是调用mDevice的registerCallback方法,并且把后面几个作为参数设置进去。

    从上文就解析到mDevice其实是hw2_device_t结构体也是HWC2On1Adapter,那么其实就是调用HWC2On1Adapter中的注册方法。
    文件:/hardware/interfaces/graphics/composer/2.1/utils/hwc2on1adapter/include/hwc2on1adapter/HWC2On1Adapter.h

    Error HWC2On1Adapter::registerCallback(Callback descriptor,
            hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer) {
        if (!isValid(descriptor)) {
            return Error::BadParameter;
        }
    
    
        std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
    
        if (pointer != nullptr) {
            mCallbacks[descriptor] = {callbackData, pointer};
        } else {
            ALOGI("unregisterCallback(%s)", to_string(descriptor).c_str());
            mCallbacks.erase(descriptor);
            return Error::None;
        }
    
        bool hasPendingInvalidate = false;
        std::vector<hwc2_display_t> displayIds;
        std::vector<std::pair<hwc2_display_t, int64_t>> pendingVsyncs;
        std::vector<std::pair<hwc2_display_t, int>> pendingHotplugs;
    
        if (descriptor == Callback::Refresh) {
            hasPendingInvalidate = mHasPendingInvalidate;
            if (hasPendingInvalidate) {
                for (auto& displayPair : mDisplays) {
                    displayIds.emplace_back(displayPair.first);
                }
            }
            mHasPendingInvalidate = false;
        } else if (descriptor == Callback::Vsync) {
            for (auto pending : mPendingVsyncs) {
                auto hwc1DisplayId = pending.first;
                if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
                    ALOGE("hwc1Vsync: Couldn't find display for HWC1 id %d",
                            hwc1DisplayId);
                    continue;
                }
                auto displayId = mHwc1DisplayMap[hwc1DisplayId];
                auto timestamp = pending.second;
                pendingVsyncs.emplace_back(displayId, timestamp);
            }
            mPendingVsyncs.clear();
        } else if (descriptor == Callback::Hotplug) {
            // Hotplug the primary display
            pendingHotplugs.emplace_back(mHwc1DisplayMap[HWC_DISPLAY_PRIMARY],
                    static_cast<int32_t>(Connection::Connected));
    
            for (auto pending : mPendingHotplugs) {
                auto hwc1DisplayId = pending.first;
                if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
                    ALOGE("hwc1Hotplug: Couldn't find display for HWC1 id %d",
                            hwc1DisplayId);
                    continue;
                }
                auto displayId = mHwc1DisplayMap[hwc1DisplayId];
                auto connected = pending.second;
                pendingHotplugs.emplace_back(displayId, connected);
            }
        }
    
        // Call pending callbacks without the state lock held
        lock.unlock();
    
        if (hasPendingInvalidate) {
            auto refresh = reinterpret_cast<HWC2_PFN_REFRESH>(pointer);
            for (auto displayId : displayIds) {
                refresh(callbackData, displayId);
            }
        }
        if (!pendingVsyncs.empty()) {
            auto vsync = reinterpret_cast<HWC2_PFN_VSYNC>(pointer);
            for (auto& pendingVsync : pendingVsyncs) {
                vsync(callbackData, pendingVsync.first, pendingVsync.second);
            }
        }
        if (!pendingHotplugs.empty()) {
            auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(pointer);
            for (auto& pendingHotplug : pendingHotplugs) {
                hotplug(callbackData, pendingHotplug.first, pendingHotplug.second);
            }
        }
        return Error::None;
    }
    

    能看到有2个集合,一个标志位在Hal判断是否需要回调当顶层。当mPendingHotplugs存在还没有被通知的屏幕热插拔消息的时候将会调用hotplug;当mPendingVsyncs存在还没有通知到的屏幕的同步也会调用vsync;如果需要刷新则会有hasPendingInvalidate设置true的标志。

    但是,如果是SF第一次进来就肯定不会有回调,因为此时还没有任何的拿到底层的任何数据。但是会把当前的监听类型和回调的方法指针都保存到mCallbacks数组中。

    此时就会直接转型为每一个回调到上层,此时就是HwcHalImpl中的refreshHook,hotplugHook,vsyncHook。

    HwcHalImpl refreshHook

        static void refreshHook(hwc2_callback_data_t callbackData, hwc2_display_t display) {
            auto hal = static_cast<HwcHalImpl*>(callbackData);
            hal->mMustValidateDisplay = true;
            hal->mEventCallback->onRefresh(display);
        }
    

    此时就会回调到IComposerClient的HalEventCallback。
    文件:/hardware/interfaces/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h

            void onRefresh(Display display) {
                auto ret = mCallback->onRefresh(display);
            }
    

    这个Callback就是上层的ComposerCallbackBridge
    文件:/frameworks/native/services/surfaceflinger/DisplayHardware/HWC2.cpp

        Return<void> onRefresh(Hwc2::Display display) override
        {
            mCallback->onRefreshReceived(mSequenceId, display);
            return Void();
        }
    

    而这个Callback就是SF。此时就会走到SF的页面刷新

    void SurfaceFlinger::onRefreshReceived(int sequenceId,
                                           hwc2_display_t /*display*/) {
        Mutex::Autolock lock(mStateLock);
        if (sequenceId != getBE().mComposerSequenceId) {
            return;
        }
        repaintEverything();
    }
    

    repaintEverything这个方法将会更新所有Layer中的图元。具体是什么意思,在之后的文章将会和大家聊聊

    HwcHalImpl vsyncHook
        static void vsyncHook(hwc2_callback_data_t callbackData, hwc2_display_t display,
                              int64_t timestamp) {
            auto hal = static_cast<HwcHalImpl*>(callbackData);
            hal->mEventCallback->onVsync(display, timestamp);
        }
    
    HalEventCallback onVsync
            void onVsync(Display display, int64_t timestamp) {
                auto ret = mCallback->onVsync(display, timestamp);
            }
    
    ComposerCallbackBridge onVsync
        Return<void> onVsync(Hwc2::Display display, int64_t timestamp) override
        {
            mCallback->onVsyncReceived(mSequenceId, display, timestamp);
            return Void();
        }
    

    最后就会走到SF中的回调

    void SurfaceFlinger::onVsyncReceived(int32_t sequenceId,
            hwc2_display_t displayId, int64_t timestamp) {
        Mutex::Autolock lock(mStateLock);
        // Ignore any vsyncs from a previous hardware composer.
        if (sequenceId != getBE().mComposerSequenceId) {
            return;
        }
    
        int32_t type;
        if (!getBE().mHwc->onVsync(displayId, timestamp, &type)) {
            return;
        }
    
        bool needsHwVsync = false;
    
        { // Scope for the lock
            Mutex::Autolock _l(mHWVsyncLock);
            if (type == DisplayDevice::DISPLAY_PRIMARY && mPrimaryHWVsyncEnabled) {
                needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);
            }
        }
    
        if (needsHwVsync) {
            enableHardwareVsync();
        } else {
            disableHardwareVsync(false);
        }
    }
    

    在这个回调中,会从硬件传来一个时间戳,对整个Vsync进行一次调整。究竟是怎么一个逻辑,我将放在后面的文章来聊。

    本文最重要将会关注屏幕热插拔的回调。

    HwcHalImpl hotplugHook

        static void hotplugHook(hwc2_callback_data_t callbackData, hwc2_display_t display,
                                int32_t connected) {
            auto hal = static_cast<HwcHalImpl*>(callbackData);
            hal->mEventCallback->onHotplug(display,
                                           static_cast<IComposerCallback::Connection>(connected));
        }
    

    HalEventCallback hotplugHook

    
            void onHotplug(Display display, IComposerCallback::Connection connected) {
                if (connected == IComposerCallback::Connection::CONNECTED) {
                    mResources->addPhysicalDisplay(display);
                } else if (connected == IComposerCallback::Connection::DISCONNECTED) {
                    mResources->removeDisplay(display);
                }
    
                auto ret = mCallback->onHotplug(display, connected);
                ALOGE_IF(!ret.isOk(), "failed to send onHotplug: %s", ret.description().c_str());
            }
    

    能看到在这个过程中就不是简单的回调,而是把回调上来的hwc2_display_t对象添加到ComposerResources中。

    ComposerResources 添加Display管理

    文件:/hardware/interfaces/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h

        Error addPhysicalDisplay(Display display) {
            auto displayResource =
                createDisplayResource(ComposerDisplayResource::DisplayType::PHYSICAL, 0);
    
            std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
            auto result = mDisplayResources.emplace(display, std::move(displayResource));
            return result.second ? Error::NONE : Error::BAD_DISPLAY;
        }
    
        virtual std::unique_ptr<ComposerDisplayResource> createDisplayResource(
            ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) {
            return std::make_unique<ComposerDisplayResource>(type, mImporter, outputBufferCacheSize);
        }
    

    在这个过程中,Composer会把每一个hwc2_display_t最终封装成一个个ComposerDisplayResource,加入到集合当中。

    class ComposerDisplayResource {
       public:
        enum class DisplayType {
            PHYSICAL,
            VIRTUAL,
        };
    
        ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer,
                                uint32_t outputBufferCacheSize)
            : mType(type),
              mClientTargetCache(importer),
              mOutputBufferCache(importer, ComposerHandleCache::HandleType::BUFFER,
                                 outputBufferCacheSize) {}
    

    能看到,此时就是把ComposerResources中的图元申请服务交给ComposerDisplayResource持有,让Display自己拥有控制图元的能力,同时初始化缓存为0.

    当缓存好ComposerDisplayResource之后就会继续回调,到顶层

    ComposerCallbackBridge onHotplug

        Return<void> onHotplug(Hwc2::Display display,
                               IComposerCallback::Connection conn) override
        {
            HWC2::Connection connection = static_cast<HWC2::Connection>(conn);
            mCallback->onHotplugReceived(mSequenceId, display, connection);
            return Void();
        }
    

    此时终于来到了上一篇文章中解析的SF层中屏幕的初始化流程中。

    注意小结

    了解了整个回调机制之后,我们能够发现其实registerCallback在Hwc1OnAdapter(也是hwc2_device_t)中做的事情仅仅只是把当前的方法指针和回调类型存储起来,同时让刚注册进来的监听消费掉还没有回调上去的消息。

    到这里,整个逻辑链路似乎就断开了。我曾经看源码也苦恼了很久,发现其实真正从硬件回调上来的地方其实是Hwc1OnAdapter::Callback中的回调。他是在hwc_device_t的registerProcs的时候注册进去的。

    接下来让我们探索一下他的原理。

    hwc_device_t的registerProcs

    调用如下:

        mHwc1Device->registerProcs(mHwc1Device,
                static_cast<const hwc_procs_t*>(mHwc1Callbacks.get()));
    

    文件:/hardware/qcom/display/msm8960/libhwcomposer/hwc.cpp

    static void hwc_registerProcs(struct hwc_composer_device_1* dev,
                                  hwc_procs_t const* procs)
    {
        hwc_context_t* ctx = (hwc_context_t*)(dev);
        if(!ctx) {
            return;
        }
        ctx->proc = procs;
    
        init_uevent_thread(ctx);
        init_vsync_thread(ctx);
    }
    

    又一次见到这种设计把hwc_composer_device_1转型成hwc_context_t.

    struct hwc_context_t {
        hwc_composer_device_1_t device;
        const hwc_procs_t* proc;
    
        qhwc::CopyBit *mCopyBit[MAX_DISPLAYS];
    
        overlay::Overlay *mOverlay;
        overlay::RotMgr *mRotMgr;
    
        //Primary and external FB updater
        qhwc::IFBUpdate *mFBUpdate[MAX_DISPLAYS];
        // External display related information
        qhwc::ExternalDisplay *mExtDisplay;
        qhwc::MDPInfo mMDP;
        qhwc::VsyncState vstate;
        qhwc::DisplayAttributes dpyAttr[MAX_DISPLAYS];
        qhwc::ListStats listStats[MAX_DISPLAYS];
        qhwc::LayerProp *layerProp[MAX_DISPLAYS];
        qhwc::LayerRotMap *mLayerRotMap[MAX_DISPLAYS];
        qhwc::MDPComp *mMDPComp[MAX_DISPLAYS];
        qhwc::CablProp mCablProp;
        overlay::utils::Whf mPrevWHF[MAX_DISPLAYS];
    
        //Securing in progress indicator
        bool mSecuring;
        //External Display configuring progress indicator
        bool mExtDispConfiguring;
        //Display in secure mode indicator
        bool mSecureMode;
        //Lock to prevent set from being called while blanking
        mutable Locker mBlankLock;
        //Lock to protect set when detaching external disp
        mutable Locker mExtSetLock;
        //DMA used for rotator
        bool mDMAInUse;
        //MDP rotater needed
        bool mNeedsRotator;
        //Check if base pipe is set up
        bool mBasePipeSetup;
        //Flags the transition of a video session
        bool mVideoTransFlag;
    };
    

    能看到这个方法初始化了2个线程,一个是vsync同步信号线程,一个是uevent的事件信号线程。还会把当前的hwc_procs_t这个回调结构体存储起来。

    hwc 初始化事件线程

    文件:/hardware/qcom/display/msm8960/libhwcomposer/hwc_uevents.cpp

    static void *uevent_loop(void *param)
    {
        int len = 0;
        static char udata[PAGE_SIZE];
        hwc_context_t * ctx = reinterpret_cast<hwc_context_t *>(param);
        char thread_name[64] = HWC_UEVENT_THREAD_NAME;
        prctl(PR_SET_NAME, (unsigned long) &thread_name, 0, 0, 0);
        setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
        uevent_init();
    
        while(1) {
            len = uevent_next_event(udata, sizeof(udata) - 2);
            handle_uevent(ctx, udata, len);
        }
    
        return NULL;
    }
    
    void init_uevent_thread(hwc_context_t* ctx)
    {
        pthread_t uevent_thread;
        int ret;
    
        ALOGI("Initializing UEVENT Thread");
        ret = pthread_create(&uevent_thread, NULL, uevent_loop, (void*) ctx);
        if (ret) {
            ALOGE("%s: failed to create %s: %s", __FUNCTION__,
                HWC_UEVENT_THREAD_NAME, strerror(ret));
        }
    }
    

    能看到该方法其实就是实例化一个最高优先级的pthread线程,经过一个uevent_init初始化后进入了uevent_loop的循环。关键能看到下面这个死循环:

        while(1) {
            len = uevent_next_event(udata, (int)sizeof(udata) - 2);
            handle_uevent(ctx, udata, len);
        }
    

    uevent_next_event不断的获取下一个需要处理事件,handle_uevent进行处理。

    uevent_init

    文件: /hardware/libhardware_legacy/uevent.c

    int uevent_init()
    {
        struct sockaddr_nl addr;
        int sz = 64*1024;
        int s;
    
        memset(&addr, 0, sizeof(addr));
        addr.nl_family = AF_NETLINK;
        addr.nl_pid = getpid();
        addr.nl_groups = 0xffffffff;
    
        s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
        if(s < 0)
            return 0;
    
        setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
    
        if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
            close(s);
            return 0;
        }
    
        fd = s;
        return (fd > 0);
    }
    

    能看到在msm8994中event的初始化其实就是一个socket服务端。这个socket设置协议族为SOCK_DGRAM也就是面向数据包的协议。同时设置了该socket是接收端,还设置了bind绑定了地址,并且回调了socket中的fd。

    uevent_next_event 获取需要处理的事件

    文件: /hardware/libhardware_legacy/uevent.c

    int uevent_next_event(char* buffer, int buffer_length)
    {
        while (1) {
            struct pollfd fds;
            int nr;
        
            fds.fd = fd;
            fds.events = POLLIN;
            fds.revents = 0;
            nr = poll(&fds, 1, -1);
         
            if(nr > 0 && (fds.revents & POLLIN)) {
                int count = recv(fd, buffer, buffer_length, 0);
                if (count > 0) {
                    struct uevent_handler *h;
                    pthread_mutex_lock(&uevent_handler_list_lock);
                    LIST_FOREACH(h, &uevent_handler_list, list)
                        h->handler(h->handler_data, buffer, buffer_length);
                    pthread_mutex_unlock(&uevent_handler_list_lock);
    
                    return count;
                } 
            }
        }
        
        // won't get here
        return 0;
    }
    

    其核心方法就是调用了poll系统调用,监听socket文件描述符中数据流的变化。一旦nr大于0,说明又说来了,就调用recv从socket中读取数据,回去遍历查找已经通过uevent_add_native_handler添加进来的回调,并返回发生变化的数量。

    然而这里面并没有通过uevent_add_native_handler进来一个回调。而是直接交给下一个函数处理。

    handle_uevent

    文件:/hardware/qcom/display/msm8960/libhwcomposer/hwc_uevents.cpp

    此时用过uevent_next_event已经把数据拷贝到uevent_data中,就开始解析数据

    enum {
        EXTERNAL_OFFLINE = 0,
        EXTERNAL_ONLINE,
        EXTERNAL_PAUSE,
        EXTERNAL_RESUME
    };
    
    
    static void handle_uevent(hwc_context_t* ctx, const char* udata, int len)
    {
        const char *str = udata;
        bool usecopybit = false;
        int compositionType =
            qdutils::QCCompositionType::getInstance().getCompositionType();
    
        if (compositionType & (qdutils::COMPOSITION_TYPE_DYN |
                               qdutils::COMPOSITION_TYPE_MDP |
                               qdutils::COMPOSITION_TYPE_C2D)) {
            usecopybit = true;
        }
    
        if(!strcasestr("change@/devices/virtual/switch/hdmi", str) &&
           !strcasestr("change@/devices/virtual/switch/wfd", str)) {
            return;
        }
        int connected = -1; // initial value - will be set to  1/0 based on hotplug
        int extDpyNum = HWC_DISPLAY_EXTERNAL;
        char property[PROPERTY_VALUE_MAX];
        if((property_get("persist.sys.wfd.virtual", property, NULL) > 0) &&
                (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
                 (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
            // This means we are using Google API to trigger WFD Display
            extDpyNum = HWC_DISPLAY_VIRTUAL;
    
        }
    
        int dpy = isHDMI(str) ? HWC_DISPLAY_EXTERNAL : extDpyNum;
    
        // update extDpyNum
        ctx->mExtDisplay->setExtDpyNum(dpy);
    
        while(*str) {
            if (!strncmp(str, "SWITCH_STATE=", strlen("SWITCH_STATE="))) {
                connected = atoi(str + strlen("SWITCH_STATE="));
                //Disabled until SF calls unblank
                ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive = false;
                //Ignored for Virtual Displays
                //ToDo: we can do this in a much better way
                ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = true;
                break;
            }
            str += strlen(str) + 1;
            if (str - udata >= len)
                break;
        }
    
        switch(connected) {
            case EXTERNAL_OFFLINE:
                {   // disconnect event
                    ctx->mExtDisplay->processUEventOffline(udata);
                    if(ctx->mFBUpdate[dpy]) {
                        Locker::Autolock _l(ctx->mExtSetLock);
                        delete ctx->mFBUpdate[dpy];
                        ctx->mFBUpdate[dpy] = NULL;
                    }
                    if(ctx->mCopyBit[dpy]){
                        Locker::Autolock _l(ctx->mExtSetLock);
                        delete ctx->mCopyBit[dpy];
                        ctx->mCopyBit[dpy] = NULL;
                    }
                    if(ctx->mMDPComp[dpy]) {
                        delete ctx->mMDPComp[dpy];
                        ctx->mMDPComp[dpy] = NULL;
                    }
                    ctx->dpyAttr[dpy].connected = false;
                    Locker::Autolock _l(ctx->mExtSetLock);
                    //hwc comp could be on
                    ctx->proc->hotplug(ctx->proc, dpy, connected);
                    break;
                }
            case EXTERNAL_ONLINE:
                {   // connect case
                    ctx->mExtDispConfiguring = true;
                    ctx->mExtDisplay->processUEventOnline(udata);
                    ctx->mFBUpdate[dpy] =
                            IFBUpdate::getObject(ctx->dpyAttr[dpy].xres, dpy);
                    ctx->dpyAttr[dpy].isPause = false;
                    if(usecopybit)
                        ctx->mCopyBit[dpy] = new CopyBit();
                    ctx->mMDPComp[dpy] =  MDPComp::getObject(
                            ctx->dpyAttr[dpy].xres, dpy);
                    ctx->dpyAttr[dpy].connected = true;
                    Locker::Autolock _l(ctx->mExtSetLock); //hwc comp could be on
                    ctx->proc->hotplug(ctx->proc, dpy, connected);
                    break;
                }
            case EXTERNAL_PAUSE:
                {   // pause case
                    ctx->mExtDispConfiguring = true;
                    ctx->dpyAttr[dpy].isActive = true;
                    ctx->dpyAttr[dpy].isPause = true;
                    break;
                }
            case EXTERNAL_RESUME:
                {  // resume case
                    ctx->dpyAttr[dpy].isActive = true;
                    ctx->dpyAttr[dpy].isPause = false;
                    break;
                }
            default:
               ...
        }
    }
    

    其实这里表达的观点很简单,首先它只解析以"change@/devices/virtual/switch/hdmi"或者"change@/devices/virtual/switch/wfd"开头的消息。这种消息的格式如下:

    change@/devices/virtual/switch/hdmi ACTION=change
    SWITCH_STATE=0
    

    需要判断的类型就是SWITCH_STATE对应的字符的int是什么进行响应的处理。有4个状态:

    • 1.EXTERNAL_OFFLINE 0
    • 2.EXTERNAL_ONLINE 1
    • 3.EXTERNAL_PAUSE 2
    • 4.EXTERNAL_RESUME 3

    同时dpy代表屏幕类型,如果是change@/devices/virtual/switch/hdmi消息来了,说明是物理屏幕HWC_DISPLAY_EXTERNAL

    当为EXTERNAL_OFFLINE 的时候就代表屏幕被关闭或者拔出。先调用 qhwc::ExternalDisplay->processUEventOffline,销毁保存在数组中数据,并让dpyAttr对应的id变成false,最后调用hotPlugin回调

    EXTERNAL_ONLINE 代表屏幕联通了。先调用ExternalDisplay的processUEventOnline,申请资源,最后调用hotPlugin回调

    EXTERNAL_PAUSE 屏幕冻结了,设置dpyAttr标志位

    EXTERNAL_RESUME 屏幕恢复了,设置dpyAttr标志位

    暂时理解这么多即可。

    vysnc线程初始化

    文件:/hardware/qcom/display/msm8960/libhwcomposer/hwc_vsync.cpp

    void init_vsync_thread(hwc_context_t* ctx)
    {
        int ret;
        pthread_t vsync_thread;
        ret = pthread_create(&vsync_thread, NULL, vsync_loop, (void*) ctx);
    ...
    }
    
    static void *vsync_loop(void *param)
    {
        const char* vsync_timestamp_fb0 = "/sys/class/graphics/fb0/vsync_event";
        const char* vsync_timestamp_fb1 = "/sys/class/graphics/fb1/vsync_event";
        int dpy = HWC_DISPLAY_PRIMARY;
    
        hwc_context_t * ctx = reinterpret_cast<hwc_context_t *>(param);
    
        char thread_name[64] = HWC_VSYNC_THREAD_NAME;
        prctl(PR_SET_NAME, (unsigned long) &thread_name, 0, 0, 0);
        setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY +
                    android::PRIORITY_MORE_FAVORABLE);
    
        const int MAX_DATA = 64;
        static char vdata[MAX_DATA];
    
        uint64_t cur_timestamp=0;
        ssize_t len = -1;
        int fd_timestamp = -1;
        bool fb1_vsync = false;
        bool logvsync = false;
    
        char property[PROPERTY_VALUE_MAX];
        if(property_get("debug.hwc.fakevsync", property, NULL) > 0) {
            if(atoi(property) == 1)
                ctx->vstate.fakevsync = true;
        }
    
        if(property_get("debug.hwc.logvsync", property, 0) > 0) {
            if(atoi(property) == 1)
                logvsync = true;
        }
    
        fd_timestamp = open(vsync_timestamp_fb0, O_RDONLY);
        if (fd_timestamp < 0) {
            ...
            ctx->vstate.fakevsync = true;
        }
    
        do {
            if (LIKELY(!ctx->vstate.fakevsync)) {
                len = pread(fd_timestamp, vdata, MAX_DATA, 0);
                if (len < 0) {
                   ...
                    continue;
                }
                // extract timestamp
                const char *str = vdata;
                if (!strncmp(str, "VSYNC=", strlen("VSYNC="))) {
                    cur_timestamp = strtoull(str + strlen("VSYNC="), NULL, 0);
                }
            } else {
                usleep(16666);
                cur_timestamp = systemTime();
            }
            // send timestamp to HAL
            if(ctx->vstate.enable) {
                ctx->proc->vsync(ctx->proc, dpy, cur_timestamp);
            }
    
        } while (true);
        if(fd_timestamp >= 0)
            close (fd_timestamp);
    
        return NULL;
    }
    

    其核心原理十分简单,也是进入到一个死循环。该循环会读取/sys/class/graphics/fb0/vsync_event下的驱动文件,如果失败说明没有硬件驱动,那就使用软件模拟,能看到这里面就会沉睡16.66毫秒。

    如果成功则读取里面的数据,一般为如下格式:

    VSYNC=41800875994
    获取后面的数值,最后把该时间顶层回调即可。

    本文对vysnc同步的信号的探索到这里,之后会结合整个SF聊聊它的原理。

    回调到HWC2On1Adapter::Callbacks

    我们现在暂时只关注一个屏幕的热插拔逻辑。

            static void hotplugHook(const hwc_procs_t* procs, int display,
                    int connected) {
                auto callbacks = static_cast<const Callbacks*>(procs);
                callbacks->mAdapter.hwc1Hotplug(display, connected);
            }
    
    void HWC2On1Adapter::hwc1Hotplug(int hwc1DisplayId, int connected) {
        ALOGV("Received hwc1Hotplug(%d, %d)", hwc1DisplayId, connected);
    
        if (hwc1DisplayId != HWC_DISPLAY_EXTERNAL) {
            return;
        }
    
        std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
    
        if (mCallbacks.count(Callback::Hotplug) == 0) {
            mPendingHotplugs.emplace_back(hwc1DisplayId, connected);
            return;
        }
    
        hwc2_display_t displayId = UINT64_MAX;
        if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
            if (connected == 0) {
                ALOGW("hwc1Hotplug: Received disconnect for unconnected display");
                return;
            }
    
            auto display = std::make_shared<HWC2On1Adapter::Display>(*this,
                    HWC2::DisplayType::Physical);
            display->setHwc1Id(HWC_DISPLAY_EXTERNAL);
            display->populateConfigs();
            displayId = display->getId();
            mHwc1DisplayMap[HWC_DISPLAY_EXTERNAL] = displayId;
            mDisplays.emplace(displayId, std::move(display));
        } else {
            if (connected != 0) {
                ALOGW("hwc1Hotplug: Received connect for previously connected "
                        "display");
                return;
            }
    
            displayId = mHwc1DisplayMap[hwc1DisplayId];
            mHwc1DisplayMap.erase(HWC_DISPLAY_EXTERNAL);
            mDisplays.erase(displayId);
        }
    
        const auto& callbackInfo = mCallbacks[Callback::Hotplug];
    
    
        lock.unlock();
    
        auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(callbackInfo.pointer);
        auto hwc2Connected = (connected == 0) ?
                HWC2::Connection::Disconnected : HWC2::Connection::Connected;
        hotplug(callbackInfo.data, displayId, static_cast<int32_t>(hwc2Connected));
    }
    

    如果没有注册热插拔的监听,则会保存到mPendingHotplugs集合中,等待回调监听。

    该回调只处理物理屏幕的逻辑。如果connect是0且mHwc1DisplayMap大于0说明有屏幕链接过,现在断开链接了,则从mHwc1DisplayMap中销毁对应id,销毁mDisplays对应的屏幕对象对象。

    如果connect为1,说明有屏幕链接进来了。此时会生成一个HWC2On1Adapter::Display对象保存mDisplays。最后就是走上面registerCallback之上的逻辑了。

    总结

    重新梳理一遍:

    • Composer其实最重要的行为就是createClient,创建一个ComposerClient,ComposerClient此时真正的逻辑核心。
    • ComposerClient会持有HwcHalImpl,该类因为持有这hw2_device_t,所以拥有了和硬件通信的能力。ComposerResource中持有ComposerInputHandler这个对象负责图元服务的控制。ComposerCommandEngine则是处理一些来自上层的命令。
    • HWC2On1Adapter则是为了适配hw_device_t和版本2之间的区别,同时注册一个监听到驱动中。
    • 对于回调来讲,分为两部分,当registerCallback的时候会消耗从底层回调上来。另一部分则是从底层直接拿到对应的HwcHalImpl的hook函数向上回调。

    原理如图:


    ComposerCallback.png

    了解Hal层的运作原理,为之后的逻辑打下基础。

    相关文章

      网友评论

        本文标题:Android 重学系列 SurfaceFlinger 的HAL

        本文链接:https://www.haomeiwen.com/subject/bvfdzctx.html