一简介
AIDL可以自动生成java语言,而java不像c/c++那样有union类型,因此HIDL部分的HAL语言是支持union类型的,当然这部分只限于生成c++代码,java代码不支持。从Andorid Q开始,HAL语言在java层面支持了union类型,可以使用safe_union来。那么hidl内部如何做到union的支持呢?
二 代码分析
比如我们添加一个safe_union类型,如下:
safe_union test2 {
int32_t type1;
int32_t type2;
};
通过hidl-gen生成test2.java,内容如下:
ublic final class test2 {
public test2() {
hidl_o = 0;
}
public static final class hidl_discriminator {
public static final byte type1 = 0; // int
public static final byte type2 = 1; // int
public static final String getName(byte value) {
switch (value) {
case 0: { return "type1"; }
case 1: { return "type2"; }
default: { return "Unknown"; }
}
}
private hidl_discriminator() {}
}
private byte hidl_d = 0;
private Object hidl_o = null;
public void type1(int type1) {
hidl_d = hidl_discriminator.type1;
hidl_o = type1;
}
public final void readFromParcel(android.os.HwParcel parcel) {
android.os.HwBlob blob = parcel.readBuffer(8 /* size */);
readEmbeddedFromParcel(parcel, blob, 0 /* parentOffset */);
}
public static final java.util.ArrayList<test2> readVectorFromParcel(android.os.HwParcel parcel) {
java.util.ArrayList<test2> _hidl_vec = new java.util.ArrayList();
android.os.HwBlob _hidl_blob = parcel.readBuffer(16 /* sizeof hidl_vec<T> */);
{
int _hidl_vec_size = _hidl_blob.getInt32(0 + 8 /* offsetof(hidl_vec<T>, mSize) */);
android.os.HwBlob childBlob = parcel.readEmbeddedBuffer(
_hidl_vec_size * 8,_hidl_blob.handle(),
0 + 0 /* offsetof(hidl_vec<T>, mBuffer) */,true /* nullable */);
_hidl_vec.clear();
for (int _hidl_index_0 = 0; _hidl_index_0 < _hidl_vec_size; ++_hidl_index_0) {
android.hardware.light.V2_0.test2 _hidl_vec_element = new android.hardware.light.V2_0.test2();
((android.hardware.light.V2_0.test2) _hidl_vec_element).readEmbeddedFromParcel(parcel, childBlob, _hidl_index_0 * 8);
_hidl_vec.add(_hidl_vec_element);
}
}
return _hidl_vec;
}
public final void readEmbeddedFromParcel(
android.os.HwParcel parcel, android.os.HwBlob _hidl_blob, long _hidl_offset) {
hidl_d = _hidl_blob.getInt8(_hidl_offset + 0);
switch (this.hidl_d) {
case hidl_discriminator.type1: {
hidl_o = 0;
hidl_o = _hidl_blob.getInt32(_hidl_offset + 4);
break;
}
case hidl_discriminator.type2: {
hidl_o = 0;
hidl_o = _hidl_blob.getInt32(_hidl_offset + 4);
break;
}
default: {
throw new IllegalStateException("Unknown union discriminator (value: " + hidl_d + ").");
}
}
}
};
java传输采用数组的形式,test2类型为例,里面保存两个int类型,占用4个字节,对应的数组占用16个字节,数组[0]保存类型,数组【1】保存值,数组【2】保存数组大小,剩下【3】作为padding
c++的对应实现
struct test2 final {
enum class hidl_discriminator : uint8_t {
type1 = 0, // int32_t
type2 = 1, // int32_t
};
test2();
~test2();
test2(test2&&);
test2(const test2&);
test2& operator=(test2&&);
test2& operator=(const test2&);
void type1(int32_t);
int32_t& type1();
int32_t type1() const;
void type2(int32_t);
int32_t& type2();
int32_t type2() const;
// Utility methods
hidl_discriminator getDiscriminator() const;
constexpr size_t hidl_getUnionOffset() const {
return offsetof(::android::hardware::light::V2_0::test2, hidl_u);
}
private:
void hidl_destructUnion();
hidl_discriminator hidl_d __attribute__ ((aligned(1))) ;
union hidl_union final {
int32_t type1 __attribute__ ((aligned(4)));
int32_t type2 __attribute__ ((aligned(4)));
hidl_union();
~hidl_union();
} hidl_u;
static_assert(sizeof(::android::hardware::light::V2_0::test2::hidl_union) == 4, "wrong size");
static_assert(__alignof(::android::hardware::light::V2_0::test2::hidl_union) == 4, "wrong alignment");
static_assert(sizeof(::android::hardware::light::V2_0::test2::hidl_discriminator) == 1, "wrong size");
static_assert(__alignof(::android::hardware::light::V2_0::test2::hidl_discriminator) == 1, "wrong alignment");
};
可以看到C++对于test2类型的保存也是按照java顺序进行的,由于union是4个字节对齐,因此会给type空出3个字节,与java实现了一一对应
hidl_discriminator hidl_d __attribute__ ((aligned(1))) ;
union hidl_union final {
int32_t type1 __attribute__ ((aligned(4)));
int32_t type2 __attribute__ ((aligned(4)));
hidl_union();
~hidl_union();
} hidl_u;
三 总结
HIDL当初设计是给HAL使用的,从R开始HIDL逐渐切换成AIDL,safe_union无法在binder使用。但是binder之间数据传递得到了统一,无需再进行切换。