传统 Hal 开发指南5 —— 添加硬件访问服务

添加 aidl 文件

添加 aidl 文件 frameworks/base/core/java/android/os/IHelloService.aidl :

java 复制代码
package android.os;

interface IHelloService
{
    void open();
    void write(String str);
    String read();
}

frameworks/base/Android.mk 中添加上 aidl 文件:

Makefile 复制代码
LOCAL_SRC_FILES += \
	core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl \
	core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl \
	core/java/android/accounts/IAccountManager.aidl \
	core/java/android/accounts/IAccountManagerResponse.aidl \
	core/java/android/accounts/IAccountAuthenticator.aidl \
      # .......
      core/java/android/os/IHelloService.aidl \ # 添加的内容
	core/java/android/security/IKeystoreService.aidl \
	core/java/android/service/carrier/ICarrierService.aidl
      # ......

实现服务端

添加 frameworks/base/services/core/java/com/android/server/HelloService.java 文件:

Java 复制代码
package com.android.server;

import android.os.IHelloService;

// 硬件服务的服务端实现
public class HelloService extends IHelloService.Stub {

    public native void natvieOpen();
    public native void natvieWrite(String str);
    public native String nativeRead();
    
    public void open() throws android.os.RemoteException {
        natvieOpen();
    }
    
    public void write(String str) throws android.os.RemoteException  {
        natvieWrite(str);
    }
    
    public String read() throws android.os.RemoteException  {
        return nativeRead();
    }


}

JNI 层实现

添加 frameworks/base/services/core/jni/com_android_server_HelloService.cpp JNI 实现:

cpp 复制代码
#define LOG_TAG "HelloService"

#include <jni.h>
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"

#include <utils/misc.h>
#include <utils/Log.h>
#include <hardware/hello_hal.h>

#include <stdio.h>
#include <string>

namespace android
{

static hw_module_t *gHelloModule = NULL;
static hello_hal_device_t *gHelloHalDevice = NULL;

static void helloOpen(JNIEnv env, jobject clazz)
{
    ALOGD("yuandaima_jni_open");
    if (gHelloModule != NULL) {
        return;
    }

    int err = hw_get_module(HELLO_HAL_HARDWARE_MODULE_ID, (hw_module_t const**)&gHelloModule);

    if (err) {
        ALOGE("Couldn't load %s module (%s)", HELLO_HAL_HARDWARE_MODULE_ID, strerror(-err));
    } else {
        if (gHelloModule) {
            ALOGD("yuandaima_jni_open get module sucess");
            hello_hal_methods_open(gHelloModule, &gHelloHalDevice);
            
        }
    }

    if(gHelloHalDevice) {
        gHelloHalDevice->hello_hal_open(gHelloHalDevice);
    }
}


static void helloWrite(JNIEnv* env, jobject clazz, jstring str)
{   
   
    if (gHelloHalDevice) {
         ALOGD("yuandaima_jni_write");
        const char * c_str = NULL;
        jboolean isCopy; 
	    c_str = env->GetStringUTFChars(str, &isCopy);   //从jstring指针中获取数据
        ALOGD("yuandaima_jni_write %s",c_str);
        gHelloHalDevice->hello_hal_write(gHelloHalDevice, c_str);
    } 
    else {
        ALOGW("Tried to hello but there is no hello device.");
    }
}

static jstring helloRead(JNIEnv* env, jobject clazz)
{
    if (gHelloHalDevice) {
        ALOGD("yuandaima_jni_read");
        char* data = NULL;
        gHelloHalDevice->hello_hal_read(gHelloHalDevice, &data);
        ALOGD("yuandaima_jni_read result is %s", data);
        if(data != NULL ) {
            // Android7 上直接用 NewStringUTF 把 char* 转 jstring 有乱码缺码 bug
            jbyteArray array = env->NewByteArray(1024);
            env->SetByteArrayRegion(array, 0, 1024,(const jbyte *)data);
            jstring strEncode = env->NewStringUTF("UTF-8");
            jclass cls = env->FindClass("java/lang/String");
            jmethodID ctor = env->GetMethodID(cls, "<init>", "([BLjava/lang/String;)V");
            jstring ret = (jstring) env->NewObject(cls, ctor, array, strEncode);
            return ret;
        }
    }
    return env->NewStringUTF("no msg");
}

    // public native void natvieOpen();
    // public native void natvieWrite(String str);
    // public native String nativeRead();

static const JNINativeMethod method_table[] = {
    { "natvieOpen", "()V", (void*)helloOpen },
    { "natvieWrite", "(Ljava/lang/String;)V", (void*)helloWrite },
    { "nativeRead", "()Ljava/lang/String;", (void*)helloRead }
};


int register_android_server_HelloService(JNIEnv *env)
{   
    ALOGD("yuandaima_jni_register");
    return jniRegisterNativeMethods(env, "com/android/server/HelloService",
            method_table, NELEM(method_table));
}

};

frameworks/base/services/core/jni/Android.mk 中添加:

Makefile 复制代码
LOCAL_SRC_FILES += \
      # ......
    $(LOCAL_REL_DIR)/com_android_server_UsbMidiDevice.cpp \
    $(LOCAL_REL_DIR)/com_android_server_UsbHostManager.cpp \
    $(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \
    $(LOCAL_REL_DIR)/com_android_server_HelloService.cpp \   # 添加的内容
    $(LOCAL_REL_DIR)/com_android_server_PersistentDataBlockService.cpp \
    $(LOCAL_REL_DIR)/onload.cpp

frameworks/base/services/core/jni/onload.cpp 中添加:

cpp 复制代码
// 在这里注册 JNI 函数
// java 层的 native 方法就能调用到对应的 native 层函数了
extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
    JNIEnv* env = NULL;
    jint result = -1;

    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        ALOGE("GetEnv failed!");
        return result;
    }
    ALOG_ASSERT(env, "Could not retrieve the env!");

    register_android_server_ActivityManagerService(env);
    register_android_server_PowerManagerService(env);
      // ......
    register_android_server_VibratorService(env);
    register_android_server_HelloService(env); // 添加的内容
    register_android_server_SystemServer(env);
    register_android_server_location_GnssLocationProvider(env);
    register_android_server_location_FlpHardwareProvider(env);
    // ......
    return JNI_VERSION_1_4;
}

客户端实现

添加一个接口 frameworks/base/core/java/android/os/HelloHal.java

java 复制代码
package android.os;

import android.app.ActivityThread;
import android.content.Context;


public abstract class HelloHal {

    public HelloHal() {
    }

    public abstract int open() throws RemoteException;

    public abstract int write(String st) throws RemoteException;
    
    public abstract String read() throws RemoteException;
}

实现接口 frameworks/base/core/java/android/os/SystemHelloHal.java

java 复制代码
package android.os;

import android.content.Context;
import android.util.Log;

/**
 * Vibrator implementation that controls the main system vibrator.
 *
 * @hide
 */
public class SystemHelloHal extends HelloHal {
    
    private static final String TAG = "HelloHal";

    private final IHelloService mService;

      // 获取Hello服务的代理端
    public SystemHelloHal() { 
        mService = IHelloService.Stub.asInterface(
                ServiceManager.getService("hello"));
    }

      // 通过代理端对象发起远程调用
    @Override
    public int open() throws RemoteException{
        if (mService != null) {
            mService.open();
        }

        return -1;
    }

    @Override
    public int write(String str) throws RemoteException {
        if (mService != null) {
            mService.write(str);
        }
        return -1;
    }
    
    @Override
    public String read() throws RemoteException {
        if (mService != null) {
            return mService.read();
        }
        return null;
    }

}

最后在 SystemServiceRegistry 的静态块中添加:

java 复制代码
// frameworks/base/core/java/android/app/SystemServiceRegistry.java
      static {
        registerService(Context.HELLO_SERVICE, HelloHal.class,
            new CachedServiceFetcher<HelloHal>() {
            @Override
            public HelloHal createService(ContextImpl ctx) {
                return new SystemHelloHal();
            }});
      }

Selinux 配置

修改 system/sepolicy/service.te:

bash 复制代码
type HelloServiceType, app_api_service, system_server_service, service_manager_type;

修改 system/sepolicy/service_contexts:

bash 复制代码
HelloService                              u:object_r:HelloServiceType:s0

修改 system/sepolicy/platform_app.te,让系统 App 可以访问我们自定义的 Binder 服务:

bash 复制代码
allow platform_app HelloServiceType:service_manager find;

修改 system/sepolicy/untrusted_app.te,让普通 App 可以访问我们自定义的 Binder 服务:

bash 复制代码
allow untrusted_app HelloServiceType:service_manager find;

最后,让 SystemServer 可以访问到 hello 驱动,修改 system/sepolicy/system_server.te

bash 复制代码
allow system_server hello_dev_t:chr_file { open read write };

编译

bash 复制代码
source build/envsetup.sh
lunch aosp_x86_64-eng
# 在 com.android.server 包中添加了 HelloService 后,给系统添加了 API
make update-api
make -j32
# 启动模拟器
emulator -kernel /tmp/kernel-qemu/x86_64-3.10.0/kernel-qemue

参考资料

Android Native 开发之 NewString 与 NewStringUtf 解析

相关推荐
前期后期32 分钟前
Android OkHttp源码分析(一):为什么OkHttp的请求速度很快?为什么可以高扩展?为什么可以高并发
android·okhttp
轻口味3 小时前
Android应用性能优化
android
全职计算机毕业设计3 小时前
基于 UniApp 平台的学生闲置物品售卖小程序设计与实现
android·uni-app
dgiij4 小时前
AutoX.js向后端传输二进制数据
android·javascript·websocket·node.js·自动化
SevenUUp5 小时前
Android Manifest权限清单
android
高林雨露5 小时前
Android 检测图片抓拍, 聚焦图片后自动完成拍照,未对准图片的提示请将摄像头对准要拍照的图片
android·拍照抓拍
wilanzai5 小时前
Android View 的绘制流程
android
INSBUG6 小时前
CVE-2024-21096:MySQLDump提权漏洞分析
android·adb
Mercury Random7 小时前
Qwen 个人笔记
android·笔记
苏苏码不动了7 小时前
Android 如何使用jdk命令给应用/APK重新签名。
android