前言
framework主要向上提供JAVA接口用于访问硬件设备,
一、新建
进入到frameworks\base\services\core\jni文件夹中,新建com_android_server_HelloxjqService.cpp文件。com_android_server表示硬件服务Helloxjqservice放在frameworks/base/services/java目录下的com/android/server目录的,这儿HelloxjqService是一个提供JAVA接口的硬件访问服务类。
#define LOG_TAG "HelloxjqService"
#include "JNIHelp.h"
#include "jni.h"
#include <utils/Log.h>
#include <utils/misc.h>
#include <utils/String8.h>
#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/timerfd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <linux/ioctl.h>
#include <linux/rtc.h>
#include <hardware/helloxjq.h>
#include <fcntl.h>
#include <stdio.h>
#include<malloc.h>
#include <hardware/hardware.h>
namespace android
{
//jstring to char*
char* jstringTostring(JNIEnv* env, jstring jstr);
//char* to jstring
jstring stoJstring(JNIEnv* env, const char* pat);
/*在硬件抽象层中定义的硬件访问结构体,参考<hardware/helloxjq.h>*/
struct helloxjq_device_t* device = NULL;
/*通过硬件抽象层定义的硬件访问接口读字符串*/
static jstring helloxjq_readString(JNIEnv* env, jobject clazz) {
jstring ret;
if(!device) {
ALOGI("Helloxjq JNI: device is not open.");
return NULL;
}
char *read_str = (char*)malloc(10);
device->read_string(device, &read_str);
ALOGI("Helloxjq JNI: read string %s from helloxjq device.", read_str);
ret = stoJstring(env,read_str);
free(read_str);
read_str = NULL;
return ret;
}
/*通过硬件抽象层定义的硬件访问接口写字符串*/
static jint helloxjq_writeString(JNIEnv* env, jobject clazz,jstring str) {
if(!device) {
ALOGI("Helloxjq JNI: device is not open.");
return -1;
}
char * local_str = jstringTostring(env,str);
device->write_string(device, local_str);
ALOGI("Helloxjq JNI: write string %s to helloxjq device.", local_str);
return sizeof(local_str);
}
/*通过硬件抽象层定义的硬件模块打开接口打开硬件设备*/
static inline int helloxjq_device_open(const hw_module_t* module, struct helloxjq_device_t** device) {
return module->methods->open(module, HELLOXJQ_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
}
/*通过硬件模块ID来加载指定的硬件抽象层模块并打开硬件*/
static jboolean helloxjq_init(JNIEnv* env, jclass clazz) {
helloxjq_module_t* module;
ALOGI("Helloxjq JNI: initializing......");
if(hw_get_module(HELLOXJQ_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) {
ALOGI("Helloxjq JNI: helloxjq Stub found.");
if(helloxjq_device_open(&(module->common), &device) == 0) {
ALOGI("Helloxjq JNI: helloxjq device is open.");
return 0;
}
ALOGI("Helloxjq JNI: failed to open helloxjq device.");
return -1;
}
ALOGI("Helloxjq JNI: failed to get helloxjq stub module.");
return -1;
}
/*JNI方法表*/
static const JNINativeMethod method_table[] = {
{"init_native", "()Z", (void*)helloxjq_init},
{"readString_native", "()Ljava/lang/String;", (void*)helloxjq_readString},
{"wirteString_native", "(Ljava/lang/String;)I", (void*)helloxjq_writeString},
};
/*注册JNI方法*/
int register_android_server_HelloxjqService(JNIEnv *env) {
ALOGI("SystemServer :register_android_server_HelloxjqService.");
return jniRegisterNativeMethods(env, "com/android/server/HelloxjqService", method_table, NELEM(method_table));
}
//jstring to char*
char* jstringTostring(JNIEnv* env, jstring jstr)
{
char* rtn = NULL;
jclass clsstring = env->FindClass("java/lang/String");
jstring strencode = env->NewStringUTF("utf-8");
jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
jsize alen = env->GetArrayLength(barr);
jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
if (alen > 0)
{
rtn = (char*)malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
env->ReleaseByteArrayElements(barr, ba, 0);
return rtn;
}
//char* to jstring
jstring stoJstring(JNIEnv* env, const char* pat)
{
jclass strClass = env->FindClass("java/lang/String");
jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");
jbyteArray bytes = env->NewByteArray(strlen(pat));
env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat);
jstring encoding = env->NewStringUTF("utf-8");
return (jstring)env->NewObject(strClass, ctorID, bytes, encoding);
}
};
进入到frameworks/base/core/java/android/os目录,添加 IHelloxjqService.aidl 文件:
package android.os;
interface IHelloxjqService {
int wirteString(String str);
String readString();
}
进入到 frameworks/base/services/java/com/android/server 目录,添加 HelloxjqService.java 文件:
package com.android.server;
import android.content.Context;
import android.os.IHelloxjqService;
import android.util.Slog;
public class HelloxjqService extends IHelloxjqService.Stub {
private static final String TAG = "HelloxjqService";
HelloxjqService() {
init_native();
}
public int wirteString(java.lang.String str){
return wirteString_native(str);
}
public java.lang.String readString() {
return readString_native();
}
private static native boolean init_native();
private static native int wirteString_native(String str);
private static native String readString_native();
};
二、修改
-
修改frameworks/base/services/jni目录下的 onload.cpp 文件,在 JNI_OnLoad函数中的return之前添加下面一句:
register_android_server_HelloxjqService(env);
在namespace中添加
int register_android_server_HelloxjqService(JNIEnv* env);
这样,在系统初始化时,就会调用register_android_server_HelloxjqService方法来加载JNI方法了。 -
在同目录下的Android.mk中在LOCAL_SRC_FILES变量中增加
$(LOCAL_REL_DIR)/com_android_server_HelloxjqService.cpp \
-
进入到 frameworks/base 目录,打开 Android.mk 文件,在 LOCAL_SRC_FILES 变量中加入这么一行:注:一定要在LOCAL_SRC_FILES变量中
core/java/android/os/IHelloxjqService.aidl \
-
打开frameworks/base/services/java/com/android/server 目录下的 SystemServer.java 文件,
添加头文件import com.android.server.HelloxjqService;
在其中的 run() 函数中找到
try {
Slog.i(TAG, "DiskStats Service");
ServiceManager.addService("diskstats", new DiskStatsService(context));
} catch (Throwable e) {
reportWtf("starting DiskStats Service", e);
}
这一段,在后面加上下面的代码:
try {
Slog.i(TAG, "Helloxjq Service");
ServiceManager.addService("helloxjq", new HelloxjqService());
} catch (Throwable e) {
Slog.e(TAG, "Failure starting Helloxjq Service", e);
}
三、编译
- 编译JNI
编译mmm frameworks/base/services/core/jni/
打包make snod
- 编译service
编译IHelloxjqService的stub接口:先执行mmm frameworks/base
编译 HelloxjqService 服务:mmm frameworks/base/services/java
重新打包:make snod
我看到很多帖子说make snod有问题,如果出现奇奇怪怪的问题,就使用make clean清理一遍工程,直接整编。
本章节出现问题很可能会导致系统一直重启,这时,可以通过查看Log,查看相关服务是否启动。