How to add a custom service for Android

Revision as of 13:21, 7 August 2019 by Registered User




1. Article purpose[edit source]

This article is intended for distribution-creator profile end users (see Which Package better suits your needs for more information).

When you develop new hardware for the device that is not yet supported you need to create your own service to be able to use it.

2. Prerequisites[edit source]


The environment used must have been installed using the right distribution creator Package for your selected microprocessor device. See the list of Android distribution Packages here.


3. Hardware interface[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 AOSP. You can refer to the HIDL manual [1]. For more information on HAL definition you can refer the the official AOSP documentation[2].

3.1. Creation[edit source]

To create your interface you need to create a folder myinterface in source tree path <aosp>/hardware/interfaces. Inside the interfaces folder, create a version folder for your interface like hardware/interfaces/myinterface/1.0/.


3.2. HAL[edit source]

Define as many classes and types you need to be able to interact with your hardware. Those functions will need to be implemented in your device HAL folder. (See Implement the vendor HAL)

IClass1.hal

package android.hardware.myinterface@1.0;

interface IClass1 {
    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;
};

3.3. Generation[edit source]

Android.bp[3]:

hidl_interface {
    name: "android.hardware.myinterface@1.0",
    root: "android.hardware",
    vndk: {
        enabled: true,
    },
    srcs: [
        "types.hal",
        "IClass1.hal",
    ],
    interfaces: [
        "android.hidl.base@1.0",
    ],
    types: [
        "MyType",
    ],
    gen_java: true,
}

3.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 have been 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 will add a specific hash matching your hardware interface. This ensures the appropriate interface is used by the framework. Do not forget to update the hash if you make changes to the interface.


4. 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.

4.1. Creation[edit source]

To create your API you need to create a "myinterface" subfolder at <aosp>/frameworks/base/core/java/android/.


4.2. 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/IClass1.aidl

package android.myinterface;

interface IClass1 {
    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/Class1.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 Class1 {
    private final Context mContext;
    private final IClass1 mService;

    public Class1(Context ctx, IClass1 service) {
        mContext = ctx;
        mService = service;
    }

    public void myAidlFunct1() {
        try{
            mService.myAidlFunct1();
        } catch (RemoteException ex){
            Slog.e("Class1", "Unable to contact the remote Class1");
        }
    }
}


4.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 created beforehand.

java_library {
	.
	.
	.
    "core/java/android/copro/IClass1.aidl",
}

4.4. Update API[edit source]

When your interface is well defined you need to execute the command:

make update-api

This command will update all the necessary files to integrate your API in AOSP.


5. Implement the vendor HAL[edit source]

To implement the HAL you just create please refer to the AOSP documentation[5].

6. 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.


6.1. Package apps[edit source]

Create a folder in <aosp>/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
          • IClass1Impl.java


6.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.IClass1;

public class MyInterfaceServiceApp extends Application { 
    private static final String REMOTE_SERVICE_NAME = IClass1.class.getName();
    private static final String TAG = "MyInterfaceServiceApp";
    private IBinder mClass1 = null; 

    public void onCreate() {
        super.onCreate();
        Slog.d(TAG, "Build service");
        mClass1 = new IClass1Impl();
        ServiceManager.addService(REMOTE_SERVICE_NAME, mClass1);
    }

    public void onTerminate() {
        super.onTerminate();
    }

}

IClass1Impl.java

package com.android.myinterfaceservice;

import android.util.Log;
import android.util.Slog;

import java.util.ArrayList;
import android.os.RemoteException;

import android.myinterface.IClass1;

import android.hardware.myinterface.V1_0.IClass1;

class IClass1Impl extends IClass1.Stub {
    private static final String TAG = "IClass1Impl";
    private IClass1 mIClass1Hal = null;

    public IClass1Impl() {
        Slog.d(TAG, "Build service");
        try {
            mIClass1Hal = IClass1.getService();
        } catch (Exception e)
        {
            mIClass1Hal = null;
        }
    }

    @Override
    public void myAidlFunct1() throws RemoteException {
        if (mIClass1Hal != null) {
            mIClass1Hal.myFunct1(new IClass1.myFunct1Callback() {

                @Override
                public void onValues(bool ret) {
                    //Do something with ret
                }
            });
        }
    }


6.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>


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.stm32mp1 \ #The HAL
        MyInterfaceService #The packages apps service

8. SDK integration[edit source]

When you have finished creating your service you need to refer to How to build and install an SDK to rebuild it to include your custom API.

9. References[edit source]