This article explains how to create your own Android service to manage a dedicated hardware resource. It is intended for distribution package users.
1. Prerequisites[edit source]
The environment used must be installed using the right Distribution Package for your selected microprocessor device. See Distribution_Package.
To be able to execute following instructions you need to work from your distribution root directory and initialize your environment:
source build/envsetup.sh
lunch aosp_<BoardId>-userdebug
2. Hardware service[edit source]
First of all you need to create your HIDL files to be able to interact with your hardware. They act as the interface between your hardware and Android. You can refer to the HIDL manual [1]. For more information on HAL definition you can refer to the official AOSP documentation[2].
2.1. Creation[edit source]
To create your interface you need to create a folder myinterface
in source tree path hardware/interfaces
.
Inside the interfaces
folder, create a version folder for your interface like hardware/interfaces/myinterface/1.0/
.
2.2. Hardware Interface (HIDL)[edit source]
Define as many classes and types you need to be able to interact with your hardware. Those functions must be implemented in your device HAL folder. (See Implement the vendor HAL)
IMyClass.hal
package android.hardware.myinterface@1.0; interface IMyClass { myFunct1() generates (bool ret); myFunct2(string name) generates (bool ret, MyType val); };
types.hal
package android.hardware.myinterface@1.0; struct MyType { uint32_t id; bool state; };
2.3. Generation[edit source]
Android.bp[3]:
hidl_interface { name: "android.hardware.myinterface@1.0", root: "android.hardware", vndk: { enabled: true, }, srcs: [ "types.hal", "IMyClass.hal", ], interfaces: [ "android.hidl.base@1.0", ], types: [ "MyType", ], gen_java: true, }
2.4. Hash creation[edit source]
This step is not required to make it work but it must be done at least once when the interfaces are finalized nearing the end of development. When your interface is done you must execute
hidl-gen -L hash android.hardware.myinterface@1.0 >> hardware/interfaces/current.txt
This adds a specific hash matching your hardware interface. This ensures the use of the appropriate interface by the framework. Do not forget to update the hash if you make changes to the interface.
3. Service (AIDL)[edit source]
In order to interact with your hardware from an application you need to add your API on top of the already existing Android API.
3.1. Creation[edit source]
To create your API you need to create a "myinterface" subfolder at frameworks/base/core/java/android/
.
3.2. Interface (AIDL)[edit source]
Create as many classes you need to define your API. All files need to have the .aidl
extension. For more information on how to create AIDL files, see[4].
frameworks/base/core/java/android/myinterface/IMyClass.aidl
package android.myinterface; interface IMyClass { void myAidlFunct1(); }
You need then to generate Java classes matching your AIDL files. Those functions will be the ones exposed to the application developer.
frameworks/base/core/java/android/myinterface/MyClassManager.java
package android.myinterface; import android.util.AndroidException; import android.util.Log; import android.util.Slog; import android.content.Context; import android.os.RemoteException; public class MyClassManager { private final Context mContext; private final IMyClass mService; public MyClassManager(Context ctx, IMyClass service) { mContext = ctx; mService = service; } public void myAidlFunct1() { try{ mService.myAidlFunct1(); } catch (RemoteException ex){ Slog.e("MyClassManager", "Unable to contact the remote MyClassManager"); } } }
3.3. Generation[edit source]
To integrate your changes you need to adapt the Android.bp
file in framework/base
.
Include all the AIDL files you have created beforehand.
java_library { . . . "core/java/android/myinterface/IMyClass.aidl", }
3.4. Update API[edit source]
Add the following line in build/make/target/product/vndk/<current api version>.txt
(ex: 28.txt
for API 28) and in build/make/target/product/vndk/current.txt
VNDK-core: android.hardware.myinterface@1.0.so
When your interface is well defined you need to execute the command:
make update-api
This command updates all the necessary files to integrate your API in the distribution.
4. Implement the vendor HAL[edit source]
To implement the HAL you have just created please refer to the AOSP documentation[5].
5. Custom Service[edit source]
To be able to connect everything together you need to create an independent service that will run in background and reply to API calls.
5.1. Package apps[edit source]
Create a folder in packages/apps
with the name of your service (MyInterfaceService
)
prepare the folder structure as follows:
- AndroidManifest.xml
- Android.mk
- src
- com
- android
- myinterfaceservice
- MyInterfaceServiceApp.java
- IMyClassImpl.java
- myinterfaceservice
- android
- com
5.2. Implement service[edit source]
MyInterfaceServiceApp.java
package com.android.myinterfaceservice;
import android.util.Log;
import android.util.Slog;
import android.os.IBinder;
import android.app.Application;
import android.os.ServiceManager;
import android.myinterface.IMyClass;
public class MyInterfaceServiceApp extends Application {
private static final String REMOTE_SERVICE_NAME = IMyClass.class.getName();
private static final String TAG = "MyInterfaceServiceApp";
private IBinder mMyClassManager = null;
public void onCreate() {
super.onCreate();
Slog.d(TAG, "Build service");
mMyClassManager = new IMyClassImpl();
ServiceManager.addService(REMOTE_SERVICE_NAME, mMyClassManager);
}
public void onTerminate() {
super.onTerminate();
}
}
IMyClassImpl.java
package com.android.myinterfaceservice;
import android.util.Log;
import android.util.Slog;
import java.util.ArrayList;
import android.os.RemoteException;
import android.myinterface.IMyClass;
import android.hardware.myinterface.V1_0.IMyClass;
class IMyClassImpl extends IMyClass.Stub {
private static final String TAG = "IMyClassImpl";
private IMyClass mIMyClassHal = null;
public IMyClassImpl() {
Slog.d(TAG, "Build service");
try {
mIMyClassHal = IMyClass.getService();
} catch (Exception e)
{
mIMyClassHal = null;
}
}
@Override
public void myAidlFunct1() throws RemoteException {
if (mIMyClassHal != null) {
mIMyClassHal.myFunct1(new IMyClass.myFunct1Callback() {
@Override
public void onValues(bool ret) {
//Function that you have to treat the HAL "IMyClass myFunct1() generates (bool ret)" returned value.
}
});
}
}
5.3. Makefile and manifest[edit source]
Android.mk
LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under,src) LOCAL_REQUIRED_MODULES := android.hardware.myinterface LOCAL_STATIC_JAVA_LIBRARIES := android.hardware.myinterface-V1.0-java LOCAL_PACKAGE_NAME := MyInterfaceService LOCAL_PROGUARD_ENABLED := disabled LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE)
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.myinterfaceservice" android:sharedUserId="android.uid.system"> <application android:name=".MyInterfaceServiceApp" android:persistent="true"> </application> </manifest>
6. Add SEpolicy[edit source]
To be able to execute your service, even if your system is permissive you need to declare dedicated SEpolicy.
Because the new service is embedded like any other AOSP service you need to adapt official AOSP SEpolicy.
For more details please refer to the official AOSP documentation[6].
6.1. Change AOSP SEpolicy[edit source]
In system/sepolicy/public/attributes, you need to declare a new HAL name.
hal_attribute(myservice);
This creates all necessary rules for the HAL.
In system/sepolicy/public/service.te
type myservice_service, app_api_service, service_manager_type;
This creates the new SEpolicy name with appropriate rights.
In system/sepolicy/private/service_contexts
android.myinterface.IMyClass u:object_r:myservice_service:s0
This gives the correct rights to the service.
In system/sepolicy/private/seapp_contexts add the new packages/apps rules.
user=system seinfo=myservice name=com.android.myinterfaceservice domain=myservice_app type=app_data_file
This gives the correct rights to the packages/apps service.
In system/sepolicy/private/compat/27.0/27.0.ignore.cil and system/sepolicy/private/compat/26.0/26.0.ignore.cil add the service at the end of the list.
myservice_service
Because of the base AOSP SEpolicy change you need to copy those files in the prebuilt location (path depends on API version used)
cp system/sepolicy/public/attributes system/sepolicy/prebuilts/api/28.0/public/attributes cp system/sepolicy/public/service.te system/sepolicy/prebuilts/api/28.0/public/service.te cp system/sepolicy/private/service_contexts system/sepolicy/prebuilts/api/28.0/private/service_contexts cp system/sepolicy/private/seapp_contexts system/sepolicy/prebuilts/api/28.0/private/seapp_contexts cp system/sepolicy/private/compat/27.0/27.0.ignore.cil system/sepolicy/prebuilts/api/28.0/private/compat/27.0/27.0.ignore.cil cp system/sepolicy/private/compat/26.0/26.0.ignore.cil system/sepolicy/prebuilts/api/28.0/private/compat/26.0/26.0.ignore.cil
6.2. Add custom SEpolicy to distribution[edit source]
Create device/stm/<STM32Series>/sepolicy/hal_myinterface_default.te
type hal_myservice_default, domain; hal_server_domain(hal_myservice_default, hal_myservice) type hal_myservice_default_exec, exec_type, vendor_file_type, file_type; init_daemon_domain(hal_myservice_default) binder_call(hal_myservice_client, hal_myservice_server) binder_call(hal_myservice_server, hal_myservice_client) add_hwservice(hal_myservice_server, hal_myservice_hwservice)
If your HAL needs to access some specific system files you need to add the definition here.
In 'device/stm/<STM32Series>/sepolicy/myservice_app.te
#packages app MyInterfaceService type myservice_app, domain;
7. Add to the board[edit source]
To include your new service in the board-specific Android image you need to customize your device.mk
.
PRODUCT_PACKAGES += \
android.hardware.myinterface@1.0-service.my \ #The HAL
MyInterfaceService #The packages apps service
You need to rebuild your distribution to integrate the changes.
make -j
8. SDK integration[edit source]
To allow using the created service in your applications, you have to re-generate the SDK and install it within Android Studio (refer to How to build and install an SDK for Android).
9. References[edit source]
- ↑ https://source.android.com/devices/architecture/hidl/interfaces
- ↑ https://source.android.com/devices/architecture/configstore/interface
- ↑ https://android.googlesource.com/platform/build/soong/
- ↑ https://developer.android.com/guide/components/aidl
- ↑ https://source.android.com/devices/architecture/hidl-cpp
- ↑ https://source.android.com/security/selinux/device-policy