Android O之后Treble VNDK, HIDL

Treble框架

Android 8.0 重新设计了 Android 操作系统框架(在一个名为“Treble”的项目中),以便让制造商能够以更低的成本更轻松、更快速地将设备更新到新版 Android 系统。在这种新架构中,HAL 接口定义语言(HIDL,发音为“hide-l”)指定了 HAL 和其用户之间的接口,让用户无需重新构建 HAL,就能替换 Android 框架。在 Android 10 中,HIDL 功能已整合到 AIDL 中。此后,HIDL 就被废弃了,并且仅供尚未转换为 AIDL 的子系统使用。

利用新的供应商接口,Treble 将供应商实现(由芯片制造商编写的设备专属底层软件)与 Android 操作系统框架分离开来。供应商或 SOC 制造商构建一次 HAL,并将其放置在设备的 /vendor 分区中;框架可以在自己的分区中通过无线下载 (OTA) 更新进行替换,而无需重新编译 HAL。

旧版 Android 架构与当前基于 HIDL 的架构之间的区别在于对供应商接口的使用:

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


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

    所有搭载 Android 8.0 及更高版本的新设备都可以利用这种新架构。为了确保供应商实现的向前兼容性,供应商接口会由供应商测试套 (VTS) 进行验证,该套件类似于兼容性测试套件 (CTS)。您可以使用 VTS 在旧版 Android 架构和当前 Android 架构中自动执行 HAL 和操作系统内核测试。

Android官网资料

Android 开发者网站,面向应用开发者,
https://developer.android.google.cn/

Android 开源操作系统网站,面向系统开发者,系统架构,安全,Treble方案,VNDK这里都有详细的说明,官网资料都是晦涩难懂,多看几遍就好。
https://source.android.google.cn/devices/architecture

Treble之后系统变化

按 Treble 架构要求,System 分区拆分成 System 和 Vendor 分区。System 镜像包含Android 原生仓及 Vendor/ODM 开发的 app 和 framework/JNI。Vendor 主要提供芯片/硬件相关接口实现。Android 版本中与 Treble 相关的新特性:

  • HIDL binderized,framework 与 HAL 实现运行在不同进程,通过 hwbinder 通信
  • System、Vendor 独立分区
  • Vendor 包含独立 SELinux 策略、Property 属性
  • Kernel 要求 linux4.4 以上版本,推荐 4.9
  • 新增 VTS 测试,保证兼容性
  • 新增 PureAndroidTest,由 Google 提供镜像,覆盖厂商 system 分区后执行 VTS 测试;
IPC 域 说明
/dev/binder 框架/应用进程之间的 IPC,使用 AIDL 接口
/dev/hwbinder 框架/供应商进程之间的 IPC,使用 HIDL 接口
供应商进程之间的 IPC,使用 HIDL 接口
/dev/vndbinder 供应商/供应商进程之间的 IPC,使用 AIDL 接口

binder,hwbinder,vndbinder之间的关系
Android O 独立 System、Vendor 分区后,增加了相应 Selinux 规则,System 进程不能按原有方式绑定 Vendor 服务。因为在 Android O 中,/dev/binder 设备节点成为了框架进程的专属节点,这意味着 Vendor 进程将无法再访问该节点,而要使用 kernel 新增的 hwbinder和 vndbinder。

Android O IPC 规范.png

About VNDK

Treble工程的目标是system/vendor进程解耦,让Android系统更新不依赖芯片方案商适配,要实现这一框架,需要先解耦system/vendor依赖(VNDK),并提供稳定的API/ABI, 再打通system/vendor直接沟通(HIDL),这玩意,要学习参考官网资料吧.
https://source.android.google.cn/devices/architecture/vndk

HIDL简介

Android O 引入 HIDL 语言,用于描述 O 中新增的跨进程 HAL 接口。原生架构下,Framework 作为 Client 端,Vendor 作为 Service 端。Framework 框架由谷歌提供,原生 HIDL要求保持稳定,适配工作主要在 Vendor Service。
Client 端:包含 Android 原生或海思扩展服务。
Server 端:Android 原生或芯片厂扩展 HAL 服务。
HIDL 文件(.hal)一般使用 Android.bp 编译。Android.bp 通过 hidl-gen 工具将 HIDL 文
件转换成
.h/*.cpp,再编译生成 android.hardware.xxxx@1.0.sovendor.xxx.hardware.xxxx@1.0

HIDL 流程示意图

HIDL示例Demo

  1. 创建HIDL接口
hardware/interfaces/demo/1.0/IDemo.hal 
package android.hardware.demo@1.0;

interface IDemo {
    doDemo(float bar) generates(int32_t status);
};
  1. 生成接口的执行代码
    这个命令会在hardware/interfaces/demo/1.0/default 下生成Demo.cpp 和 Demo.h两个文件
hidl-gen -o hardware/interfaces/demo/1.0/default -Lc++-impl -r android.hardware:hardware/interfaces -r android.hidl:system/libhidl/transport android.hardware.demo@1.0
  1. 生成makefile
    根目录执行脚本,自动生成*.hal 对应的 Android.bp 和 Android.mk 文件
./hardware/interfaces/update-makefiles.sh 
  1. 添加接口声明
    扩展接口需要在 vendor/manifest.xml 中声明, 或device/hisilicon/Hi37XXVXXX/manifest.xml
  <hal format="hidl">
      <name>android.hardware.demo</name>
      <transport>hwbinder</transport>
      <version>1.0</version>
      <interface>
          <name>IDemo</name>
          <instance>default</instance>
      </interface>
  </hal>
  1. 增加 hash 值
    HIDL 接口层是 Treble 架构的基础,原则上发布后不能变动,新接口应升级版本号。系统编译时会检查已发布接口 hash 值,防止篡改。已有接口对应 hash 值详见hardware/interfaces/current.txt。新增扩展接口,可在 Android 根目录执行命令生成 hash 值:
hidl-gen -L hash -r android.hardware:hardware/interfaces -r android.hidl:system/libhidl/transport android.hardware.demo@1.0 >> hardware/interfaces/current.txt
  1. 服务端实现
    代码目录结构如下,default目录下面Android.mk, service.cpp, android.hardware.demo@1.0-service.rc需要自
    己创建,目录结构如下,
hardware/interfaces/demo/1.0
├── Android.bp
├── Android.mk
├── default
│   ├── android.hardware.demo@1.0-service.rc
│   ├── Android.mk
│   ├── Demo.cpp
│   ├── Demo.h
│   └── service.cpp
└── IDemo.hal

Demo.cpp就添加一个打印

#include "Demo.h"
#include <log/log_main.h>
#define LOG_TAG "Demo"

namespace android {
namespace hardware {
namespace demo {
namespace V1_0 {
namespace implementation {

// Methods from ::android::hardware::demo::V1_0::IDemo follow.
Return<int32_t> Demo::doDemo(float bar) {
    // Demo就简单做个打印,
    ALOGD(" Hello Hidl Demo Bar is %f \n", bar);
    return int32_t {0};
}

// Methods from ::android::hidl::base::V1_0::IBase follow.

IDemo* HIDL_FETCH_IDemo(const char* /* name */) {
    return new Demo();
}

}  // namespace implementation
}  // namespace V1_0
}  // namespace demo
}  // namespace hardware
}  // namespace android

service.cpp将IDemo注册到hwservicemanager:

#define LOG_TAG "android.hardware.demo@1.0-service"
#include "Demo.h"
#include <hidl/LegacySupport.h>
#include <android/log.h>

using android::hardware::demo::V1_0::IDemo;
using android::hardware::defaultPassthroughServiceImplementation;

int main() {
    return defaultPassthroughServiceImplementation<IDemo>();
}

android.hardware.demo@1.0-service.rc启动脚本

service demo_hal_service /vendor/bin/hw/android.hardware.demo@1.0-service
    class hal
    user  root
    group  root 

Android.mk参考其他hidl模块写

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := android.hardware.demo@1.0-impl
LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_SRC_FILES :=  \
        Demo.cpp
LOCAL_C_INCLUDES := \
LOCAL_SHARED_LIBRARIES := \
    libutils \
    libcutils \
    liblog \
    libbinder \
    libhardware \
    libhidlbase \
    libhidltransport \
    libhidlmemory \
    android.hardware.demo@1.0 \

include $(BUILD_SHARED_LIBRARY)
############################################

include $(CLEAR_VARS)
LOCAL_MODULE := android.hardware.demo@1.0-service
LOCAL_INIT_RC := android.hardware.demo@1.0-service.rc
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_PROPRIETARY_MODULE := true

LOCAL_SRC_FILES := service.cpp

LOCAL_SHARED_LIBRARIES := \
    android.hardware.demo@1.0 \
    libbase \
    libcutils \
    libhidlbase \
    libhidltransport \
    liblog \
    libutils

include $(BUILD_EXECUTABLE)
  1. 实现客户端
//Android.bp
frameworks/native/cmds/demo$ cat *
cc_binary {
    name: "demo_client",
    srcs: ["demo_client.cpp"],
    shared_libs: [
        "libhidlbase",
        "libhidltransport",
        "libutils",
        "liblog",
        "android.hardware.demo@1.0",
    ],
}
//demo_client.cpp
#include <android/hardware/demo/1.0/IDemo.h>
#include <hidl/Status.h>
#include <hidl/LegacySupport.h>
#include <hidl/HidlSupport.h>

#include <utils/misc.h>
#include <utils/Log.h>
#define LOG_TAG "demo_client"
using android::hardware::demo::V1_0::IDemo;
using android::sp;

int main(int argc, char* argv[])
{
    android::sp<IDemo> service = IDemo::getService();
    if(service == nullptr){
        ALOGD("Failed to get service\n");
        return -1;
    }
    float bar = 1.0;
    service->doDemo(bar);
    return 0;
}
  1. 添加SELinux策略
    我这边把自定义SELinux策略放到了独立目录,
//device/honeybee/system/sepolicy/vendor/hal_demo.te
type hal_demo, domain;
type hal_demo_exec, exec_type, file_type, vendor_file_type;
hwbinder_use(hal_demo);
init_daemon_domain(hal_demo)
add_hwservice(hal_demo, hal_demo_hwservice)

//device/honeybee/system/sepolicy/vendor/file_contexts
# Vendor files
/(vendor|system/vendor)/bin/DoraemonService                                             u:object_r:DoraemonService_exec:s0
/(vendor|system/vendor)/bin/hw/android\.hardware\.demo@1\.0-service     u:object_r:hal_demo_exec:s0

//device/honeybee/system/sepolicy/vendor/hwservice.te
type hal_demo_hwservice, hwservice_manager_type;

//device/honeybee/system/sepolicy/vendor/hwservice_contexts
android.hardware.demo::IDemo  u:object_r:hal_demo_hwservice:s0
  1. 添加编译声明
    如果不添加,系统编译的时候不会编译你的模块,
PRODUCT_PACKAGES += \
       android.hardware.demo@1.0 \
       android.hardware.demo@1.0-impl \
       android.hardware.demo@1.0-service
  1. 生成二进制
    新增 Demo HIDL示例生成的二进制文件如下所示:
system/lib64/android.hardware.demo@1.0.so
system/lib/android.hardware.demo@1.0.so
vendor/etc/init/android.hardware.demo@1.0-service.rc
vendor/bin/hw/android.hardware.demo@1.0-service
vendor/lib64/hw/android.hardware.demo@1.0-impl.so
vendor/lib/hw/android.hardware.demo@1.0-impl.so
  1. Demo测试
    把demo_client 编译好push到/system/bin,
Hi3751V811:/system/bin # demo_client                                           
Hi3751V811:/system/bin # logcat | grep Demo
01-01 16:00:11.529  1809  1809 D Demo    :  Hello Hidl Demo Bar is 1.000000 

----Demo完毕。

HIDL平时需要参考系统模块写就好,如果要学习参考官网就好,或者下面博客
https://www.jianshu.com/p/ca6823b897b5

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335