Android 字符驅(qū)動#2#開發(fā)Android硬件訪問服務(wù)和JNI

開發(fā)Android硬件訪問服務(wù)

定義硬件訪問服務(wù)接口

首先,在android的源碼framework目錄犬第,創(chuàng)建aidl文件锦积,為其他應(yīng)用提供上層調(diào)用接口

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文件中,需要聲明創(chuàng)建的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 \
 

定義硬件訪問服務(wù)

在android源碼的server目錄瓶殃,創(chuàng)建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);

}


開發(fā)硬件訪問的JNI程序

com_jdf_android_server_hal_HelloService.cpp###

進(jìn)入services的jni目錄,創(chuàng)建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);//對應(yīng)hello.h的結(jié)構(gòu)體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;
    }
}

主要關(guān)注三個地方:
1:hello_init->hw_get_module("hello" )加載對應(yīng)的hello的硬件抽象層遥椿,也就是上一節(jié)在以下方法聲明的

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函數(shù)中淆储,第二個參數(shù)的值必須對應(yīng)HelloService所在的包的路徑冠场,即com/jdf/android/server/hal(下節(jié)會創(chuàng)建改服務(wù)相關(guān)文件)

修改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系統(tǒng)初始化時碴裙,就會自動加載該JNI方法調(diào)用表

修改Android.mk編譯文件###

在Android.mk文件中進(jìn)行聲明

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))

啟動硬件訪問服務(wù)###

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);

以上步驟完整后,嘗試去刷機(jī)点额,驗證舔株,在HelloService初始化過程,也就是下圖所示流程:

![hw_get_module]
jeJzTw9.png

會拋出

HelloHal fail open /dev/hello -- Permission denied

因此还棱,我們還需要設(shè)置system_server對/dev/hello的訪問權(quán)限

修改SePolicy的權(quán)限

HelloServer注冊權(quán)限

  • 修改 /external/sepolicy/service.te

在最后一行添加

type hello_service, system_api_service, system_server_service, service_manager_type;

type關(guān)鍵字载慈,把一個自定義的域與原有的域相關(guān)聯(lián)
聲明hello_service是一個system_server服務(wù)

  • 定義服務(wù)名稱
    修改 /external/sepolicy/service_contexts 文件
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對內(nèi)核節(jié)點訪問權(quán)限
服務(wù)添加成功后办铡,還需要設(shè)置systemserver對/dev/hello的操作權(quán)限

  • 打開文件android/external/sepolicy/file_contexts.be,,聲明權(quán)限
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是自定義琳要,其他左右兩邊的內(nèi)容參考原生代碼

  • 打開文件AndroidL/android/external/sepolicy/device.te
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是我們上一步自定義的名稱

  • 修改system_server.te文件

android/external/sepolicy/目錄下很多.te文件都是以進(jìn)程名來結(jié)尾的寡具,因為我們是需要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進(jìn)程擁有對hello_device的這個字符設(shè)備的讀寫權(quán)限童叠;

編譯驗證

make snod -j32

這樣,重新打包的system.img鏡像文件就包含我們剛才編寫的JNI方法了课幕,也就是我們可以通過Android系統(tǒng)的Application Frameworks層提供的硬件服務(wù)HelloService來調(diào)用這些JNI方法拯钻,進(jìn)而調(diào)用低層的硬件抽象層接口去訪問硬件了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末帖努,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子粪般,更是在濱河造成了極大的恐慌拼余,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亩歹,死亡現(xiàn)場離奇詭異匙监,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)小作,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門亭姥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人顾稀,你說我怎么就攤上這事达罗。” “怎么了静秆?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵粮揉,是天一觀的道長。 經(jīng)常有香客問我抚笔,道長扶认,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任殊橙,我火速辦了婚禮辐宾,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘膨蛮。我一直安慰自己叠纹,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布敞葛。 她就那樣靜靜地躺著吊洼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪制肮。 梳的紋絲不亂的頭發(fā)上冒窍,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機(jī)與錄音豺鼻,去河邊找鬼综液。 笑死,一個胖子當(dāng)著我的面吹牛儒飒,可吹牛的內(nèi)容都是我干的谬莹。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼附帽!你這毒婦竟也來了埠戳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤蕉扮,失蹤者是張志新(化名)和其女友劉穎整胃,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體喳钟,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡屁使,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了奔则。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蛮寂。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡日月,死狀恐怖焕蹄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情左冬,我是刑警寧澤抽莱,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布范抓,位于F島的核電站,受9級特大地震影響岸蜗,放射性物質(zhì)發(fā)生泄漏尉咕。R本人自食惡果不足惜叠蝇,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一璃岳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧悔捶,春花似錦铃慷、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至堂淡,卻和暖如春馋缅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背绢淀。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工萤悴, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人皆的。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓覆履,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子硝全,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353