Hope you are doing well !!!. Today I am going to discuss a Practical example of AIDLs for HIDLs.
Previous post Explain AIDLs for HIDLs
Here is the plan :
Third party App take String input from User and pass it to Android Kernel module to get the reverse of String.
Kernel Module
We need to create a kernel module named as "invstr" and add our logic to reverse the string that coming from User App. I am assuming that you guys know how to add a new module in kernel and build it.If you guys are not familiar to add new module in kernel and build. I will add a separate post on it.
This guide assumes that invstr module is loaded as below:
+ insmod /system/lib/modules/invstr.ko
+ chown system system /dev/invstr
+ chmod 0600 /dev/invstr
AOSP
build
- make
- target
- product
base_vendor.mk
Include new packages+ PRODUCT_PACKAGES += \ + android.hardware.invstr \ + android.hardware.invstr-service \ + Invstr
hardware
interfaces
invstr
aidl
- Android.bp
android
- hardware
- invstr
IInvstr.aidl
@VintfStability interface IInvstr { String getChars(); void putChars(in String msg); }
- invstr
- hardware
default
- Android.bp
- Invstr.h
- Invstr.cpp
- service.cpp
compatible_matrices
compatible_matrix.current.xml
+ <hal format="aidl" optional="true"> + <name>android.hardware.invstr</name> + <version>1</version> + <interface> + <name>IInvstr</name> + <instance>default</instance> + </interface> + </hal>
Define HAL Interface#
Create a new AIDL file in the folder hardware/interfaces/invstr/aidl
:
package android.hardware.invstr;
@VintfStability
interface IInvstr
String getChars();
void putChars(in String msg);
}
hardware/interfaces/invstr/aidl/Android.bp
- Select the backend: We will use NDK (as recommended), so declare the CPP backend as false
- Set vendor: true and remove vendor_available because this is a custom vendor HAL
- Remove vndk section, so this HAL is located in /vendor only
mmm hardware/interfaces/invstr/
you will get error about the API missing.
We need to freeze the API by running:
m android.hardware.invstr-update-ap
Ok, build it again:
mmm hardware/interfaces/invstr/
Then include the module to the system:
PRODUCT_PACKAGES += \
android.hardware.invstr \
Implement HAL#
We will use the ndk_platfrom
library, therefore, let check the generated code for ndk_platform
.
cd out/soong/.intermediates/hardware/interfaces/invstr/aidl/android.hardware.invstr-V1-ndk_platform-source
find .
.
./gen
./gen/timestamp
./gen/include
./gen/include/aidl
./gen/include/aidl/android
./gen/include/aidl/android/hardware
./gen/include/aidl/android/hardware/invstr
./gen/include/aidl/android/hardware/invstrBpInvstr.h
./gen/include/aidl/android/hardware/invstr/IInvstr.h
./gen/include/aidl/android/hardware/invstr/BnInvstr.h
./gen/android
./gen/android/hardware
./gen/android/hardware/invstr
./gen/android/hardware/invstr/IInvstr.cpp.d
./gen/android/hardware/invstr/IInvstr.cpp
Our interface APIs are converted to APIs as below:
IInvstr.hvirtual ::ndk::ScopedAStatus getChars(std::string* _aidl_return) = 0;
virtual ::ndk::ScopedAStatus putChars(const std::string& in_msg) = 0;
They are virtual functions and then need to be defined.
Header file
hardware/interfaces/invstr/aidl/default/Invstr.h
Implementation
hardware/interfaces/invstr/aidl/default/service.cpp
Build Service
Similar to the HIDL module, we will create a cc_binary
module in theAndroid.bp
.
AIDL has three different backends: Java, NDK, CPP. To use Stable AIDL, you must always use the system copy of libbinder
at system/lib*/libbinder.so
and talk on /dev/binder
. For code on the vendor image, this means that libbinder
(from the VNDK) cannot be used: this library has an unstable C++ API and unstable internals. Instead, native vendor code must use the NDK backend of AIDL, link against libbinder_ndk
(which is backed by system libbinder.so
), and link against the -ndk_platform
libraries created by aidl_interface
entries.
Then include the service to the system:
PRODUCT_PACKAGES += \
android.hardware.invstr \
android.hardware.invstr-service \
Run Service
We need to define the service with the init
process, so it can start whenever the hal
class is started. To do this, we will create a new android.hardware.invstr-service.rc
:
service android.hardware.invstr-service /vendor/bin/hw/android.hardware.invstr-service
interface aidl android.hardware.invstr.IInvstr/default
class hal
user system
group system
Expose AIDL InterfaceA new VINTF AIDL object should be declared as below:
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.invstr</name>
<version>1</version>
<fqname>IInvstr/default</fqname>
</hal>
</manifest>
If this is a new package, add it to the latest framework compatibility matrix. If no interface should be added to the framework compatibility matrix (e.g. types-only package), add it to the exempt list in libvintf_fcm_exclude
.
hardware/interfaces/compatibility_matrices/compatibility_matrix.current.xml
<hal format="aidl" optional="true">
<name>android.hardware.invstr</name>
<version>1</version>
<interface>
<name>IInvstr</name>
<instance>default</instance>
</interface>
</hal>
Define SELinux Policy for HAL service#
To make the service run at boot, HAL service needs to be registered to system under a security policy.
Declare new type
system/sepolicy/public/hwservice.te
type hal_invstr_hwservice, hwservice_manager_type;
Set compatibility
Ignore in API 31, which also ignore in lower API:
system/sepolicy/private/compat/31.0/31.0.ignore.cil
(type new_objects)
(typeattribute new_objects)
(typeattributeset new_objects
( new_objects
hal_invstr_hwservice
)
)
Add service path
Add a new label in the:
/(vendor|system/vendor)/bin/hw/android\.hardware\.invstr-service u:object_r:hal_invstr_service_exec:s0
Set service context interface:
system/sepolicy/private/hwservice_contexts
android.hardware.invstr::IInvstr u:object_r:hal_invstr_hwservice:s0
Declare attribute:
system/sepolicy/public/attributes
hal_attribute(invstr);
this is macro for adding below attributes:
attribute hal_invstr;
attribute hal_invstr_client;
attribute hal_invstr_server;mon
Define default domain:
type hal_invstr_service, domain;
hal_server_domain(hal_invstr_service, hal_invstr)
type hal_invstr_service_exec, exec_type, vendor_file_type, vendor_file_type, file_type;
init_daemon_domain(hal_invstr_service)
Set binder policy:
system/sepolicy/public/hal_invstr.te
binder_call(hal_invstr_client, hal_invstr_server)
binder_call(hal_invstr_server, hal_invstr_client)
hal_attribute_hwservice(hal_invstr, hal_invstr_hwservice)
Declare system_server as client of HAL service:
system/sepolicy/private/system_server.te
hal_client_domain(system_server, hal_invstr)
Deliver HAL module#
Include HAL service and the test app to the PRODUCT_PACKAGES
:
+ PRODUCT_PACKAGES += \
+ android.hardware.invstr-service \
This will include below files to system:
/vendor/lib/hw/android.hardware.invstr-service
User App
The User App will be very simple to test the hardware. It contains an EditText
to get user input, a Button
to execute commands, and a TextView
to display the result.
I will Add user App details as separate blog . Current post itself become too long.
Thanks you guys for bearing with me to read this long post. Hope it help you guys as one stop solution to Use AIDL as HIDL.