AndroidHIDL学习-HelloWord⼊门(整理1)
Android HIDL学习(整理1)
概述
HAL 接⼝定义语⾔(简称 HIDL,发⾳为“hide-l”)是⽤于指定 HAL 和其⽤户之间的接⼝的⼀种接⼝描述语⾔ (IDL)。HIDL 允许指定类型和⽅法调⽤(会汇集到接⼝和软件包中)。从更⼴泛的意义上来说,HIDL 是⽤于在可以独⽴编译的代码库之间进⾏通信的系统。
HIDL 旨在⽤于进程间通信 (IPC)。进程之间的通信采⽤ Binder 机制。对于必须与进程相关联的代码库,还可以使⽤直通模式(在 Java 中不受⽀持)。
HIDL 可指定数据结构和⽅法签名,这些内容会整理归类到接⼝(与类相似)中,⽽接⼝会汇集到软件包中。尽管 HIDL 具有⼀系列不同的关键字,但 C++ 和 Java 程序员对 HIDL 的语法并不陌⽣。此外,HIDL 还使⽤ Java 样式的注释。
⼊⼿准备
程序员有个癖好,⽆论是学习什么新知识,都喜欢以HelloWorld作为⼀个简单的例⼦来开头,咱们也不例外。
OK,咱这⾥都是⼲货,废话就不多说啦,学习HIDL呢咱们还是需要⼀些准备⼯作和门槛的。
准备⼯作:
Android BSP编译环境,需要做整编
Android 设备的BSP代码
Android设备,⽤来跑测试代码
我这边使⽤的是MTK的⼀款设备,基于Android O系统这个平台来做开发。
当然了,如果⼿头上没有设备的话,你也可以使⽤Andnroid模拟器做开发,Android模拟器的镜像可以使⽤官⽅的AOSP代码来编译,但是注意的是如果使⽤模拟器,kernel要去下载goldfish的代码,这个我这⾥就不赘述了,可以google了解⼀下。
实例应⽤
接下来我们开始第⼀个HIDL应⽤实例,我们需要给这个简单的例⼦起⼀个⽜逼的名字,我这⾥叫Naruto,不要问我为什么,哥是⼀个铁打的⽕影迷,哈哈,就这么定了,就叫Naruto了,那么那么我们就来说⼀段故事吧:
咱们可是要写⼀个Android的HAL,⼤家不要把初衷搞混了,我们看看AOSP有哪些HAL:
Camera
Audio
Sensor
怎么用java编写app软件等等
这些啊都是Android设备上的硬件,因为Google理论上只关⼼Android的框架层和上层软件,但是上层软件依赖于底层的硬件实现,但是每家⼿机⼚商,或者说是CPU⼚商底层硬件的实现都是不⼀样的,所以这个HAL层基本都是⼿机⼚商或者CPU⼚商去实现的,Google只是作为⼀个框架的指导,和Framework层API的接⼝定义,这些接⼝的实现都得由HAL去完成。
那么我们的Naruto就肩负了这个重任喽,控制底层硬件嘛,底层硬件都是由Linux kernel驱动控制的,提供⽂件读写就可以简单控制驱动啦,咱们这边就搞虚拟驱动好了,省略了kernel driver的实现;
等等,我们这个是HelloWorld,好吧,Naruto,你就提供⼀个HelloWorld的接⼝吧,⼤材⼩⽤了。⽬的是让我们知道写⼀个HIDL的流程这就够了
1.HIDL接⼝⽂件定义
进⼊代码,我们假设Naruto作为标准AOSP的HAL,我们就把代码揉进标准HAL(hardware/interface)层去,进⼊代码⽬录创建HIDL⽬录:
mkdir -p hardware/interfaces/naruto/1.0/default
接着创建接⼝描述⽂件INaruto.hal,放在刚才创建的1.0/⽬录中:
// INaruto.hal
package android.hardware.naruto@1.0;
interface INaruto {
helloWorld(string name) generates (string result);
};
没错这是⼀个Google定义的语⾔格式,C++和Java的结合体,我相信咱们搞Android BSP来发的,什么语⾔不会呢,对不:汇编:bootloader和kernel中可能会⽤到
C语⾔:这你丫不会,你玩⽑的Linux Kernel啊
C++:这你丫不会,你就别搞Android底层开发了,HAL和中间库
Java:这么再不会就⾃杀吧,framework和app的代码都是Java的
Python:这个不会么也没事,编译相关的
Shell:这个不可能不会
Makefile:肯定会的,不会跳楼吧
这⾥我们定义了⼀个INaruto接⼝⽂件,简单的添加了⼀个helloWorld接⼝,传⼊是⼀个string,返回⼀个string,后⾯我们会来实现这个接⼝。
2. ⽣成HAL相关⽂件
如上,hal接⼝⽂件已经定义完成,接下来我们需要继承实现这个接⼝,那么我们应该如何继承如何编写
呢,幸运的是Google还是帮我们提供了⼀套⼯具hidl-gen来⽣成HAL层相关的代码框架和代码实例,这样⼦我们只需要关⼼实现部分,⽽不需要写⼀堆⽆⽤代码,浪费时间在搞Makefile和⼀些低级错误上。
hidl-gen 可以⾃动帮我们⽣成hal层实例框架和Android.mk/bp编译控制
因此,系统已经帮我们提供了⼀个执⾏脚本hardware/interface/update-makefiles.sh, 如下执⾏将会⾃动为我们⽣成所需要的⽂件:
./hardware/interface/update-makefiles.sh
查看我们最新的代码⽬录: hardware/interface/naruto:
├── 1.0
│├── Android.bp //⾃动⽣成
│├── Android.mk //⾃动⽣成
│├── default
││├── Android.bp //需要⾃⼰编写
││├── android.hardware.naruto@ //⽤于加⼊开机启动服务
││├── Naruto.cpp //⾃动⽣成
││├── Naruto.h //⾃动⽣成
││└── service.cpp // hidl服务端注册⼊⼝程序
│└── INaruto.hal //定义接⼝
└── Android.bp //⾃动⽣成
是不是so easy,我们写代码就写了⼀个INaruto.hal,其余代码都是⾃动⽣成的,特别是Naruto.cpp和Naruto.h这两个⽂件是实现接⼝的关键⽂件。
3. 实现HAL服务端的共享库
打开Naruto.h⽂件:
#ifndef ANDROID_HARDWARE_NARUTO_V1_0_NARUTO_H
#define ANDROID_HARDWARE_NARUTO_V1_0_NARUTO_H
#include<android/hardware/naruto/1.0/INaruto.h>
#include<hidl/MQDescriptor.h>
#include<hidl/Status.h>
namespace android {
namespace hardware {
namespace naruto {
namespace V1_0 {
namespace implementation {
using::android::hardware::hidl_array;
using::android::hardware::hidl_memory;
using::android::hardware::hidl_string;
using::android::hardware::hidl_vec;
using::android::hardware::Return;
using::android::hardware::Void;
using::android::sp;
struct Naruto :public INaruto {
// Methods from INaruto follow.
Return<void>helloWorld(const hidl_string& name, helloWorld_cb _hidl_cb) override;
// Methods from ::android::hidl::base::V1_0::IBase follow.
};
// FIXME: most likely delete, this is only for passthrough implementations
// extern "C" INaruto* HIDL_FETCH_INaruto(const char* name);
}// namespace implementation
}// namespace V1_0
}// namespace naruto
}// namespace hardware
}// namespace android
#endif// ANDROID_HARDWARE_NARUTO_V1_0_NARUTO_H
我们知道,HIDL的实现有两种⽅式,⼀种是Binderized模式,另⼀种是Passthrough模式,我们看到上⾯有两⾏注释掉的代码,看来这个代码是关键,来选择实现⽅式是Binderized还是Passthrough。
我们这⾥使⽤Passthrough模式来演⽰,其实⼤家后⾯尝试这两种⽅式后会发现其实这两种本质是⼀样的,⽬前⼤部分⼚商使⽤的都是Passthrough来延续以前的很多代码,但是慢慢的都会被改掉的,所以我们来打开这个注释 - extern “C” INaruto*
HIDL_FETCH_INaruto(const char* name);
打开并修改Naruto.cpp:
#include"Naruto.h"
namespace android {
namespace hardware {
namespace naruto {
namespace V1_0 {
namespace implementation {
// Methods from INaruto follow.
Return<void> Naruto::helloWorld(const hidl_string& name, helloWorld_cb _hidl_cb){
// TODO implement
char buf[100];
memset(buf,0,100);
snprintf(buf,100,"HelloWorld, %s", name.c_str());
hidl_string result(buf);
_hidl_cb(result);
return Void();
}
// Methods from ::android::hidl::base::V1_0::IBase follow.
INaruto*HIDL_FETCH_INaruto(const char*/* name */){
return new Naruto();
}
}// namespace implementation
}// namespace V1_0
}// namespace naruto
}// namespace hardware
}// namespace android
这个⽂件我们做了两处改动:
打开了HIDL_FETCH_I的注释,让我们的HIDL使⽤Passthrough⽅式去实现
添加helloWorld函数的实现,简单的做了字符串拼接(学过C/C++)的同学应该都看得懂
接下来我们编写⼀下default/Android.bp⽂件⽣成我们需要impl实现的so库。
default/Android.bp
cc_library_shared {
name: "android.hardware.naruto@1.0-impl",
relative_install_path: "hw",
proprietary: true,
srcs: [
"Naruto.cpp",
],
shared_libs: [
"libhidlbase",
"libhidltransport",
"libutils",
"android.hardware.naruto@1.0",
],
}
最终会⽣成⼀个android.hardware.naruto@1.0-impl.so, ⽣成在/vendor/lib/hw/下,如果是64bits的平台会⽣成在/vendor/lib64/hw,在这⾥我⽤的是32bits平台,最终会⽣成在/vendor/lib/hw/⽬录下;
我们可以⽤mmm编译⽣成。
mmm hardware/interface/naruto
这样将会⽣成两个so⽂件,⼀个是INaruto接⼝框架库⽂件:android.hardware.naruto@1.0.so ⼀个是INaruto实现接⼝库⽂件:android.hardware.naruto@1.0-impl.so
他们直接的调⽤流程⼤概如下:
4. Hal server端启动注册程序
现在,我们有了HIDL接⼝及接⼝的实现实例,接下来需要将这个服务端注册到HWServiceManager中,客户端才能通过binder接⼝getService()获取到服务端的接⼝并使⽤它。
还记得我们之前创建的两个⽂件吗,我们还没有去实现呢,先来看⼀下rc⽂件
# android.hardware.naruto@
service naruto_hal_service /vendor/bin/hw/android.hardware.naruto@1.0-service
class hal
user system
group system
很简单,就是在设备启动的时候执⾏/vendor/bin/hw/android.hardware.naruto@1.0-service程序,这个程序就是去注册服务的到serviceManager管理中的,具体实现如下:
service.cpp⽂件:
// service.cpp
# define LOG_TAG "android.hardware.naruto@1.0-service"
# include<android/hardware/naruto/1.0/INaruto.h>
# include<hidl/LegacySupport.h>
using android::hardware::naruto::V1_0::INaruto;
using android::hardware::defaultPassthroughServiceImplementation;
int main(){
return defaultPassthroughServiceImplementation<INaruto>();
}
这个service是注册了INaruto接⼝⽂件⾥⾯的接⼝,作为binder server端,很简单就⼀句话,因为我们使⽤了passthrough的模
式,Android帮我们封装了这个函数,不需要我们⾃⼰去addService啦,直接调⽤defaultPassthroughServiceImplementation即可。还有另⼀种注册⽅式是针对binderies的:
::android::sp<IFoo> myFoo =new FooImpl();
::android::sp<IFoo> mySecondFoo =new FooAnotherImpl();
status_t status = myFoo->registerAsService();
status_t anotherStatus = mySecondFoo->registerAsService("another_foo");
接下来,在Android.bp中添加对应的编译控制逻辑:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论