HAL interface definition language(HIDL) is used to interface between HAL and its users. It creates a seamless way to invoke the HAL interface from either Java or cpp. All the inter process communication boiler plate code required is automatically created when the HIDL file is compiled.
This article outlines the method to create your custom HIDL. In this example HIDL interface is created under vendor instead of directly adding onto any other AOSP directories.
Create your hidl interface directory and the sub directories as shown below
Now time to create your hidl interface file IMycompanyMyhal.hal
package vendor.mycompany.hardware.myhal@1.0;
Types needed for your interface should be defined in types.hal. In the interface defined above we use the type 'MycompanyMyhalState' as the type.
Create the makefiles Android.bp & Android.mk. You can also use hidl-gen tool to automatically create these files.
Android.bp file example
Now moving onto the real deal, implement the interface. Our default implementation will be under '1.0/default' directory.
First we need to create a main function where the service is started, create 'service.cpp'.
Now for the actual implementation of the hal interface
Header file myhal.h
Interface implementation in myhal.cpp.
We need a makefile to compile this default implementation, so create Android.mk here to compile the implementation
Android use SELINUX policies to determine which processes to run in the system. To run your service SELINUX permissions needs to be enabled
Most sepolicy is built under system/sepolicy.
But your vendor could override it under device/vendorname/sepolicy/common
Since this is hw service add the component in 'hwservice_contexts' file
If application needs to find the HIDL interface it needs to be published in manifest file. Add it in one of the manifest.xml file for eg: device/<vendorname>/<platform>/manifest.xml
If SELINUX mode is 'permissive' this should work. If not, to allow our service to run, add 'allow' line in hwservice.te.
After compilation make sure your service is copied to /vendor/bin/hw and the '.rc' file is copied to /vendor/etc/init.
Also your service library('.so') file should be copied to /system/lib and /system/lib64.
This article outlines the method to create your custom HIDL. In this example HIDL interface is created under vendor instead of directly adding onto any other AOSP directories.
Create your hidl interface directory and the sub directories as shown below
vendor/mycompany/proprietary/interfaces/myhal/1.0/default
Now time to create your hidl interface file IMycompanyMyhal.hal
package vendor.mycompany.hardware.myhal@1.0;
interface IMycompanyMyhal {
/**
* Starts myhal data streaming
*
*/
oneway startMyhal();
/**
* Stops myhal data streaming
*
*/
oneway stopMyhal();
/**
* Gets current myhal state
*
*/
getCurrentState() generates (MycompanyMyhalState state);
};
Types needed for your interface should be defined in types.hal. In the interface defined above we use the type 'MycompanyMyhalState' as the type.
package vendor.mycompany.hardware.myhal@1.0;
enum MycompanyMyhalState : int32_t {
IDLE = 0,
PLAYING = 1,
ERROR = 2
};
Create the makefiles Android.bp & Android.mk. You can also use hidl-gen tool to automatically create these files.
Android.bp file example
// This file is autogenerated by hidl-gen. Do not edit manually.
filegroup {
name: "vendor.mycompany.hardware.myhal@1.0_hal",
srcs: [
"types.hal",
"IMycompanyMyhal.hal",
],
}
genrule {
name: "vendor.mycompany.hardware.myhal@1.0_genc++",
tools: ["hidl-gen"],
cmd: "$(location hidl-gen) -o $(genDir) -Lc++-sources \
-randroid.hidl:system/libhidl/transport \
-rvendor.mycompany.hardware:vendor/mycompany/proprietary/interfaces
vendor.mycompany.hardware.myhal@1.0",
srcs: [
":vendor.mycompany.hardware.myhal@1.0_hal",
],
out: [
"vendor/mycompany/hardware/myhal/1.0/types.cpp",
"vendor/mycompany/hardware/myhal/1.0/MycompanyMyhalAll.cpp",
],
}
genrule {
name: "vendor.mycompany.hardware.myhal@1.0_genc++_headers",
tools: ["hidl-gen"],
cmd: "$(location hidl-gen) -o $(genDir) -Lc++-headers \
-randroid.hidl:system/libhidl/transport \
-rvendor.mycompany.hardware:vendor/mycompany/proprietary/interfaces \
vendor.mycompany.hardware.myhal@1.0",
srcs: [
":vendor.mycompany.hardware.myhal@1.0_hal",
],
out: [
"vendor/mycompany/hardware/myhal/1.0/types.h",
"vendor/mycompany/hardware/myhal/1.0/hwtypes.h",
"vendor/mycompany/hardware/myhal/1.0/IMycompanyMyhal.h",
"vendor/mycompany/hardware/myhal/1.0/IHwMycompanyMyhal.h",
"vendor/mycompany/hardware/myhal/1.0/BnHwMycompanyMyhal.h",
"vendor/mycompany/hardware/myhal/1.0/BpHwMycompanyMyhal.h",
"vendor/mycompany/hardware/myhal/1.0/BsMycompanyMyhal.h",
],
}
cc_library {
name: "vendor.mycompany.hardware.myhal@1.0",
defaults: ["hidl-module-defaults"],
generated_sources: ["vendor.mycompany.hardware.myhal@1.0_genc++"],
generated_headers: ["vendor.mycompany.hardware.myhal@1.0_genc++_headers"],
export_generated_headers: ["vendor.mycompany.hardware.myhal@1.0_genc++_headers"],
vendor_available: true,
vndk: {
enabled: true,
},
shared_libs: [
"libhidlbase",
"libhidltransport",
"libhwbinder",
"liblog",
"libutils",
"libcutils",
],
export_shared_lib_headers: [
"libhidlbase",
"libhidltransport",
"libhwbinder",
"libutils",
],
}
cc_library {
name: "vendor.mycompany.hardware.myhal@1.0_vendor",
defaults: ["hidl-module-defaults"],
generated_sources: ["vendor.mycompany.hardware.myhal@1.0_genc++"],
generated_headers: ["vendor.mycompany.hardware.myhal@1.0_genc++_headers"],
export_generated_headers: ["vendor.mycompany.hardware.myhal@1.0_genc++_headers"],
vendor: true,
shared_libs: [
"libhidlbase",
"libhidltransport",
"libhwbinder",
"liblog",
"libutils",
"libcutils",
],
export_shared_lib_headers: [
"libhidlbase",
"libhidltransport",
"libhwbinder",
"libutils",
],
}
Android.mk file example# This file is autogenerated by hidl-gen. Do not edit manually. LOCAL_PATH := $(call my-dir) ################################################################################ include $(CLEAR_VARS) LOCAL_MODULE := vendor.mycompany.hardware.myhal-V1.0-java LOCAL_MODULE_CLASS := JAVA_LIBRARIES intermediates := $(call local-generated-sources-dir, COMMON) HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) LOCAL_JAVA_LIBRARIES := \ android.hidl.base-V1.0-java \ # # Build types.hal (MycompanyMyhalState) # GEN := $(intermediates)/vendor/mycompany/hardware/myhal/V1_0/MycompanyMyhalState.java $(GEN): $(HIDL) $(GEN): PRIVATE_HIDL := $(HIDL) $(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal $(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) $(GEN): PRIVATE_CUSTOM_TOOL = \ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ -Ljava \ -randroid.hidl:system/libhidl/transport \ -rvendor.mycompany.hardware:vendor/mycompany/proprietary/interfaces \ vendor.mycompany.hardware.myhal@1.0::types.MycompanyMyhalState $(GEN): $(LOCAL_PATH)/types.hal $(transform-generated-source) LOCAL_GENERATED_SOURCES += $(GEN) # # Build IMycompanyMyhal.hal # GEN := $(intermediates)/vendor/mycompany/hardware/myhal/V1_0/IMycompanyMyhal.java $(GEN): $(HIDL) $(GEN): PRIVATE_HIDL := $(HIDL) $(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IMycompanyMyhal.hal $(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal $(GEN): $(LOCAL_PATH)/types.hal $(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) $(GEN): PRIVATE_CUSTOM_TOOL = \ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ -Ljava \ -randroid.hidl:system/libhidl/transport \ -rvendor.mycompany.hardware:vendor/mycompany/proprietary/interfaces \ vendor.mycompany.hardware.myhal@1.0::IMycompanyMyhal $(GEN): $(LOCAL_PATH)/IMycompanyMyhal.hal $(transform-generated-source) LOCAL_GENERATED_SOURCES += $(GEN) include $(BUILD_JAVA_LIBRARY) ################################################################################ include $(CLEAR_VARS) LOCAL_MODULE := vendor.mycompany.hardware.myhal-V1.0-java-static LOCAL_MODULE_CLASS := JAVA_LIBRARIES intermediates := $(call local-generated-sources-dir, COMMON) HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) LOCAL_STATIC_JAVA_LIBRARIES := \ android.hidl.base-V1.0-java-static \ # # Build types.hal (MycompanyMyhalState) # GEN := $(intermediates)/vendor/mycompany/hardware/myhal/V1_0/MycompanyMyhalState.java $(GEN): $(HIDL) $(GEN): PRIVATE_HIDL := $(HIDL) $(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal $(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) $(GEN): PRIVATE_CUSTOM_TOOL = \ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ -Ljava \ -randroid.hidl:system/libhidl/transport \ -rvendor.mycompany.hardware:vendor/mycompany/proprietary/interfaces \ vendor.mycompany.hardware.myhal@1.0::types.MycompanyMyhalState $(GEN): $(LOCAL_PATH)/types.hal $(transform-generated-source) LOCAL_GENERATED_SOURCES += $(GEN) # # Build IMycompanyMyhal.hal # GEN := $(intermediates)/vendor/mycompany/hardware/myhal/V1_0/IMycompanyMyhal.java $(GEN): $(HIDL) $(GEN): PRIVATE_HIDL := $(HIDL) $(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IMycompanyMyhal.hal $(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal $(GEN): $(LOCAL_PATH)/types.hal $(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) $(GEN): PRIVATE_CUSTOM_TOOL = \ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ -Ljava \ -randroid.hidl:system/libhidl/transport \ -rvendor.mycompany.hardware:vendor/mycompany/proprietary/interfaces \ vendor.mycompany.hardware.myhal@1.0::IMycompanyMyhal $(GEN): $(LOCAL_PATH)/IMycompanyMyhal.hal $(transform-generated-source) LOCAL_GENERATED_SOURCES += $(GEN) include $(BUILD_STATIC_JAVA_LIBRARY)
Now moving onto the real deal, implement the interface. Our default implementation will be under '1.0/default' directory.
First we need to create a main function where the service is started, create 'service.cpp'.
#include <android-base/logging.h>
#include <hidl/HidlTransportSupport.h>
#include <utils/Looper.h>
#include <utils/StrongPointer.h>
#include "myhal.h"
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
int main(int /*argc*/, char** argv) {
android::base::InitLogging(argv,
android::base::LogdLogger(android::base::SYSTEM));
LOG(INFO) << "Mycompany myhal service booting up...";
configureRpcThreadpool(1, true /* callerWillJoin */);
// Setup hwbinder service
android::sp<vendor::mycompany::hardware::myhal::V1_0::IMycompanyMyhal> service =
new vendor::mycompany::hardware::myhal::V1_0::MycompanyMyhal();
CHECK_EQ(service->registerAsService(), android::NO_ERROR)
<< "Failed to register Mycompany myhal service";
joinRpcThreadpool();
LOG(INFO) << "Mycompany myhal service is terminating...";
return 0;
}
Now for the actual implementation of the hal interface
Header file myhal.h
#ifndef MYHAL_H_
#define MYHAL_H_
#include <functional>
#include <android-base/macros.h>
#include <vendor/mycompany/hardware/myhal/1.0/IMycompanyMyhal.h>
#include <utils/Looper.h>
#include "AudioEngine.h"
namespace vendor {
namespace mycompany {
namespace hardware {
namespace myhal {
namespace V1_0 {
using namespace vendor::mycompany::hardware::myhal::V1_0;
using namespace android::hardware;
/**
* Root HIDL interface object used to control the Myhal HAL.
*/
class MycompanyMyhal : public V1_0::IMycompanyMyhal {
public:
MycompanyMyhal();
//HIDL interfaces
Return<void> startMyhal() override;
Return<void> stopMyhal() override;
Return<MycompanyMyhalState> getMyhalState() override;
private:
std::unique_ptr<AudioEngine> myhalEngine_;
MycompanyMyhalState myhalState_;
DISALLOW_COPY_AND_ASSIGN(MycompanyMyhal);
};
} // namespace V1_0
} // namespace myhal
} // namespace hardware
} // namespace mycompany
} // namespace android
#endif // MYHAL_H_
Interface implementation in myhal.cpp.
#include <android-base/logging.h>
#include "myhal.h"
namespace vendor {
namespace mycompany {
namespace hardware {
namespace myhal {
namespace V1_0 {
MycompanyMyhal::MycompanyMyhal() : myhalState_(MycompanyMyhalState::IDLE) {
/* TODO: Do initialization here */
}
Return<void> MycompanyMyhal::startMyhal() {
/* TODO: Do your logic to start myhal */
myhalState_ = MycompanyMyhalState::PLAYING;
return Void();
}
Return<void> MycompanyMyhal::stopMyhal() {
/* TODO: Do your logic to stop myhal */
myhalState_ = MycompanyMyhalState::IDLE;
return Void();
}
Return<MycompanyMyhalState> MycompanyMyhal::getMyhalState() {
return myhalState_;
}
} // namespace V1_0
} // namespace myhal
} // namespace hardware
} // namespace mycompany
} // namespace android
Every service needs an '.rc' file to specify the service name, permissions etc and to start your service automatically - vendor.mycompany.hardware.myhal@1.0-service.rc
service mycompanymyhalservice /vendor/bin/hw/vendor.mycompany.hardware.myhal@1.0-service class hal user root group audio myhal system seclabel u:r:shell:s0
We need a makefile to compile this default implementation, so create Android.mk here to compile the implementation
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := vendor.mycompany.hardware.myhal@1.0-service LOCAL_MODULE_RELATIVE_PATH := hw LOCAL_PROPRIETARY_MODULE := true LOCAL_CPPFLAGS := -Wall -Werror -Wextra LOCAL_SRC_FILES := \ myhal.cpp \ service.cpp LOCAL_C_INCLUDES := \ frameworks/av/media/libaaudio/include LOCAL_SHARED_LIBRARIES := \ vendor.mycompany.hardware.myhal@1.0 \ libbase \ libcutils \ libhidlbase \ libhidltransport \ libaaudio \ liblog \ libnl \ libutils LOCAL_INIT_RC := vendor.mycompany.hardware.myhal@1.0-service.rc include $(BUILD_EXECUTABLE)
Android use SELINUX policies to determine which processes to run in the system. To run your service SELINUX permissions needs to be enabled
Most sepolicy is built under system/sepolicy.
But your vendor could override it under device/vendorname/sepolicy/common
Since this is hw service add the component in 'hwservice_contexts' file
vendor.mycompany.hardware.myhal::IMycompanyMyhal u:object_r:hal_telephony_hwservice:s0
If application needs to find the HIDL interface it needs to be published in manifest file. Add it in one of the manifest.xml file for eg: device/<vendorname>/<platform>/manifest.xml
<!-- Mycompany service --> <hal format="hidl"> <name>vendor.mycompany.hardware.myhal</name> <transport>hwbinder</transport> <impl level="generic"></impl> <version>1.0</version> <interface> <name>IMycompanyMyhal</name> <instance>default</instance> </interface> </hal>
If SELINUX mode is 'permissive' this should work. If not, to allow our service to run, add 'allow' line in hwservice.te.
After compilation make sure your service is copied to /vendor/bin/hw and the '.rc' file is copied to /vendor/etc/init.
Also your service library('.so') file should be copied to /system/lib and /system/lib64.
No comments:
Post a Comment