開發(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]會拋出
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)用低層的硬件抽象層接口去訪問硬件了