前面兩篇文章實現了自定義HAL和HIDL服務,本篇接着往上層實現,這篇文章要寫的是JNI服務和framework層AIDL服務實現,由AIDL服務調用JNI層的服務的函數,爲了提供給上層APP使用
同樣我們參照系統其他服務的方式來寫,來到frameworks/base/services/core/jni目錄下,這下面有許多JNI的服務,創建cpp文件com_android_server_am_HelloService.cpp,爲什麼要叫這個名字,因爲等下我們實現的AIDL服務包名爲"com.android.server.am"
#include <jni.h>
#include <nativehelper/JNIHelp.h>
#include <binder/IServiceManager.h>
#include <android/hardware/hello_hidl/1.0/IHello.h>
#include <log/log.h>
using android::sp;
using android::hardware::hello_hidl::V1_0::IHello;
namespace android {
sp<IHello> hw_device;
static jint android_server_am_HelloService_nativeAdd(JNIEnv* env, jobject /* clazz */,jint a,jint b) {
ALOGW("dongjiao...android_server_am_HelloService_nativeAdd.....");
uint32_t total = hw_device->addition_hidl(a,b);
return reinterpret_cast<jlong>(total);
}
static void android_server_am_HelloService_nativeInit(JNIEnv* /* env */,jobject /* clazz */) {
ALOGW("dongjiao...android_server_am_HelloService_nativeInit.....");
hw_device = IHello::getService();
if (hw_device == nullptr) {
ALOGW("dongjiao...failed to get IHello service");
return;
}
ALOGW("dongjiao...success to get IHello service");
}
/*
* JNI registration.
*/
static const JNINativeMethod gMethods[] = {
{ "nativeAdd", "(II)I", (void*) android_server_am_HelloService_nativeAdd },
{ "nativeInit", "()V", (void*) android_server_am_HelloService_nativeInit },
};
int register_android_server_am_HelloService(JNIEnv* env)
{
return jniRegisterNativeMethods(env, "com/android/server/am/HelloService",
gMethods, NELEM(gMethods));
}
}; // namespace android
這個JNI服務中定義兩個函數,android_server_am_HelloService_nativeAdd和android_server_am_HelloService_nativeInit,這兩個函數是提供給framework層AIDL服務調用的,添加了一些log方便後面驗證,對應等下要實現的AIDL服務中的nativeAdd和nativeInit
android_server_am_HelloService_nativeInit函數作用是獲取我們上一篇文章實現的HIDL服務IHello
android_server_am_HelloService_nativeAdd函數作用是調用HIDL服務中定義的addition_hidl函數
JNI服務中的函數想要被framework調用還需要通過register_android_server_am_HelloService函數進行註冊,"com/android/server/am/HelloService"這個是等下我們要實現的framework層的AIDL服務
接着需要將這個自定義JNI服務添加到onload.cpp中開機註冊,打開frameworks/base/services/core/jni/onload.cpp,添加如下代碼:
接着需要修改Android.bp文件,打開frameworks/base/services/core/jni/Android.bp,添加如下代碼:
主要就是將新增文件添加進編譯和添加hello_hidl的依賴庫,JNI服務已經創建好了,接着,需要創建framework層AIDL服務
首先到frameworks/base/core/java/android/app/目錄下創建IHelloService.aidl文件:
package android.app;
interface IHelloService {
int add(int a,int b);
}
想要編譯這個文件還需要修改Android.bp,在frameworks/base/Android.bp中添加如下代碼:
然後就可以編譯了,mmm frameworks/base
編譯成功後我們可以去out目錄下看看IHelloService.aidl編出來的IHelloService.java文件:
/*
* This file is auto-generated. DO NOT MODIFY.
*/
package android.app;
public interface IHelloService extends android.os.IInterface
{
/** Default implementation for IHelloService. */
public static class Default implements android.app.IHelloService
{
@Override public int add(int a, int b) throws android.os.RemoteException
{
return 0;
}
@Override
public android.os.IBinder asBinder() {
return null;
}
}
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements android.app.IHelloService
{
private static final java.lang.String DESCRIPTOR = "android.app.IHelloService";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an android.app.IHelloService interface,
* generating a proxy if needed.
*/
public static android.app.IHelloService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof android.app.IHelloService))) {
return ((android.app.IHelloService)iin);
}
return new android.app.IHelloService.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
/** @hide */
public static java.lang.String getDefaultTransactionName(int transactionCode)
{
switch (transactionCode)
{
case TRANSACTION_add:
{
return "add";
}
default:
{
return null;
}
}
}
/** @hide */
public java.lang.String getTransactionName(int transactionCode)
{
return this.getDefaultTransactionName(transactionCode);
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
java.lang.String descriptor = DESCRIPTOR;
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(descriptor);
return true;
}
case TRANSACTION_add:
{
data.enforceInterface(descriptor);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.add(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements android.app.IHelloService
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public int add(int a, int b) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(a);
_data.writeInt(b);
boolean _status = mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().add(a, b);
}
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
public static android.app.IHelloService sDefaultImpl;
}
static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
public static boolean setDefaultImpl(android.app.IHelloService impl) {
if (Stub.Proxy.sDefaultImpl == null && impl != null) {
Stub.Proxy.sDefaultImpl = impl;
return true;
}
return false;
}
public static android.app.IHelloService getDefaultImpl() {
return Stub.Proxy.sDefaultImpl;
}
}
public int add(int a, int b) throws android.os.RemoteException;
}
其實這個文件和我們用Android Studio創建AIDL服務生成的中間文件差不多的,都是統一的AIDL框架:有一個Stub抽象類,繼承IBinder,實現IHelloService,還有一個代理類Proxy繼承IHelloService,通過asInterface方法來獲取
瞭解了IHelloService.aidl生成的一箇中間文件,我們再實現HelloService.java的時候就清晰了,在frameworks/base/services/core/java/com/android/server/am/目錄下創建HelloService.java文件:
package com.android.server.am;
import android.app.IHelloService;
public class HelloService extends IHelloService.Stub {
public HelloService(){
android.util.Log.d("dongjiao","Start HelloService...");
nativeInit();
}
@Override
public int add(int a, int b){
android.util.Log.d("dongjiao","HelloService add()...a = :"+a+",b = :"+b);
return nativeAdd(a,b);
}
private static native void nativeInit();
private static native int nativeAdd(int a,int b);
}
這個HelloService繼承自IHelloService.Stub,它作爲Binder的具體實現端,裏面定義了兩個native方法,這兩個方法和之前創建的JNI服務中的那兩個函數一一對應,HelloService構造方法中調用nativeInit,add方法提供給外界訪問,它裏面調用nativeAdd
好了這個AIDL服務已經創建好了,接着我們到SystemServer中去添加開機註冊此服務的代碼,打開frameworks/base/services/java/com/android/server/SystemServer.java隨便在其他某個服務下添加如下代碼:
SystemServer啓動時就會將HelloService添加到ServiceManager,名字自定義爲”helloService“,代碼已經添加完畢,總的修改就是如下部分:
開始進行編譯 mmm frameworks/base/
編譯成功後需要將/system/framework/下所有文件push進手機
adb push out/target/product/TOKYO_TF_arm64/system/framework/ /system/
另外定義的JIN服務相關代碼會被編譯到libandroid_servers.so這個so中,還需push這個so
adb push out/target/product/TOKYO_TF_arm64/system/lib64/libandroid_servers.so /system/lib64/
重啓手機發現瞭如下錯誤:
這是因爲缺少了SELinux權限,實際開發中添加自定義AIDL,HIDL服務都需要SELinux權限,我們這裏重點不在SELinux,所以採用規避方案,直接將SELinux關閉adb shell setenforce 0,這需要root權限
我們發現如下log,這是因爲我的HIDL服務還沒啓動
啓動一下前一篇文章實現的HIDL服務:
我們重新將SystemServer殺掉,爲了再看一遍log:
04-14 23:58:58.760 9279 9279 E : hello_hidl service is init success…
04-14 23:58:58.761 9279 9279 I ServiceManagement: Registered [email protected]::IHello/default (start delay of 52ms)
04-14 23:58:58.762 9279 9279 I ServiceManagement: Removing namespace from process name [email protected] to [email protected].
04-14 23:58:58.762 9279 9279 I [email protected]: Registration complete for [email protected]::IHello/default.
這一段代表的是HIDL服務的啓動註冊
04-14 23:59:38.881 328 328 I ServiceManager: service ‘helloService’ died
04-14 23:59:41.582 14037 14037 W : JNI_OnLoad…hello…
04-14 23:59:41.594 14037 14037 W : register_android_server_am_HelloService…
04-14 23:59:44.978 14037 14037 D dongjiao: SystemServer…addService(helloService)…
04-14 23:59:44.978 14037 14037 D dongjiao: Start HelloService…
04-14 23:59:44.978 14037 14037 W : HelloService…nativeInit…
04-14 23:59:44.980 14037 14037 W : success to get IHello service
這一段代表AIDL服務的啓動註冊
可以看到關閉了SELinux權限之後,HIDL和AIDL服務都註冊成功了,並且在AIDL服務初始化時也能成功通過JNI服務獲取到HIDL服務了,後面如果調用HIDL的addition_hidl函數也應該是很簡單了
其實整個調用邏輯還是比較清晰的,從AIDL到JNI到HIDL,在AIDL服務初始化中調用JNI服務的nativeInit函數,JNI服務的nativeInit函數中獲取到HIDL服務,之後就可以隨意調用HIDL的函數了
下一篇文章我將寫一個APP通過AIDL調用HIDL的addition_hidl函數