Click the card below to follow Android System Engineer
No Pain, No Gain!
1. Introduction
Learning Philosophy: Understand one knowledge point at a time
Difficulty: ★★★☆☆
Source Code Environment: Android 9.0+
Hardware Environment: Qcom
Reading Time: 2 minutes
Some classmates in the group have raised questions about HIDL and AIDL. In response to these questions, I plan to output three articles. This article is the first one, analyzing the differences between several modes of HAL and HIDL, followed by a demo to solidify the concepts.
-
First, let’s look at a diagram of the development process from HAL to HIDL
Figure 1
-
What are the differences in usage between the four stages from HAL to HIDL?
-
First Stage: Legacy HAL: Represents the old HAL mode.
-
Second Stage: HIDL (passthrough): Also known as “passthrough mode”, it indicates using HIDL but does not require communication through the Binder IPC mechanism, and directly uses the Legacy HAL library to communicate with the driver.
-
Third Stage: HIDL (binderized + dopen): Indicates using the Binder mechanism, but in this mode, the HAL library is loaded through dlopen to communicate with the driver.
-
Fourth Stage: HIDL (binderized) mode: Indicates that the client communicates with the server through Binder IPC, and the server communicates directly with the driver.
-
Next, let’s write an example of using HIDL in binderized mode for communication.
2. Writing .hal file
# mkdir -p hardware/interfaces/led/1.0/default
# cd hardware/interfaces/led/1.0
# emacs ILed.hal
package [email protected];
interface ILed.hal{
helloWorld(string name) generates (string result);
}
3. hidl-gen.sh generates .cpp/h from .hal
1. If the hidl-gen tool is not available, compile it
# make hidl-gen -j16
2. Switch to the outermost directory of Android
# cd ~/android
Generate Android.bp, Led.cpp, Led.h in hardware/interfaces/led/1.0/default
3. Write the hidl-gen.sh script
# emacs hidl-gen.sh
#!/bin/bash
LOC=./hardware/interfaces/led/1.0/default
hidl-gen -o $LOC -Lc++-impl -randroid.hidl:system/libhidl/transport $PACKAGE
4. Execute the compilation
# ./hidl-gen.sh
4. Compile and Implement HIDL Service
<1>. Update Makefile, automatically generate Android.mk, Android.bp in the hardware/interfaces/led/1.0 directory
# ./hardware/interfaces/update-makefiles.sh
# mmm hardware/interfaces/led/1.0
# touch hardware/interfaces/led/1.0/default/[email protected]
# touch hardware/interfaces/led/1.0/default/service.cpp
<2>. Implement: [email protected]
service led_hal_service /vendor/bin/hw/[email protected]
class hal
user system
group system
<3>. Implement HIDL Service: service.cpp
#define LOG_TAG “[email protected]”
#include <android/hardware/led/1.0/ILed.h>
#include <hidl/LegacySupport.h>
#include “led.h”
using android::hardware::led::V1_0::ILed;
using android::hardware::led::V1_0::implementation::led;
using android::hardware::defaultPassthroughServiceImplementation;
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
using android::sp;
int main() {
#if 0=
// Passthrough mode
return defaultPassthroughServiceImplementation<Iled>();
#else
// Binder mode
sp<ILed> service = new led();
configureRpcThreadpool(1, true /*callerWillJoin*/)
service->registerAsService();
joinRpcThreadpool();
#endif
}
<4>. Configure system/libhidl/manifiest.xml
1. Development board path: /system/manifest.xml Or /vendor/manifest.xml
# emacs system/libhidl/manifiest.xml
<hal format=”hidl”>
<name>android.hardware.led</name>
<!– hwbinder: Binder mode; passthrough: passthrough mode–>
<transport>hwbinder</transport>
<version>1.0</version>
<interface> <name>ILed</name>
<instance>default</instance>
</interface>
</hal>
2. Push to system
# adb push manifiest.xml /system
3. Restart
# adb reboot
5. HIDL Server-side Compilation
<1>. Add executable program in Android.bp
# emacs hardware/interfaces/led/1.0/default/Android.bp
cc_binary {
name: “[email protected]”,
srcs: [“service.cpp”,
“ledImpl.cpp”],
shared_libs: [
“liblog”,
“libhardware”,
“libhidlbase”
“libhidltransport”,
“libutils”,
“[email protected]”, ],
}
# mmm hardware/interfaces/led/1.0/default
system/bin/[email protected] //server-side executable program
system/lib64/[email protected] //server-side defined so
system/lib/[email protected]
vendor/lib64/hw/[email protected] //server-side implementation of hwbinder so
vendor/lib/hw/[email protected]
6. Client-side
<1>. Android.bp
# cd hardware/interfaces/led/1.0/default
# emacs Android.bp // Add
cc_binary {
relative_install_path: “hw”,
defaults: [“hidl_defaults”],
name: “led_client”,
proprietary: true,
srcs: [“led_client.cpp”],
shared_libs: [
“liblog”
“libhardware”,
“libhidlbase”,
“libhidltransport”,
“libutils”,
],
}
#define LOG_TAG “LED_CLIENT”
#include <android/hardware/led/1.0/ILed.h>
#include <log/log.h>
using android::hardware::led::V1_0::ILed;
using android::hardware::hidl_vec;
using android::hardware::hidl_string;
using android::sp;
int main(){
sp<ILed> service = ILed::getService();
if( service == nullptr ){
ALOGE(“Can’t find ILed service…”);
return -1;
}
service->helloWorld(“HIDL!!!!”, [&](hidl_string result){
ALOGE(“%s(), line = %d, result = %s”,__FUNCTION__,__LINE__,result.c_str()); });
ALOGE(“%s(), line = %d”,__FUNCTION__,__LINE__);
return 0;
}
# mmm hardware/interfaces/led/1.0/default
vendor/bin/hw/led_client //client-side testing demo
// Push 32/64 bit so and bin to the development board
# adb push vendor_lib_hw/[email protected] /vendor/lib/hw
# adb push vendor_lib64_hw/[email protected] /vendor/lib64/hw
# adb push system_lib64/[email protected] /system/lib64
# adb push system_lib/[email protected] /system/lib
# adb push server_system_bin/[email protected] /system/bin
# adb push led_client /system/bin
# adb push manifest.xml /system // Need to restart
# adb logcat -s [email protected] LED_CLIENT led_server
// Start server-side
# /system/bin/[email protected]
// Start client-side
# /system/bin/led_client
7. Android APP as Client Configuration
# make update-api -j16
# mmm hardware/interfaces/led/1.0
# mmm hardware/interfaces/led/1.0/default
# setenforce 0
8. Conclusion
1. Legacy HAL: In early versions of Android, the Hardware Abstraction Layer (HAL) was implemented in C and communicated directly with the kernel drivers. This method tightly couples HAL code with the drivers, making code reuse and maintenance difficult. Additionally, Legacy HAL has security issues, such as drivers having direct access to user space data and resources.
2. HIDL (passthrough): HIDL is a new HAL implementation method that uses C++ and HIDL Interface Definition Language (IDL) to define HAL interfaces. In HIDL (passthrough) mode, applications communicate directly with drivers without needing to go through the Binder mechanism. This method can provide higher performance and lower latency, suitable for high-performance scenarios such as audio and video processing.
3. HIDL (binderized + dopen): In HIDL (binderized + dopen) mode, applications communicate with drivers through the Binder mechanism, and drivers can dynamically load through the dlopen mechanism. This method can provide better isolation and security and support dynamic loading of drivers.
4. HIDL (binderized): In HIDL (binderized) mode, applications communicate with drivers through the Binder mechanism, and drivers are pre-compiled and linked into the system. This method can provide better isolation and security while also offering higher performance and lower latency.
5. Currently, HIDL (binderized) mode is the mainstream HAL implementation method, providing better isolation and security while also offering high performance and low latency. HIDL (passthrough) and HIDL (binderized + dopen) modes are suitable for specific scenarios, such as high-performance scenarios and those requiring dynamic loading of drivers.
For complete source code, please send a private message.
Recommended Columns
Leave a Comment
Your email address will not be published. Required fields are marked *