说明
:转载自Android官网https://source.android.com/devices/architecture/hal/framework-testing,方便国内查看。
HIDL HALs guarantee the Android core system (aka system.img or the framework) is backwards compatible. While Vendor Test Suite (VTS) tests ensure that HALs work as expected (e.g. 1.1 HAL tests are run on all 1.2 implementations), framework testing is needed to ensure that when a supported HAL (1.0, 1.1, or 1.2) is provided, the framework works properly with that HAL.
For details on HAL interface definition language (HIDL), refer to HIDL, HIDL versioning, and HIDL HAL Deprecation.
There are two types of HAL upgrades: major and minor. Most systems include only one HAL implementation, but multiple implementations are supported. For example:
android.hardware.teleport@1.0 # initial interface
android.hardware.teleport@1.1 # minor version upgrade
android.hardware.teleport@1.2 # another minor version upgrade
...
android.hardware.teleport@2.0 # major version upgrade
...
The system partition typically includes a framework daemon (such as teleportd
) that manages communication with a specific group of HAL implementations. Alternatively, systems might instead include a system library (such as android.hardware.configstore-utils
) that implements convenient client behavior. In the example above, teleportd
must work no matter what version of the HAL is installed on the device.
If major version upgrades (1.0, 2.0, 3.0, etc.) exist, at least one Google-maintained device must maintain an implementation of each major version until that version is deprecated. If no Google-maintained device ships with a specific major version, Google continues to maintain an old implementation of that major version.
Such maintenance adds minor additional overhead because the old implementation (e.g. 1.2) can be kept and not used by default when a new implementation (e.g. 2.0) is created.
Testing the backwards compatibility of minor versions in the framework requires a way to automatically generate minor version implementations. Given the restrictions around Google-maintained versions, hidl-gen
will only (and can only) generate adapters that take a 1.(x+n) implementation and provide a 1.x implementation; it cannot generate a 1.0 implementation from a 2.0 implementation (by definition of a major version).
For example, to run 1.1 tests on a 1.2 implementation, you must be able to simulate having a 1.1 implementation. The 1.2 interfaces can automatically be used as 1.1 implementation with some slight differences in behavior (such as the framework manually checking what version something is or calling castFrom
on it).
The basic idea is this:
These adapters completely hide the fact that the implementation is actually backed by a 1.2 interface and only provides the 1.1 interface (the adapter takes a 1.2 interface and makes it look like a 1.1 interface).
In this example, the Android device runs android.hardware.foo@1.1::IFoo/default
. To ensure a client works properly with android.hardware.foo@1.0::IFoo/default
:
$ PACKAGE=android.hidl.allocator@1.0-adapter
$ INTERFACE=IAllocator
$ INSTANCE=ashmem
$ THREAD_COUNT=1 # can see current thread use on `lshal -i -e`
$ m -j $PACKAGE
$ /data/nativetest64/$PACKAGE/$PACKAGE $INTERFACE $INSTANCE $THREAD_COUNT
Trying to adapt down android.hidl.allocator@1.0-adapter/default
Press any key to disassociate adapter.
adb shell stop
(or start
) or simply kill the process.
hidl-gen
automatically adds additional build targets for the adapters for every interface specified with hidl_interface
in the build system. For package a.b.c@x.y
, there is an additional C++ target a.b.c@x.y-adapter
.
Note
: No java adapter needs to be made because a C++ adapter can always be used to wrap a Java service.
An adapter for a.b.c@x.y
takes as an input some implementation, a.b.c@x.(y+n)::ISomething/instance-name
, and must register a.b.c@x.y::ISomething/instance-name
which must also unregister the y+n
implementation.
Given the following sample interface:
// IFoo.hal
package a.b.c@1.0;
interface IFoo {
doFoo(int32_t a) generates (int64_t b);
doSubInterface() generates (IFoo a);
};
The code provided by a.b.c@1.0-adapter
is similar to the sample below:
// autogenerated code
// in namespace a::b::c::V1_0::IFoo
struct MockFoo {
// takes some subclass of V1_0. May be V1_1, V1_2, etc...
MockFoo(V1_0::IFoo impl) mImpl(impl) {}
Return<int64_t> doFoo(int32_t a) {
return this->mImpl->doFoo(a);
}
Return<V1_0::ICallback> doSubInterface() {
// getMockForBinder returns MockCallback instance
// that corresponds to a particular binder object
// It can't return a new object every time or
// clients using interfacesSame will have
// divergent behavior when using the mock.
auto _hidl_out = this->mImpl->doSubInterface();
return getMockForBinder(_hidl_out);
}
};
Data values are forwarded exactly into and out of the auto-generated mock class, except for sub interfaces, which are returned. These interfaces must be wrapped in the corresponding most recent callback object.