Android Treble架构解析

Android Treble架构下Binder IPC与HIDL/AIDL HAL接口设计解析 进程间通信(IPC)是操作系统实现模块化与解耦的核心机制,它允许不同进程安全高效地交换数据与指令。在Android系统中,Binder作为默认的IPC机制,通过内核驱动与用户空间库的协同,实现了基于Client-Server模型的远程过程调用(RPC)。其技术价值在于为系统服务、应用框架及硬件抽象层提供了稳定可靠的通信基础,尤其在系统安全性与稳定性方面至关重要。随着Android生态对模块化与快速升级的需求增长,这一机制被深度应用于Treble项目,以解决传统硬件抽象层(HAL)与框架层的紧耦合问题。具体而 阅读详情

本文主要介绍Treble架构下的HAL&HIDL&Binder相关技术原理。Treble的详细资料文档,请参考Treble 官方文档。

1. Treble 简介

Android 8.0 版本的一项新元素是 Project Treble。这是 Android 操作系统框架在架构方面的一项重大改变,旨在让制造商以更低的成本更轻松、更快速地将设备更新到新版 Android 系统。Project Treble 适用于搭载 Android 8.0 及后续版本的所有新设备(这种新的架构已经在 Pixel 手机的开发者预览版中投入使用)。

1.1 系统更新

这里写图片描述

图 1. Treble 推出前的 Android 更新环境

Android 7.x 及更早版本中没有正式的供应商接口,因此设备制造商必须更新大量 Android 代码才能将设备更新到新版 Android 系统:

这里写图片描述 
图 2. Treble 推出后的 Android 更新环境

Treble 提供了一个稳定的新供应商接口,供设备制造商访问 Android 代码中特定于硬件的部分,这样一来,设备制造商只需更新 Android 操作系统框架,即可跳过芯片制造商直接提供新的 Android 版本:

1.2 Android 经典架构

为了更好的了解Treble 架构里面的HAL,首先了解一下Android的经典架构。

这里写图片描述

在Android O之前,HAL是一个个的.so库,通过dlopen来进行打开,库和framework位于同一个进程。如图所示:

这里写图片描述

1.3 Trebe 架构

为了能够让Android O之前的版本升级到Android O,Android设计了Passthrough模式,经过转换,可以方便的使用已经存在代码,不需要重新编写相关的HAL。HIDL分为两种模式:Passthrough和Binderized。

  • Binderized: Google官方翻译成绑定试HAL。
  • Passthrough:Google官方翻译成直通式HAL。

大致框架图如下,对于Android O之前的设备,对应图1,对于从之前的设备升级到O的版本,对应图2、图3. 对于直接基于Android O开发的设备,对应图4。

这里写图片描述

新的架构之下,framework和hal运行于不同的进程,所有的HAL采用新的HIDL技术来完成。

这里写图片描述

2. HIDL 深入理解

HIDL是一种接口定义语言,描述了HAL和它的用户之间的接口。接下来深入分析一下HIDL相关实现。

2.1 hidl-gen工具

在Treble架构中,经常会提到HIDL,首先介绍和HIDL相关的一个工具hidl-gen,系统定义的所有的.hal接口,都是通过hidl-gen工具转换成对应的代码。比如hardware/interfaces/power/1.0/IPower.hal,会通过hidl-gen转换成out/soong/.intermediates/hardware/interfaces/power/1.0/android.hardware.power@1.0_genc++/gen/android/hardware/power/1.0/PowerAll.cpp文件,为了深入了解,介绍相关原理,首先分析hidl-gen。

hidl-gen源码路径:system/tools/hidl,是在ubuntu上可执行的二进制文件。

使用方法:hidl-gen -o output-path -L language (-r interface-root) fqname

例子:

hidl-gen  -Lmakefile  -r  android.hardware:hardware/interfaces  -r  android.hidl:system/libhidl/transport  android.hardware.power@1.0
 
  • 1

参数含义:

  • -L: 语言类型,包括c++, c++-headers, c++-sources, export-header, c++-impl, java, java-constants, vts, makefile, androidbp, androidbp-impl, hash等。hidl-gen可根据传入的语言类型产生不同的文件。
  • fqname: 完全限定名称的输入文件。比如本例中android.hardware.power@1.0,要求在源码目录下必须有hardware/interfaces/power/1.0/目录。 
    • 对于单个文件来说,格式如下:package@version::fileName,比如android.hardware.power@1.0::types.Feature。
    • 对于目录来说。格式如下package@version,比如android.hardware.power@1.0。
  • -r: 格式package:path,可选,对fqname对应的文件来说,用来指定包名和文件所在的目录到Android系统源码根目录的路径。如果没有制定,前缀默认是:android.hardware,目录是Android源码的根目录。
  • -o : 存放hidl-gen产生的中间文件的路径。我们查看hardware/interfaces/power/1.0/Android.bp,可以看到,-o参数都是写的$(genDir),一般都是在out/soong/.intermediates/hardware/interfaces/power/1.0/下面,根据-L的不同,后面产生的路径可能不太一样,比如c++,那么就会就是out/soong/.intermediates/hardware/interfaces/power/1.0/android.hardware.power@1.0_genc++/gen,如果是c++-headers,那么就是out/soong/.intermediates/hardware/interfaces/power/1.0/android.hardware.power@1.0_genc++_headers/gen。

对于实例来说,fqname是:android.hardware.power@1.0,包名是android.hardware,文件所在的目录是hardware/interfaces。例子中的命令会在out/soong/.intermediates/hardware/interfaces/power/1.0/下面产生对应的c++文件。

2.2 生成子hal的Android.mk和Android.bp文件

正如我们所知,所有的HIDL Interface 都是通过一个.hal文件来描述,为了方便编译生成每一个子hal。Google在系统默认提供了一个脚本update-makefiles.sh,位于hardware/interfaces/、frameworks/hardware/interfaces/、system/hardware/interfaces/、system/libhidl/。以hardware/interfaces/里面的代码为实例做介绍。

#!/bin/bash

source system/tools/hidl/update-makefiles-helper.sh

do_makefiles_update \
  "android.hardware:hardware/interfaces" \
  "android.hidl:system/libhidl/transport"

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这个脚本的主要作用:根据hal文件生成Android.mk(makefile)和Android.bp(blueprint)文件。在hardware/interfaces的子目录里面,存在.hal文件的目录,都会产生Android.bp和Android.mk文件。详细分析如下:

a. source system/tools下面的update-makefiles-helper.sh,然后执行do_makefiles_update

b. 解析传入进去的参数。参数android.hardware:hardware/interfaces:

  • android.hardware: android.hardware表示包名。
  • hardware/interfaces:表示相对于根目录的文件路径。

会输出如下LOG:

Updating makefiles for android.hardware in hardware/interfaces. 
Updating ….

c. 获取所有的包名。通过function get_packages()函数,获取hardware/interfaces路径下面的所有hal文件所在的目录路径,比如子目录power里面的hal文件的路径是power/1.0,加上当前的参数包名hardware/interfaces,通过点的方式连接,将nfc/1.0+hardware/interfaces里面的斜线转换成点,最终获取的包名就是 android.hardware.power@1.0,依次类推获取所有的包名。

d. 执行hidl-gen命令.将c步骤里面获取的参数和包名还有类名传入hidl-gen命令,在hardware/interfaces/power/1.0目录下产生Android.mk和Android.bp文件。

  • Android.mk: hidl-gen -Lmakefile -r android.hardware:hardware/interfaces -r android.hidl:system/libhidl/transport android.hardware.power@1.0
  • Android.bp: hidl-gen -Landroidbp -r android.hardware:hardware/interfaces -r android.hidl:system/libhidl/transport android.hardware.power@1.0

关于hidl-gen,后续章节会介绍。

e. 在hardware/interfaces的每个子目录下面产生Android.bp文件,文件内容主要是subdirs的初始化,存放当前目录需要包含的子目录。比如hardware/interfaces/power/下面的Android.bp文件。

@hardware/interfaces/power/Android.bp

// This is an autogenerated file, do not edit.
subdirs = [ 
    "1.0",
    "1.0/default",
    "1.0/vts/functional",
]
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

意思就是说,编译的时候,需要编译hardware/interfaces/power目录下面的三个子目录。

经过以上步骤,就会在对应的子目录产生Android.mk和Android.bp文件。这样以后我们就可以执行正常的编译命令进行编译了。比如mmm hardware/interfaces/power/,默认情况下,在源码中,Android.mk和Android.bp文件已经存在。

2.3 转换.hal 文件为代码

如前面所示,每个接口都是定义在.hal文件里面,比如hardware/interfaces/power/1.0/IPower.hal,通过hidl-gen生成的android.bp文件里面会定义

filegroup {
    name: "android.hardware.power@1.0_hal",
    srcs: [
        "types.hal",
        "IPower.hal",
    ],
}

genrule {
    name: "android.hardware.power@1.0_genc++",
    tools: ["hidl-gen"],
    cmd: "$(location hidl-gen) -o $(genDir) -Lc++-sources -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.power@1.0",
    srcs: [
        ":android.hardware.power@1.0_hal",
    ],
    out: [
        "android/hardware/power/1.0/types.cpp",
        "android/hardware/power/1.0/PowerAll.cpp",
    ],
}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

可以看到在Android.bp里面,通过hidl-gen在out下面产生了types.cpp和PowerAll.cpp. 实际例子很多,不做详细介绍。

对于生成的PowerAll.cpp来说,我们可以看到,除了IPower.hal里面定义的函数之外,还生成了很多其他的方法,这个是hidl-gen默认产生,为了能够支持binder通信。在IPower.hal里面定义的setInteractive(bool interactive);,在PowerAll.cpp里面对应的是BpHwPower::setInteractive(bool interactive)。通过命名就可以知道,这个和Binder机制里面的命名一致。代码如下:

::android::hardware::Return<void> BpHwPower::setInteractive(bool interactive) {
    atrace_begin(ATRACE_TAG_HAL, "HIDL::IPower::setInteractive::client");
    #ifdef __ANDROID_DEBUGGABLE__
    if (UNLIKELY(mEnableInstrumentation)) {
        std::vector<void *> _hidl_args;
        _hidl_args.push_back((void *)&interactive);
        for (const auto &callback: mInstrumentationCallbacks) {
            callback(InstrumentationEvent::CLIENT_API_ENTRY, "android.hardware.power", "1.0", "IPower", "setInteractive", &_hidl_args);
        }
    }
    #endif // __ANDROID_DEBUGGABLE__

    ::android::hardware::Parcel _hidl_data;
    ::android::hardware::Parcel _hidl_reply;
    ::android::status_t _hidl_err;
    ::android::hardware::Status _hidl_status;

    _hidl_err = _hidl_data.writeInterfaceToken(IPower::descriptor);
    if (_hidl_err != ::android::OK) { goto _hidl_error; }

    _hidl_err = _hidl_data.writeBool(interactive);
    if (_hidl_err != ::android::OK) { goto _hidl_error; }

    _hidl_err = remote()->transact(1 /* setInteractive */, _hidl_data, &_hidl_reply);
    if (_hidl_err != ::android::OK) { goto _hidl_error; }

    _hidl_err = ::android::hardware::readFromParcel(&_hidl_status, _hidl_reply);
    if (_hidl_err != ::android::OK) { goto _hidl_error; }

    if (!_hidl_status.isOk()) { return _hidl_status; }

    atrace_end(ATRACE_TAG_HAL);
    #ifdef __ANDROID_DEBUGGABLE__
    if (UNLIKELY(mEnableInstrumentation)) {
        std::vector<void *> _hidl_args;
        for (const auto &callback: mInstrumentationCallbacks) {
            callback(InstrumentationEvent::CLIENT_API_EXIT, "android.hardware.power", "1.0", "IPower", "setInteractive", &_hidl_args);
        }
    }
    #endif // __ANDROID_DEBUGGABLE__

    _hidl_status.setFromStatusT(_hidl_err);
    return ::android::hardware::Return<void>();

_hidl_error:
    _hidl_status.setFromStatusT(_hidl_err);
    return ::android::hardware::Return<void>(_hidl_status);
}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

经过以上步骤,.hal文件就转换成了对应的代码,而且具备了Binder通信的能力。

HIDL整个流程如图所示:

这里写图片描述

3. HAL通信机制(c++)

在Treble架构中,framework/vendor之间的通信通过HIDL接口和dev/hwbinder的IPC域来完成。而且HIDL接口有两种通信模式Passthrough和Binderized。接下来我们介绍两种模式下的交互原理。创建HAL服务器有两种模式:

  • defaultPassthroughServiceImplementation
int main() {
    return defaultPassthroughServiceImplementation<IPower>();
}

 
  • 1
  • 2
  • 3
  • 4
  • registerAsService
int main(int /* argc */, char* /* argv */ []) {
    sp<IDumpstateDevice> dumpstate = new DumpstateDevice;
    configureRpcThreadpool(1, true /* will join */);
    if (dumpstate->registerAsService() != OK) {
        ALOGE("Could not register service.");
        return 1;
    }
    joinRpcThreadpool();

    ALOGE("Service exited!");
    return 1;
}

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

接下来我们分别介绍两种类型的详细过程。

3.1 defaultPassthroughServiceImplementation

首先介绍Passthrough模式的HIDL实现机制。以hardware/interfaces/power/1.0作为例子。当编译hardware/interfaces/power/1.0的时候,会生成:

  • 中间文件PowerAll.cpp
  • /vendor/bin/hw/android.hardware.power@1.0-service的可执行文件
  • /vendor/lib/hw/android.hardware.power@1.0-impl.so的库文件
  • android.hardware.power@1.0-service.rc会被拷贝到vendor.img里面的vendor/etc/init目录。rc文件的内容如下:
service power-hal-1-0 /vendor/bin/hw/android.hardware.power@1.0-service
    class hal
    user system
    group system
 
  • 1
  • 2
  • 3
  • 4

接下来我们就一步步分析,power Server是如何初始化的。

  • 对于init的解析机制,本文不做描述,在开机过程的某一个阶段,系统会启动class是hal的服务,会执行/vendor/bin/hw/android.hardware.power@1.0-service,从而调用hardware/interfaces/power/1.0/default/service.cpp的main方法。代码如下:
int main() {
    return defaultPassthroughServiceImplementation<IPower>();
}

 
  • 1
  • 2
  • 3
  • 4

接下来会调用

@PowerAll.cpp

:android::sp<IPower> IPower::getService(const std::string &serviceName, const bool getStub) {
    using ::android::hardware::defaultServiceManager;
    using ::android::hardware::details::waitForHwService;
    using ::android::hardware::getPassthroughServiceManager;
    using ::android::hardware::Return;
    using ::android::sp;
    using Transport = ::android::hidl::manager::V1_0::IServiceManager::Transport;

    sp<IPower> iface = nullptr;
    // 获取HwServiceManager
    const sp<::android::hidl::manager::V1_0::IServiceManager> sm = defaultServiceManager();
    if (sm == nullptr) {
        ALOGE("getService: defaultServiceManager() is null");
        return nullptr;
    }
    // 获取当前Tranport类型,passthrough或者binderized
    Return<Transport> transportRet = sm->getTransport(IPower::descriptor, serviceName);

    if (!transportRet.isOk()) {
        ALOGE("getService: defaultServiceManager()->getTransport returns %s", transportRet.description().c_str());
        return nullptr;
    }
    Transport transport = transportRet;
    const bool vintfHwbinder = (transport == Transport::HWBINDER);
    const bool vintfPassthru = (transport == Transport::PASSTHROUGH);

    // 返回当前的接口类

    for (int tries = 0; !getStub && (vintfHwbinder || (vintfLegacy && tries == 0)); tries++) {
        if (tries > 1) {
            ALOGI("getService: Will do try %d for %s/%s in 1s...", tries, IPower::descriptor, serviceName.c_str());
            sleep(1);
        }
        if (vintfHwbinder && tries > 0) {
            waitForHwService(IPower::descriptor, serviceName);
        }
        Return<sp<::android::hidl::base::V1_0::IBase>> ret = 
                sm->get(IPower::descriptor, serviceName);
        if (!ret.isOk()) {
            ALOGE("IPower: defaultServiceManager()->get returns %s", ret.description().c_str());
            break;
        }
        sp<::android::hidl::base::V1_0::IBase> base = ret;
        if (base == nullptr) {
            if (tries > 0) {
                ALOGW("IPower: found null hwbinder interface");
            }continue;
        }
        Return<sp<IPower>> castRet = IPower::castFrom(base, true /* emitError */);
    // ...
        iface = castRet;
        if (iface == nullptr) {
            ALOGW("IPower: received incompatible service; bug in hwservicemanager?");
            break;
        }
        return iface;
    }
    // 获取passthrough模式的类。
    if (getStub || vintfPassthru || vintfLegacy) {
        const sp<::android::hidl::manager::V1_0::IServiceManager> pm = getPassthroughServiceManager();
        if (pm != nullptr) {
            Return<sp<::android::hidl::base::V1_0::IBase>> ret = 
                    pm->get(IPower::descriptor, serviceName);
            if (ret.isOk()) {
                sp<::android::hidl::base::V1_0::IBase> baseInterface = ret;
                if (baseInterface != nullptr) {
                    iface = new BsPower(IPower::castFrom(baseInterface));
                }
            }
        }
    }
    return iface;
}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • defaultPassthroughServiceImplementation(); @hardware/interfaces/power/1.0/default/service.cpp
  • IPower::getService @PowerAll.cpp 从HwServiceManager里面获取注册的服务。默认情况下是没有注册这个服务的。
  • defaultServiceManager @system/libhidl/transport/ServiceManagement.cpp 打开/dev/hwbinder,通过binder通信,获取HwServiceManager服务端。
  • sm->getTransport 基本就是按照Binder通信的机制来实现相关的流程。通过HwBinder调用服务端的getTransPort方法。

    • BpHwServiceManager::getTransport @ServiceManagerAll.cpp
    • BpHwBinder::transact
    • IPCThreadState::self()->transact
    • IPCThreadState::transact writeTransactionData waitForResponse
    • IPCThreadState::executeCommand
  • ServiceManager::getTransport@system/hwservicemanager/ServiceManager.cpp

    • getTransport @ system/hwservicemanager/Vintf.cpp 根据framework hal和device hal配置的manifest.xml里面的定义,来判断当前的传输类型是HwBinder还是Passthrough模式。在vendor/manifest.xml里面,power配置的是hwbinder,所以最终就是hwBinder模式。(后续会讲解manifest.xml的原理)

由于我们采取的是defaultPassthroughServiceImplementation<IPower>();进行注册,所以getStub=true.所以会走到const sp<::android::hidl::manager::V1_0::IServiceManager> pm = getPassthroughServiceManager(); 
- getPassthroughServiceManager @ PowerAll.cpp 获取passthrough服务管理。 
- 调用PassthroughServiceManager的get(const hidl_string& fqName, const hidl_string& name)函数 @ServiceManagement.cpp, 根据传入的fqName=(android.hardware.power@1.0::IPower"),获取当前的接口名IPower,拼接出后面需要载入的函数名HIDL_FETCH_IPower和库名字android.hardware.power@1.0-impl,接着通过dlopen载入/vendor/lib/hw/android.hardware.power@1.0-impl.so,然后通过dlsym载入HIDL_FETCH_IPower函数。 代码如下:

@hardware/interfaces/power/1.0/default/Power.cpp

IPower* HIDL_FETCH_IPower(const char* /* name */) {
    const hw_module_t* hw_module = nullptr;
    power_module_t* power_module = nullptr;
    int err = hw_get_module(POWER_HARDWARE_MODULE_ID, &hw_module);
    if (err) {
        ALOGE("hw_get_module %s failed: %d", POWER_HARDWARE_MODULE_ID, err);
        return nullptr;
    }

    if (!hw_module->methods || !hw_module->methods->open) {
        power_module = reinterpret_cast<power_module_t*>(
            const_cast<hw_module_t*>(hw_module));
    } else {
        err = hw_module->methods->open(
            hw_module, POWER_HARDWARE_MODULE_ID,
            reinterpret_cast<hw_device_t**>(&power_module));
        if (err) {
            ALOGE("Passthrough failed to load legacy HAL.");
            return nullptr;
        }
    }
    return new Power(power_module);
}

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

通过hw_get_module就和Android O以前的Hal模式一致,这正是Passthrough复用原有hal的原理,测试用的是模拟器,所以最终获取的库文件是/system/lib/hw/power.ranchu.so,后续所有的和Power有关的接口调用,最终都是通过power.ranchu.so来实现功能。

接下来会调用registerReference("android.hardware.power@1.0::IPower","default"),接着调用BpHwServiceManager::registerPassthroughClient将fqName和服务名,注册进hwservicemanager的mServiceMap对象里面。

Return<void> ServiceManager::registerPassthroughClient(const hidl_string &fqName,
        const hidl_string &name) {
    pid_t pid = IPCThreadState::self()->getCallingPid();
    if (!mAcl.canGet(fqName, pid)) {
        /* We guard this function with "get", because it's typically used in
         * the getService() path, albeit for a passthrough service in this
         * case
         */
        return Void();
    }
    PackageInterfaceMap &ifaceMap = mServiceMap[fqName];
    if (name.empty()) {
        LOG(WARNING) << "registerPassthroughClient encounters empty instance name for "
                     << fqName.c_str();
        return Void();
    }
    HidlService *service = ifaceMap.lookup(name);
    if (service == nullptr) {
        auto adding = std::make_unique<HidlService>(fqName, name);
        adding->registerPassthroughClient(pid);
        ifaceMap.insertService(std::move(adding));
    } else {
        service->registerPassthroughClient(pid);
    }
    return Void();
}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 返回android::hidl::base::V1_0::IBase实例。

  • new BsPower:首先会通过interfaceChain判断当前的interface是否支持转换,然后传入包名和接口名"android.hardware.power@1.0", "IPower"构造出一个new BsPower的实例。

  • IPower::registerAsService 接下来,调用status_t status = service->registerAsService(name),首先会创建BnHwPower对象,然后将当前的service 添加进hwservicemanager里面。初始化BnHwPower的过程中, _hidl_mImpl实际上就是BsPower的引用。代码如下。 。

BnHwPower::BnHwPower(const ::android::sp<IPower> &_hidl_impl)
        : ::android::hidl::base::V1_0::BnHwBase(_hidl_impl, "android.hardware.power@1.0", "IPower") { 
            _hidl_mImpl = _hidl_impl;
            auto prio = ::android::hardware::details::gServicePrioMap.get(_hidl_impl, {SCHED_NORMAL, 0}); 
            mSchedPolicy = prio.sched_policy;
            mSchedPriority = prio.prio;
}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

然后调用如下步骤,将当前通信加入IPC Binder的线程池进行循环。

  • android::hardware::joinRpcThreadpool at system/libhidl/transport/HidlTransportSupport.cpp:28 加入RpcThreadPool。
  • android::hardware::joinBinderRpcThreadpool at system/libhidl/transport/HidlBinderSupport.cpp:188
  • android::hardware::IPCThreadState::joinThreadPool at system/libhwbinder/IPCThreadState.cpp:497
  • android::hardware::IPCThreadState::getAndExecuteCommand at system/libhwbinder/IPCThreadState.cpp:443

至此,android.hardware.power@1.0::IPower服务就启动成功了,可以响应客户端的请求了。

总结,通过defaultPassthroughServiceImplementation把当前的服务注册进HwServiceManager,每个服务都是一个HidlService。然后就可以等待客户端的调用。

3.2 registerAsService 创建HAL

根据Android源码网站介绍,android.hardware.dumpstate@1.0是属于绑定式HAL。接下来我们分析dumpstate服务初始化的流程。代码位于:hardware/interfaces/dumpstate/1.0/default/,查看service.cpp,代码如下:

int main(int /* argc */, char* /* argv */ []) {
    sp<IDumpstateDevice> dumpstate = new DumpstateDevice;
    configureRpcThreadpool(1, true /* will join */);
    if (dumpstate->registerAsService() != OK) {
        ALOGE("Could not register service.");
        return 1;
    }
    joinRpcThreadpool();

    ALOGE("Service exited!");
    return 1;
}

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • IDumpstateDevice::registerAsService
  • android::hardware::details::onRegistration(“android.hardware.dumpstate@1.0”, “IDumpstateDevice”, serviceName) 
    • tryShortenProcessName 设置当前进程的名字,长度最多为16。android.hardware.dumpstate@1.0-service
  • BpHwServiceManager::add 
    • ServiceManager::add @system/hwservicemanager/ServiceManager.cpp 注意和binder的区别。将当前的service添加进mInstanceMap。
  • 收到HwBinder驱动的 BR_TRANSACTION 消息,然后执行 BHwBinder::transact
  • BnHwDumpstateDevice::onTransact
  • joinRpcThreadpool(); 把当前的通信加入HwBinder的线程池进行循环。

至此,registerAsService 创建HAL Service就完成了。

3.2 Binderized 模式 client和服务端的交互

服务注册成功之后,客户端就可以调用相关服务提供的功能。

以点击屏幕为实例说明,当我们点击屏幕的时候,会调用com_android_server_power_PowerManagerService.cpp的android_server_PowerManagerService_userActivity函数,代码如下:

void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) {
    // Tell the power HAL when user activity occurs.
    gPowerHalMutex.lock();
    if (getPowerHal()) {
        Return<void> ret = gPowerHal->powerHint(PowerHint::INTERACTION, 0);
        processReturn(ret, "powerHint");
    }
    // ...
    }
}

// Check validity of current handle to the power HAL service, and call getService() if necessary.
// The caller must be holding gPowerHalMutex.
bool getPowerHal() {
    if (gPowerHalExists && gPowerHal == nullptr) {
        gPowerHal = IPower::getService();
        if (gPowerHal != nullptr) {
            ALOGI("Loaded power HAL service");
        } else {
            ALOGI("Couldn't load power HAL service");
            gPowerHalExists = false;
        }
    }
    return gPowerHal != nullptr;
}

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

在getPowerHal里面,通过IPower::getService();方法经过HwBinder通信,获取服务端的引用。主要包含如下步骤:

  • IPower::getService() 获取IPower的服务。返回远程服务的代理gPowerHal,最终返回的是BpHwPower。

    • IPower::getService(const std::string &serviceName, const bool getStub)@PowerApp.cpp。
    • BpHwServiceManager::getTransport 获取当前的传输类型,passthrough或者binderized。Power是binderized,返回对应的服务代理。
    • sm->get(IPower::descriptor, serviceName) 从ServiceManager里面获取描述是android.hardware.power@1.0::IPower,服务名是default的hidlservice的引用。
    • IPower::castFrom(base, true /* emitError */)
    • android::hardware::details::castInterface 将hidlservice服务的引用转换成Binder对象。
    • ::android::hardware::IInterface::asBinder(static_cast

3.4 pathrough 模式 client和服务端的交互

查询manifest.xml可以发现。android.hardware.graphics.mapper是passthrough的模式。

    <hal format="hidl">
        <name>android.hardware.graphics.mapper</name>
        <transport arch="32+64">passthrough</transport>
        <version>2.0</version>
        <interface>
            <name>IMapper</name>
            <instance>default</instance>
        </interface>
    </hal>
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

以hardware/interfaces/graphics/mapper/2.0/作为例子进行分析。

@frameworks/native/libs/ui/Gralloc2.cpp

Mapper::Mapper()
{
    mMapper = IMapper::getService();
    if (mMapper == nullptr || mMapper->isRemote()) {
        LOG_ALWAYS_FATAL("gralloc-mapper must be in passthrough mode");
    }
}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

// static 
::android::sp IMapper::getService(const std::string &serviceName, const bool getStub) { 
using ::android::hardware::defaultServiceManager; 
using ::android::hardware::details::waitForHwService; 
using ::android::hardware::getPassthroughServiceManager; 
using ::android::hardware::Return; 
using ::android::sp; 
using Transport = ::android::hidl::manager::V1_0::IServiceManager::Transport;

sp<IMapper> iface = nullptr;

const sp<::android::hidl::manager::V1_0::IServiceManager> sm = defaultServiceManager();
if (sm == nullptr) {
    ALOGE("getService: defaultServiceManager() is null");
    return nullptr;
}

Return<Transport> transportRet = sm->getTransport(IMapper::descriptor, serviceName);

if (!transportRet.isOk()) {
    ALOGE("getService: defaultServiceManager()->getTransport returns %s", transportRet.description().c_str());
    return nullptr;
}
Transport transport = transportRet;
const bool vintfHwbinder = (transport == Transport::HWBINDER);
const bool vintfPassthru = (transport == Transport::PASSTHROUGH);

// ...
if (getStub || vintfPassthru || vintfLegacy) {
    const sp<::android::hidl::manager::V1_0::IServiceManager> pm = getPassthroughServiceManager();
    if (pm != nullptr) {
        Return<sp<::android::hidl::base::V1_0::IBase>> ret =
                pm->get(IMapper::descriptor, serviceName);
        if (ret.isOk()) {
            sp<::android::hidl::base::V1_0::IBase> baseInterface = ret;
            if (baseInterface != nullptr) {
                iface = new BsMapper(IMapper::castFrom(baseInterface));
            }
        }
    }
}
return iface;

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

}

  • 步骤和前面的一致,由于是passthrough的模式,调用PassthroughServiceManager的get(const hidl_string& fqName, const hidl_string& name)函数 @ServiceManagement.cpp, 根据传入的fqName=(android.hardware.graphics.mapper@2.0::IMapper"),获取当前的接口名IMapper,拼接出后面需要载入的函数名HIDL_FETCH_IMapper和库名字android.hardware.graphics.mapper@2.0-impl,接着通过dlopen载入android.hardware.graphics.mapper@2.0-impl,然后通过dlsym载入HIDL_FETCH_IMapper函数。

这样就实现了passthrough模式下的通信了。

4. HAL 通信 (JAVA)

以hardware/interfaces/radio/1.0/作为例子:

当我们编译hardware/interfaces/radio/1.0/的时候,会编译出:

  • android.hardware.radio-V1.0-java-static
  • out/target/common/gen/JAVA_LIBRARIES/android.hardware.radio-V1.0-java-static_intermediates/android/hardware/radio/V1_0/IRadio.java

接下来我们以

@frameworks/opt/telephony/Android.mk 最为例子,直接引用android.hardware.radio-V1.0-java-static,然后就可以使用里面的相关代码。


LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

// ...
LOCAL_JAVA_LIBRARIES := voip-common ims-common
LOCAL_STATIC_JAVA_LIBRARIES := android.hardware.radio-V1.0-java-static \
    android.hardware.radio.deprecated-V1.0-java-static
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := telephony-common
// ...

include $(BUILD_JAVA_LIBRARY)
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

接下来我们看一下使用的地方。

@RIL.java

        try {
            mRadioProxy = IRadio.getService(HIDL_SERVICE_NAME[mPhoneId == null ? 0 : mPhoneId]);
            if (mRadioProxy != null) {
                mRadioProxy.linkToDeath(mRadioProxyDeathRecipient,
                        mRadioProxyCookie.incrementAndGet());
                mRadioProxy.setResponseFunctions(mRadioResponse, mRadioIndication);
            } else {
                riljLoge("getRadioProxy: mRadioProxy == null");
            }
        } catch (RemoteException | RuntimeException e) {
            mRadioProxy = null;
            riljLoge("RadioProxy getService/setResponseFunctions: " + e);
        }

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

首先会直接调用IRadio.getService来获取相关服务。

@IRadio.java

    public static IRadio getService(String serviceName) throws android.os.RemoteException {
        return IRadio.asInterface(android.os.HwBinder.getService("android.hardware.radio@1.0::IRadio",serviceName));
    }

 
  • 1
  • 2
  • 3
  • 4

android.os.HwBinder.getService(“android.hardware.radio@1.0::IRadio”,serviceName)

JNI 
@frameworks/base/core/jni/android_os_HwBinder.cpp

static jobject JHwBinder_native_getService(
        JNIEnv *env,
        jclass /* clazzObj */,
        jstring ifaceNameObj,
        jstring serviceNameObj) {

    ///...

    auto manager = hardware::defaultServiceManager();

    // ...


    Return<IServiceManager::Transport> transportRet =
            manager->getTransport(ifaceNameHStr, serviceNameHStr);

    if (!transportRet.isOk()) {
        signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
        return NULL;
    }

    IServiceManager::Transport transport = transportRet;

    // ... java 类型的传输模式必须是HwBinder

    if (transport != IServiceManager::Transport::HWBINDER && !vintfLegacy) {
        LOG(ERROR) << "service " << ifaceName << " declares transport method "
                   << toString(transport) << " but framework expects hwbinder.";
        signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
        return NULL;
    }
    // 获取接口引用。
    Return<sp<hidl::base::V1_0::IBase>> ret = manager->get(ifaceNameHStr, serviceNameHStr);

    if (!ret.isOk()) {
        signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
        return NULL;
    }

    // 转换成Binder接口
    sp<hardware::IBinder> service = hardware::toBinder<
            hidl::base::V1_0::IBase, hidl::base::V1_0::BpHwBase>(ret);

    if (service == NULL) {
        signalExceptionForError(env, NAME_NOT_FOUND);
        return NULL;
    }

    LOG(INFO) << "Starting thread pool.";
    ::android::hardware::ProcessState::self()->startThreadPool();
    // 返回JHwRemoteBinder对象。
    return JHwRemoteBinder::NewObject(env, service);
}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

以上步骤和C++里面的获取服务步骤类似。通过IRadio.getService()获取相关的服务,进入JNI的相关接口,获取HwServiceManager服务,然后获取当前HAL的类型(必须是Binderized),接下来获取服务对应的接口引用,接着将当前接口转换成Ibinder引用,然后创建JHwRemoteBinder对象返回给java层。

IRadio.asInterface(android.os.HwBinder.getService("android.hardware.radio@1.0::IRadio",serviceName))
 
  • 1

java层接着调用IRadio.asInterface将Hwbinder引用转换成IRadio对象。

这样就可以通过IRadio对象调用

5. Vendor Interface Object

5.1 manifest.xml 和 compatibility_matrix.xml

在system分区和vendor分区,分别存在manifest.xml和compatibility_matrix.xml。内容大致如下:

<manifest version="1.0" type="framework">
    <hal format="hidl">
        <name>android.frameworks.displayservice</name>
        <transport>hwbinder</transport>
        <version>1.0</version>
        <interface>
            <name>IDisplayService</name>
            <instance>default</instance>
        </interface>
    </hal>
    <hal format="hidl">
        <name>android.frameworks.schedulerservice</name>
        <transport>hwbinder</transport>
        <version>1.0</version>
        <interface>
            <name>ISchedulingPolicyService</name>
            <instance>default</instance>
        </interface>
    </hal>
    ...
</manifest>
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

分为两类:

  • framework相关的,Google默认定义完成。
  • device相关,有设备厂商自定义。

device可以通过DEVICE_MANIFEST_FILE和DEVICE_MATRIX_FILE指定自己的manifest.xml文件。如高通平台的项目:

DEVICE_MANIFEST_FILE := device/qcom/msm8937_64/manifest.xml
DEVICE_MATRIX_FILE   := device/qcom/common/compatibility_matrix.xml
 
  • 1
  • 2

默认的framework manifest定义和兼容性文件定义如下: 
@build/core/config.mk

FRAMEWORK_MANIFEST_FILE := system/libhidl/manifest.xml
FRAMEWORK_COMPATIBILITY_MATRIX_FILE := hardware/interfaces/compatibility_matrix.xml
 
  • 1
  • 2

以上文件都是通过编译生成到对应的分区,编译脚本位于build/target/board/Android.mk。

通过对比可以发现,out下面生成的和源码里面存在的文件,并不是完全一致,在Android.mk里面可以发现,这几个文件都经过了out/host/linux-x86/bin/assemble_vintf转换,assemble_vintf会判断文件格式是否正确,并且会根据name按字母顺序排列。

以上两个xml都是在,在system/libvintf/parse_string.cpp里面进行解析。

在前面的介绍中,我们都讲到了一个重要的方法,就是transport

在system/libvintf/include/vintf/Transport.h定义

static const std::array<std::string, 3> gTransportStrings = {
    {
        "",
        "passthrough",
        "hwbinder",
    }
};

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

我们获取服务的时候,首先肯定要获取当前的HAL是什么类型。

6 其他技巧

打印当前的manifest信息

  • mmm system/libvintf/
  • adb push out/target/product/(产品名)/system/bin/vintf /system/bin/vintf
  • adb shell vintf


 原文地址: http://blog.youkuaiyun.com/xiaosayidao/article/details/75577940

Android HIDL完全解析:从Treble架构到硬件抽象层接口实战 在Android系统开发中,硬件抽象层(HAL)是连接framework与底层硬件驱动的关键纽带。传统HAL因缺乏稳定接口,导致系统升级与驱动适配高度耦合,成为碎片化的重要诱因。为解耦系统与厂商实现,Project Treble引入HIDL(HAL接口定义语言),通过Binder实现进程隔离,以版本化软件包定义稳定契约,使system与vendor可独立演进。HIDL支持passthrough与binderized两种模式,并借助hidl-gen自动生成代理与桩代码,配合VINTF manifest完成服务 阅读详情

相关推荐

Android系统Treble架构详解:解耦厂商实现

在2017年之前,Android用户可能都有过这样的经历:谷歌发布了新版本Android(比如Android 8.0 Oreo),但自己的手机厂商(如三星、小米)却要等半年甚至更久才能推送更新。这种“更新慢”的背后,是传统Android架构的“紧耦合”问题——厂商的定制代码(如UI、硬件驱动)与谷歌的系统核心代码深度绑定,导致每次大版本升级都需要厂商重新适配,耗时耗力。Treble(意为“三倍的”,这里指“分层”)正是谷歌为解决这一问题推出的架构改进方案。它的核心目标是。

操作系统内核探秘的博客 1724

Android Treble 简介

前言: With Android O, we’ve been working very closely with device makers and silicon manufacturers to take steps toward solving this problem, and we’re excited to give you a sneak peek at Project Treble, the biggest change to the low-level system architectu

南柯好萌的博客 1555

Android Treble与Mainline计划:推动Android生态系统的持续改进

Android操作系统作为目前全球最流行的移动操作系统之一,具有庞大而复杂的生态系统。它不仅驱动着数十亿台设备,还支持各种类型的应用程序开发和定制化需求。Android生态系统是由设备制造商、开发者社区和最终用户组成的多方参与体系。

虎哥LoveDroid 1237

Android Treble架构解析--

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.youkuaiyun.com/xiaosayidao/article/details/75577940 本文主要介绍Treble架构下的HAL&amp;HIDL&amp;Binder相关技术原理。T...

Linux and C 787

treble check检测工具 安卓4.4可用

检测工具 GSI 通刷检测 安卓4.4可用treble check

Python自动化神器:5分钟搞定PSCAD仿真波形图导出到Word(附WPS兼容方案)

本文介绍如何利用Python自动化库快速将PSCAD仿真波形图导出到Word或WPS,大幅提升电力系统仿真工程师的工作效率。通过精准坐标定位、智能排版和批量处理功能,实现仿真报告的自动化生成,同时提供WPS兼容方案,适用于不同办公环境。

sony5的博客 207

13.学习Camera之——Android Treble架构解析

本文主要介绍Treble架构下的HAL&HIDL&Binder相关技术原理。 1. Treble 简介 Android 8.0 版本的一项新元素是 Project Treble。这是 Android 操作系统框架在架构方面的一项 重大改变,旨在让制造商以更低的成本更轻松、更快速地将设备更新到新版 Android 系统。 Project Treble 适用于搭载 Android 8.0 及后续版本的所有新设备(这种新的架构已经在 Pixel 手机的开发者预览版中投入使用)。 1.1 系统.

Linux_zhicheng的博客 911

Vscode远程免密连接Linux虚拟机,并配置C/C++运行环境

目前想要深入学习在Linux,也为了方便编写C/C++程序。Linux的环境里一般自带有c++的编译环境,如果没有安装gcc和g++等编译器也比较便利。但是在虚拟机里用vim编写C++程序又不得劲,因此打算使用vscode远程连接Linux虚拟机进行学习。为了防止自己以后还要再配置,重复踩坑,因此写下这篇博客用做记录。环境:windows11、VMware17、rocky linux9.1 ( 开源的CentOS9 )

m0_56779872的博客 8676

Treble Check:安卓架构革命性检测工具深度解析

在安卓生态系统中,Project Treble被誉为自Android诞生以来最重要的架构变革。Treble Check作为这一变革的"技术诊断师",为用户提供了前所未有的设备兼容性洞察能力。本文将从技术价值、实用指南、应用场景、特色亮点和未来展望五个维度,深度剖析这款创新工具。 ## 📋 文章导航 - 🎯 技术价值:架构分离的革命意义 - 🛠️ 实用指南:从安装到深度使用 - 🌟 应用场

gitblog_00600的博客 723

使用sklearn学习多项式回归(三)

1,什么是线性 我们无数次提到”线性“这个名词。在支持向量机中,我们也曾经提到最初的支持向量机只能够分割线性可分的数据,然后引入了”核函数“来帮助我们分类那些非线性可分的数据。我们也曾经说起过,比如说决策树,支持向量机是”非线性“模型。所有的这些概念,让我们对”线性“这个词非常熟悉,却又非常陌生——因为我们并不知道它的真实含义。接下来我们看看线性回归模型改进的核心之一:帮助线性回归解决非线性问题。 1.1,变量之间的线性关系 ”线性“这个词用于描述不同事物时有着不同的含义。我们最常使用的线性是指“变量

理科男同学 5100

攻防世界-Reverse-Game

攻防世界,game,逆向

wuh2333的博客 775

从零构建:深入解析Vendor.img在Android Treble架构中的角色与实战

本文深入解析Vendor.img在Android Treble架构中的核心角色与实战制作方法。作为连接硬件与系统的关键分区,Vendor.img包含驱动、配置和HAL实现,显著提升系统更新效率与硬件兼容性。文章详细介绍了从环境准备、目录结构到ext4映像生成的完整构建流程,为ROM开发和系统优化提供实用指导。

pea55的博客 1027

操作系统头歌 课后作业3.3.2:进程的调度

请问:从 6 号进程刚创建完 7 号进程开始,在接下来的 9 次进程调度中,每次调度时,6 号和 7 号进程的剩余时间片是多少?请问:从 6 号进程刚创建完 7 号进程开始,在接下来的 9 次进程调度中,每次调度时,6 号和 7 号进程的剩余时间片是多少?根据相关知识回答当程序 01.c 运行时(在版本 0 内核中),会在父子两个进程(假设分别为 6 号和 7 号进程)中分别输出字符串。当程序 01.c 运行时(在版本 0 内核中),会在父子两个进程(假设分别为 6 号和 7 号进程)中分别输出字符串。

weixin_73255571的博客 4702

Treble兼容性检测工具:让安卓设备更新不再神秘

你是否遇到过这样的困扰?新买的安卓手机才用一年,就再也收不到系统更新通知?明明同品牌的高端机型已经用上最新系统,你的设备却仿佛被厂商"遗忘"?如果你对安卓系统更新速度感到失望,那么Project Treble可能是解决这一问题的关键技术——而Treble Check这款检测工具,正是帮你了解设备更新潜力的必备利器。 ## Project Treble是什么? 想象你的安卓设备是一座两层小楼:上

gitblog_00221的博客 437

Ansys Lumerical FDTD硬件配置避坑指南:从RTX 4090到A100的GPU选择实战

本文针对Ansys Lumerical FDTD仿真计算,深入分析了从消费级RTX 4090到专业级A100的GPU硬件配置选择。文章指出,选择的关键在于显存容量能否容纳仿真模型,并对比了二者在显存、双精度算力及多卡扩展性上的核心差异,为不同预算和仿真规模的用户提供了实战避坑指南与配置建议。

weixin_29196891的博客 271

基于Harness Engineering构建AI Agent的全自动化CI_CD流水线

AI Agent的CI/CD是指对Agent的全生命周期资产(代码、Prompt、RAG知识库、模型权重、工具配置)进行持续集成、持续测试、持续发布和持续观测的自动化流程,核心目标是在保障发布质量的前提下,最大化提升Agent的迭代效率。

AI云原生与云计算技术学院 622

Android O Treble框架

    一、Android O里使用HIDL来解耦Android Framework 与Vendor HAL Implemetation之间的关系,从而简化降低Android系统升级的影响与难度,最终目的是减小Android系统碎片化。     二、Treble框架是由binder、hwbinder和vndbinder三种类型的binder组成。     三、HIDL涉及到三个进程,通过hwb...

薛文旺 538

机器人全局路线规划导读

认知有限,望大家多多包涵,有什么问题也希望能够与大家多交流,共同成长!本文先对全局路线规划导读做个简单的介绍,具体内容后续再更,其他模块可以参考去我其他文章提示:以下是本篇文章正文内容。

qq_35635374的博客 1504

博客摘录「 Android Treble架构解析」2023年11月6日

获取hardware/interfaces路径下面的所有hal文件所在的目录路径。

m0_46400482的博客 103

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Android O Treble框架笔记(基于高通845平台)

Android O Treble框架笔记(基于高通845平台) tags: android 文章目录Android O Treble框架笔记(基于高通845平台)@[toc]**0 前言** **1 关于Treble架构** **2 hardware中的IBinder与IBase** **2.1 关于binder** **2.2 关于base** **2.3 对binder与base的理解** ...

whshiyun的专栏 1648

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Android音频架构演进:从传统HAL到Treble时代的AudioHal设计变迁

本文深入剖析了Android音频架构从传统HAL到Treble时代的演进历程。重点解读了Treble项目如何通过HIDL接口将框架与AudioHal解耦,解决了传统紧耦合模型下的升级与兼容性难题,并分析了HIDL AudioHal的核心设计、数据流优化及双轨制过渡策略,为开发者理解现代Android音频底层设计提供了清晰指南。

herb5的博客 784
上一篇: 学习 Android O HIDL
下一篇: Android Treble 计划技术文档
Omni-Space
博客等级 码龄11年 2158粉丝 23原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值