Android OS车载

Android 字符驱动#2#开发Android硬件访问服务和J

2019-05-06  本文已影响0人  古风子

开发Android硬件访问服务

定义硬件访问服务接口

首先,在android的源码framework目录,创建aidl文件,为其他应用提供上层调用接口

xuzhike@ubuntu:~/mtk_6737_6.x_wtwd_8_qiku_LE_PLUS/android/qiku/frameworks/base/core/java/com/jdf/android/hal$ ls
IHelloService.aidl

package com.jdf.android.hal;

interface IHelloService{
    void setVal(int val);
    int getVal();
}

在framework的Android.mk文件中,需要声明创建的aidl文件

diff --git a/base/Android.mk b/base/Android.mk
old mode 100644
new mode 100755
index b5b7fa9..2b10d7b
--- a/base/Android.mk
+++ b/base/Android.mk
@@ -420,6 +420,7 @@ LOCAL_SRC_FILES += \
        packages/services/Proxy/com/android/net/IProxyCallback.aidl \
        packages/services/Proxy/com/android/net/IProxyPortListener.aidl \
        telephony/java/com/mediatek/internal/telephony/ITelephonyEx.aidl \
+       core/java/com/jdf/android/hal/IHelloService.aidl \
 

定义硬件访问服务

在android源码的server目录,创建HelloServices.java文件,用于system_server通过jni跟hal通信

jdf@ubuntu:~/mtk_6737_6.x_wtwd_8_qiku_LE_PLUS/android/qiku/frameworks/base/services/core/java/com/jdf/android/server/hal$ ls
HelloService.java
package com.jdf.android.server.hal;

import com.jdf.android.hal.IHelloService;
import android.util.Slog;

public class HelloService extends IHelloService.Stub {

    private int ptr = 0;
    public HelloService(){
        Slog.i("HelloHal", "start  HelloService");
        //ptr = init_hello();
        Slog.i("HelloHal", "init hello ret info:"+ptr);
    }


    public int getVal(){
        int a = -1;
        Slog.i("HelloHal", "getVal start");
        //a = getVal_native(ptr);
        //return getVal_native(ptr);
        Slog.i("HelloHal", "getVal end");
        return a;
        
    }

    public void setVal(int val){
        Slog.i("HelloHal", "setVal start : " + val + "ptr : " + ptr);
        //setVal_native(ptr,val);
        Slog.i("HelloHal", "setVal end");
    }

   public native int init_hello();
   public native int getVal_native(int ptr);
   public native void setVal_native(int ptr,int val);

}


开发硬件访问的JNI程序

com_jdf_android_server_hal_HelloService.cpp###

进入services的jni目录,创建com_jdf_android_server_hal_HelloService.cpp文件,用于与HAL通信

jdf@ubuntu:~/mtk_6737_6.x_wtwd_8_qiku_LE_PLUS/android/qiku/frameworks/base/services/core/jni$ ls | grep hello
com_jdf_android_server_hal_HelloService.cpp


#include <jni.h>
#include "JNIHelp.h"
#include <hardware/hardware.h>
#include <android_runtime/AndroidRuntime.h>
#include <hardware/hello.h>
#include <utils/Log.h>
namespace android{

    static jint getVal(JNIEnv *env,jobject obj,jint ptr){
        ALOGI("HelloHal jni getVal start");
        struct hello_device_t *dev = (struct hello_device_t *)ptr;
        int val = 0;
        dev->get_val(dev,&val);//对应hello.h的结构体hello_device_t中声明的get_val
        ALOGI("HelloHal jni getVal value : %d" , val);
        return val;
    }

   static void setVal(JNIEnv *env,jobject obj,jint ptr,jint val){
        ALOGI("HelloHal jni  setVal start");
        struct hello_device_t *dev = (struct hello_device_t *)ptr;
        dev->set_val(dev,val);
        ALOGI("HelloHal jni set value : %d" , val);


    }
   static inline int hello_device_open(const hw_module_t* module, struct hello_device_t** device) {  
    return module->methods->open(module, "hello", (struct hw_device_t**)device);  
   } 

   static jint hello_init(JNIEnv *env,jobject obj){
        struct hello_module_t *module;
        struct hello_device_t *device;
        ALOGI("HelloHal jni hello JNI: initializing......");
        /*加载out/target/product/yk658_37m_lwtg_35g/system/lib/hw目录的hello.default.so模块*/
        if(hw_get_module("hello",(const struct hw_module_t **)&module)== 0){
            //module->common.methods->open(&(module->common),"hello",(struct hw_device_t **)&device);
            //module->common.methods->open(&(module->common),"hello",(struct hw_device_t **)&device);
            if(hello_device_open(&(module->common), &device) == 0) {  

                ALOGI("HelloHal jni fail open3 /dev/hello : %d" , (jint)device);
                return (jint)device;
            }
            ALOGI("HelloHal jni fail open /dev/hello");
        }
        ALOGI("HelloHal jni sucess /dev/hello : %d ",(jint)device);
        return (jint)device;
    }
    //JNI方法表
    static const JNINativeMethod method_table[] = {
            {"init_hello","()I",(void *)hello_init},
            {"getVal_native","(I)I",(void *)getVal},
            {"setVal_native","(II)V",(void *)setVal}
    };
    //注册jni方法
    int register_hello_Service(JNIEnv *env){
        jniRegisterNativeMethods(env,"com/jdf/android/server/hal/HelloService",method_table,NELEM(method_table));
        return 0;
    }
}

主要关注三个地方:
1:hello_init->hw_get_module("hello" )加载对应的hello的硬件抽象层,也就是上一节在以下方法声明的

struct hello_module_t HAL_MODULE_INFO_SYM = {
        common : {
                tag : HARDWARE_MODULE_TAG,
                version_major : 1,
                version_minor : 0,
                id : "hello",
                name : "hello",
                author : "jdf",
                methods : &hello_method
        }
};

2:JNINativeMethod声明JNI方法表
3:注册JNI方法,在jniRegisterNativeMethods函数中,第二个参数的值必须对应HelloService所在的包的路径,即com/jdf/android/server/hal(下节会创建改服务相关文件)

修改onload文件###

修改jni文件同目录下文件的onload.cpp文件,增加上述JNI文件中的register_hello_Service声明

diff --git a/base/services/core/jni/onload.cpp b/base/services/core/jni/onload.cpp
index f36360f..8f18dbc
--- a/base/services/core/jni/onload.cpp
+++ b/base/services/core/jni/onload.cpp
@@ -25,6 +25,7 @@
 #include "utils/misc.h"
 
 namespace android {
+int register_hello_Service(JNIEnv *env);
 int register_android_server_AlarmManagerService(JNIEnv* env);
 int register_android_server_AssetAtlasService(JNIEnv* env);
 int register_android_server_BatteryStatsService(JNIEnv* env);
@@ -71,7 +72,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
         return result;
     }
     ALOG_ASSERT(env, "Could not retrieve the env!");
+    register_hello_Service(env);
     register_android_server_PowerManagerService(env);
     register_android_server_SerialService(env);
     register_android_server_InputApplicationHandle(env);

这样,在Android系统初始化时,就会自动加载该JNI方法调用表

修改Android.mk编译文件###

在Android.mk文件中进行声明

diff --git a/base/services/core/jni/Android.mk b/base/services/core/jni/Android.mk
index 067929d..4915830
--- a/base/services/core/jni/Android.mk
+++ b/base/services/core/jni/Android.mk
@@ -30,6 +30,7 @@ LOCAL_SRC_FILES += \
     $(LOCAL_REL_DIR)/com_mediatek_perfservice_PerfServiceManager.cpp \
     $(LOCAL_REL_DIR)/com_mediatek_hdmi_MtkHdmiManagerService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_display_DisplayPowerController.cpp \
+    $(LOCAL_REL_DIR)/com_jdf_android_server_hal_HelloService.cpp \
     $(LOCAL_REL_DIR)/onload.cpp
 
 ifneq (yes,$(MTK_BSP_PACKAGE))

启动硬件访问服务###

diff --git a/base/services/java/com/android/server/SystemServer.java b/base/services/java/com/android/server/SystemServer.java
old mode 100644
new mode 100755
index 06c8ee0..aa29eb6
--- a/base/services/java/com/android/server/SystemServer.java
+++ b/base/services/java/com/android/server/SystemServer.java
@@ -21,6 +21,7 @@
 
 package com.android.server;
 
+import com.jdf.android.server.hal.HelloService;
 /* 360OS begin */
 import android.os.FileUtils;
 import com.qiku.android.feature.QikuFeatureUtils;
@@ -615,6 +616,7 @@ public final class SystemServer {
             Slog.i(TAG, "Telephony Registry");
             telephonyRegistry = new TelephonyRegistry(context);
             ServiceManager.addService("telephony.registry", telephonyRegistry);
+            ServiceManager.addService("hello", new HelloService());
 
             Slog.i(TAG, "Entropy Mixer");
             entropyMixer = new EntropyMixer(context);

以上步骤完整后,尝试去刷机,验证,在HelloService初始化过程,也就是下图所示流程:

![hw_get_module] jeJzTw9.png

会抛出

HelloHal fail open /dev/hello -- Permission denied

因此,我们还需要设置system_server对/dev/hello的访问权限

修改SePolicy的权限

HelloServer注册权限

在最后一行添加

type hello_service, system_api_service, system_server_service, service_manager_type;

type关键字,把一个自定义的域与原有的域相关联
声明hello_service是一个system_server服务

hello u:object_r:hello_service:s0

定义的格式意义为:user:role:type[:range]

以上不修改的话,add不成功。

修改记录如下

diff --git a/sepolicy/service.te b/sepolicy/service.te
old mode 100644
new mode 100755
index bfb29d0..cb23af8
--- a/sepolicy/service.te
+++ b/sepolicy/service.te
@@ -13,6 +13,8 @@ type surfaceflinger_service,    service_manager_type;
 type system_app_service,        service_manager_type;
 
 # system_server_services broken down
+type hello_service, system_api_service, system_server_service, service_manager_type;
+
 type accessibility_service, app_api_service, system_server_service, service_manager_type;
 type account_service, app_api_service, system_server_service, service_manager_type;
 type activity_service, app_api_service, system_server_service, service_manager_type;
diff --git a/sepolicy/service_contexts b/sepolicy/service_contexts
old mode 100644
new mode 100755
index 7fb3598..0c7b4a0
--- a/sepolicy/service_contexts
+++ b/sepolicy/service_contexts
@@ -1,3 +1,5 @@
+hello                                     u:object_r:hello_service:s0
+
 accessibility                             u:object_r:accessibility_service:s0
 account                                   u:object_r:account_service:s0
 activity                                  u:object_r:activity_service:s0

system_server/HelloServer对内核节点访问权限
服务添加成功后,还需要设置systemserver对/dev/hello的操作权限

diff --git a/sepolicy/file_contexts b/sepolicy/file_contexts
old mode 100644
new mode 100755
index f58a74a..ceba8ea
--- a/sepolicy/file_contexts
+++ b/sepolicy/file_contexts
@@ -125,6 +125,7 @@
 /dev/zero              u:object_r:zero_device:s0
 /dev/__kmsg__          u:object_r:klog_device:s0
 /dev/__properties__ u:object_r:properties_device:s0
+/dev/hello              u:object_r:hello_device:s0 
 #############################
 # System files
 #

hello_device是自定义,其他左右两边的内容参考原生代码

diff --git a/sepolicy/device.te b/sepolicy/device.te
old mode 100644
new mode 100755
index 20f842c..e32a78d
--- a/sepolicy/device.te
+++ b/sepolicy/device.te
@@ -1,4 +1,5 @@
 # Device types
+type hello_device, dev_type;
 type device, dev_type, fs_type;
 type alarm_device, dev_type, mlstrustedobject;
 type adb_device, dev_type;

hello_device是我们上一步自定义的名称

android/external/sepolicy/目录下很多.te文件都是以进程名来结尾的,因为我们是需要system_server去访问dev/hello,因此,我们修改system_server.te文件

diff --git a/sepolicy/system_server.te b/sepolicy/system_server.te
old mode 100644
new mode 100755
index ef772e1..25d3102
--- a/sepolicy/system_server.te
+++ b/sepolicy/system_server.te
@@ -170,6 +170,7 @@ allow system_server video_device:chr_file rw_file_perms;
 allow system_server adbd_socket:sock_file rw_file_perms;
 allow system_server rtc_device:chr_file rw_file_perms;
 allow system_server audio_device:dir r_dir_perms;
+allow system_server hello_device:chr_file rw_file_perms; 
 
 # write access needed for MIDI
 allow system_server audio_device:chr_file rw_file_perms;

允许system_server进程拥有对hello_device的这个字符设备的读写权限;

编译验证

make snod -j32

这样,重新打包的system.img镜像文件就包含我们刚才编写的JNI方法了,也就是我们可以通过Android系统的Application Frameworks层提供的硬件服务HelloService来调用这些JNI方法,进而调用低层的硬件抽象层接口去访问硬件了

上一篇下一篇

猜你喜欢

热点阅读