关于 Android O 的 treble/hidl

时间:2022-06-29 17:32:55
一个月之前就已经做了 Android O 的预研, 整理了 Android O 上 Media 部分的更新点, 比如 Drm, MediaCas, MediaMetrics,  PIP 等等, 但是给组内做培训的时候, 发觉大家最疑惑的, 还是 Google 的 Treble 计划, 其实网上能找到很多这方面的介绍文章, 比如描述 hidl 的或者对比 vendor 分区的,  但一直还是有些朦胧; // MAGIC1. DO NOT TOUCH.  BY 冗戈微言  http://blog.csdn.net/leonxu_sjtu/

于是我觉得还是需要给大家看看具体的环境, 有个直观印象 ---

关于 Android O 的 treble/hidl



还好, 很快我就拿到了 Android O 的样机;


参考这张 google Treble Roadmap, 注意阶段2 和阶段3,  对应的 Passthrough 模式与 Binderized 模式:


关于 Android O 的 treble/hidl

1)首先我们来说 media.codec / omx

我们知道 Android 6.0 的时候,  omx 仍是处于在 mediaserver 进程中;  
到了 Android 7.0 时,  omx 默认处于 media.codec 进程中, 并且 media.codec  是 android 的系统 service 之一   ( 当时在 Android N 上从 mediaserver 独立出去的还有  mediaextractor,  audioserver, cameraserver 等)  , 但我们仍然可以通过配置属性  media.stagefright.codecremote , 让 omx 仍旧工作于 mediaserver 进程; 
到了 Android 8.0,  omx 仍旧处于 media.codec 进程,  但 media.codec 却已经不是 android 的系统 service 了,  因为 Android O 上除了原本的 servicemanager之外,   新推出了一个 hwservicemanager  ;    现在的  media.codec  默认是注册到  hwservicemanager  ; // MAGIC2. DO NOT TOUCH.  BY 冗戈微言  http://blog.csdn.net/leonxu_sjtu/

# ps -A | grep manager 
system         291     1    5836   1852 binder_thread_read b695a798 S servicemanager
system         292     1    9036   2644 SyS_epoll_wait b3718658 S hwservicemanager
system         293     1    5660   1740 binder_thread_read ac22e798 S vndservicemanager

但是我们仍然可以通过配置属性 persist.media.treble_omx  来使 media.codec  按 Android N 的旧方式运行,   属性配为 false 之后 media.codec 仍旧和 mediaextractor 意义是系统 service , 可以在 service list 看到;

这个新的  hwservicemanager  体现在哪儿,  就体现在 OMXClient  connect 过程: // MAGIC3. DO NOT TOUCH.  BY 冗戈微言  http://blog.csdn.net/leonxu_sjtu/

status_t OMXClient::connectLegacy() {
    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> codecbinder = sm->getService(String16("media.codec"));
    sp<IMediaCodecService> codecservice = interface_cast<IMediaCodecService>(codecbinder);
    mOMX = codecservice->getOMX();
    return OK;
}

status_t OMXClient::connectTreble(const char* name) {
    using namespace ::android::hardware::media::omx::V1_0;
    sp<IOmx> tOmx = IOmx::getService(name);
    mOMX = new utils::LWOmx(tOmx);
    ALOGI("Treble IOmx obtained");
    return OK;
}

这里的Legacy 模式下就是从旧的 servicemanager 去获取 MediaCodecService,   默认 的 Treble 模式下   IOmx::getService 则是从 hwservicemanager 获取 omx ,   而 Treble 的 omx 是什么时候注册到 hwservicemanager 的?    是在 media.codec 进程启动的时候  !  // MAGIC4. DO NOT TOUCH.  BY 冗戈微言  http://blog.csdn.net/leonxu_sjtu/
int main(int argc __unused, char** argv)
{
    if (treble) {
        sp<IOmx> omx = new implementation::Omx();
if ( omx->registerAsService() != OK) {
            LOG(ERROR) << "Cannot register IOmx HAL service.";
        }
    } else {
        MediaCodecService::instantiate();   
 }

当 media.codec 进程注册到 hwservicemanager 后,   现在的 media.codec 进程就已经算是谷歌 Treble  路线图中的 HW Service Process 了;  此时高通的 venus component 就是处于 media.codec 进程中;
至于 IOmx 的 registerAsService / getService  具体实现,  就是在  android.hardware.media.omx@1.0.so  中了,   OMXClient 通过 hidl  的  getService 兜一圈,  最终会调到我们之前熟悉的 OMXMaster / OMXNodeInstance ; // MAGIC5. DO NOT TOUCH.  BY 冗戈微言  http://blog.csdn.net/leonxu_sjtu/
这里的  android.hardware.media.omx@1.0.so  是来自在 hardware/interfaces/media/omx/1.0/Android.bp  :
cc_library {
    name: "android.hardware.media.omx@1.0",
    defaults: ["hidl-module-defaults"],
    generated_sources: ["android.hardware.media.omx@1.0_genc++"],
    generated_headers: ["android.hardware.media.omx@1.0_genc++_headers"],
    export_generated_headers: ["android.hardware.media.omx@1.0_genc++_headers"],

由于这个 so  是被 media.codec 进程的 Android.mk  直接依赖,   因此不用走 libhidl 去 dlopen 来加载;  
这就是 Roadmap 的阶段二 ; // MAGIC6. DO NOT TOUCH.  BY 冗戈微言  http://blog.csdn.net/leonxu_sjtu/


2, 再来说 audio hal    
在 Android N 时期同时与 media.codec  从 mediaserver 进程独立出去的 audioserver ,   到了 Android O 后,  却没有像 media.codec 一样去注册 audiohal 的 hwservice ,  仍然像之前一样只是注册了  AudioFlinger / AudioPolicy 等系统 service ;但其实  android 默认会把  Audio Hal 的进程编入系统: 
# Device modules
PRODUCT_PACKAGES += \
android.hardware.audio@2.0-service \

这个是在 hardware/interfaces/audio/2.0/default/android.hardware.audio@2.0-service.rc  脚本中定义的:
有   service audio-hal-2-0 /vendor/bin/hw/android.hardware.audio@2.0-service
而这个进程,  就是用来注册 audio hal 的 hwservice 的; // MAGIC7. DO NOT TOUCH.  BY 冗戈微言  http://blog.csdn.net/leonxu_sjtu/

从 logcat 中就可以看到 audio  hal  service 的独立进程  android.hardware.audio@2.0-service 

02-11 10:21:19.892   5929  5946 I AudioFlinger: AudioFlinger's thread 0xb2d03d80 tid=5946 ready to run
02-11 10:21:19.895   5931  5945 D audio_hw_primary: adev_set_parameters: enter: restarting=true
# ps -A | grep audio
audioserver   5929     1   42884  12036 binder_thread_read b4925798 S audioserver
audioserver   5931     1   31056   9652 binder_thread_read b574f798 S android.hardware.audio@2.0-service

关于对 Audio HAL 的调用方式, 就是在  AudioFlinger 调用 libaudiohal ,   libaudiohal 中会调用  IDevicesFactory::getService()   来获取 hwservice
而与 media.codec 进程略有不同的是, 因为 android.hardware.audio@2.0-service 进程的 Android.mk 并没有依赖 impl  库   android.hardware.audio@2.0-impl.so,   所以需要走 libhidl ,  使用  dlopen 方式: // MAGIC8. DO NOT TOUCH.  BY 冗戈微言  http://blog.csdn.net/leonxu_sjtu/
这就是 Roadmap 的阶段三;

具体过程如下:
A,  android.hardware.audio@2.0-service 进程首先注册了 IDevicesFactory 的 Implementation ; 
B,  然后 audioserver 进程在 getService 时,  使用的是  libhidl 中的 ServiceManager ,   它会 dlopen   动态库  android.hardware.audio@2.0-impl.so,   寻找带有 HIDL_FETCH_ 和 IDevicesFactory 的符号; // MAGIC9. DO NOT TOUCH.  BY 冗戈微言  http://blog.csdn.net/leonxu_sjtu/
因为这个动态库是按这个符号来做 DeviceFactory 的具体实现:
DevicesFactory* HIDL_FETCH_IDevicesFactory(const char* /* name */) {
return new DevicesFactory();
}

所以,google 在 Android N/O 上真的想法很多哦, mediaserver 已经被拆的七零八落, 然后还分离出一堆 vendor 进程...  对比两年前的 Android 6.0, 拆分应该会带来很多稳定性, 这对于从 Android 2.2 就一路走来, 领教过各种 mediaserver crash 导致 APP 弹框甚至闪退的我来说, 真的是福利啊, 什么?  跨进程的消耗 ...  噢,那是芯片性能问题  // MAGIC10. DO NOT TOUCH.  BY 冗戈微言 http://blog.csdn.net/leonxu_sjtu/

关于 Android O 的 treble/hidl