学习并转载了老罗的Java到C通过JNI调用的过程,在自己的平台上逐一实现,很是受用。本文将在此基础上,进行C到JAVA调用的验证。C到JAVA的调用在android系统GPS部分数据上报部分已经用到。
为了测试,在hardware中添加dev->init函数,实现callback的简历,并在init中创建线程,循环上报,添加后的代码如下:
/hardware/libhardware/include/hardware/hello.h
#ifndef ANDROID_HELLO_INTERFACE_H
#define ANDROID_HELLO_INTERFACE_H
#include <sys/types.h>
#include <hardware/hardware.h>
#include <pthread.h>
__BEGIN_DECLS
/*定义模块ID*/
#define HELLO_HARDWARE_MODULE_ID "hello"
typedef void (* hello_val_callback)(const char* val,int length);
typedef pthread_t (* hello_create_thread)(const char* name, void (*start)(void *), void* arg);
typedef struct {
/** set to sizeof(GpsCallbacks) */
size_t size;
hello_val_callback hello_cb;
hello_create_thread create_thread_cb;
} HelloCallbacks;
/*硬件模块结构体*/
struct hello_module_t {
struct hw_module_t common;
};
/*硬件接口结构体*/
struct hello_device_t {
struct hw_device_t common;
int fd;
int (*set_val)(struct hello_device_t* dev, int val);
int (*get_val)(struct hello_device_t* dev, int* val);
int (*init)( HelloCallbacks* callbacks );
int (*remove)(struct hello_device_t* dev, int* val);
};
__END_DECLS
#endif
/hardware/xxxx/libhellotest/hello.c
#define LOG_TAG "HelloStub"
#include <hardware/hardware.h>
#include <hardware/hello.h>
#include <fcntl.h>
#include <errno.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#include <stdio.h>
#include <sys/types.h>
#include <stdbool.h>
#define DEVICE_NAME "/dev/hello"
#define MODULE_NAME "Hello"
#define MODULE_AUTHOR "zhhpudk@163.com"
typedef struct {
bool use;
HelloCallbacks callbacks;
pthread_t thread;
} HelloState;
static HelloState _hello_state[1];
static HelloState *hello_state = _hello_state;
/*设备打开和关闭接口*/
static int hello_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device);
static int hello_device_close(struct hw_device_t* device);
/*设备访问接口*/
static int hello_set_val(struct hello_device_t* dev, int val);
static int hello_get_val(struct hello_device_t* dev, int* val);
static int hello_init(HelloCallbacks* callbacks);
//static int hello_close(struct hello_device_t* dev);
static int hello_remove(struct hello_device_t* dev, int* val);
/*模块方法表*/
static struct hw_module_methods_t hello_module_methods = {
open: hello_device_open
};
/*模块实例变量*/
struct hello_module_t HAL_MODULE_INFO_SYM = {
common: {
tag: HARDWARE_MODULE_TAG,
version_major: 1,
version_minor: 0,
id: HELLO_HARDWARE_MODULE_ID,
name: MODULE_NAME,
author: MODULE_AUTHOR,
methods: &hello_module_methods,
}
};
static int hello_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device) {
struct hello_device_t* dev;
dev = (struct hello_device_t*)malloc(sizeof(struct hello_device_t));
if(!dev) {
LOGE("Hello Stub: failed to alloc space");
return -EFAULT;
}
memset(dev, 0, sizeof(struct hello_device_t));
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = 0;
dev->common.module = (hw_module_t*)module;
dev->common.close = hello_device_close;
dev->set_val = hello_set_val;
dev->get_val = hello_get_val;
dev->init=hello_init;
dev->remove=hello_remove;
if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) {
LOGE("Hello Stub: failed to open /dev/hello -- %s.", strerror(errno));
free(dev);
return -EFAULT;
}
//*device = &(dev->common);
*device = (struct hw_device_t*)dev;
LOGI("Hello Stub: open /dev/hello successfully.");
return 0;
}
static int hello_device_close(struct hw_device_t* device) {
struct hello_device_t* hello_device = (struct hello_device_t*)device;
LOGI("Hello Stub: close /dev/hello successfully.");
if(hello_device) {
close(hello_device->fd);
free(hello_device);
}
return 0;
}
static int hello_set_val(struct hello_device_t* dev, int val) {
LOGI("Hello Stub: set value %d to device.", val);
write(dev->fd, &val, sizeof(val));
return 0;
}
static int hello_get_val(struct hello_device_t* dev, int* val) {
if(!val) {
LOGE("Hello Stub: error val pointer");
return -EFAULT;
}
read(dev->fd, val, sizeof(*val));
LOGI("Hello Stub: get value %d from device", *val);
return 0;
}
static void *hello_state_thread( void* arg )
{
HelloState* state = (HelloState*) arg;
char val[1]={0};
// now loop
for (;;)
{
sleep(5);
if(!state->use)
{
LOGI("Hello Stub: hello thread exit");
break;
}
val[0]++;
LOGI("Hello Stub: hello thread val %d .",val[0]);
state->callbacks.hello_cb(val,1);
}
return NULL;
}
static int hello_init(HelloCallbacks* callbacks)
{
HelloState* s = _hello_state;
LOGI("Hello Stub: hello init.");
s->callbacks = *callbacks;
if(callbacks!= NULL && callbacks->create_thread_cb != NULL)
s->thread = s->callbacks.create_thread_cb("hello", hello_state_thread, s);
if (!s->thread)
{
LOGE("could not create hello thread: %s", strerror(errno));
return -1;
}
s->use = true;
return 0;
}
static int hello_remove(struct hello_device_t* dev, int* val)
{
struct hello_device_t* hello_device = (struct hello_device_t*)dev;
void *dummy;
hello_state->use=false;
LOGI("Hello Stub: hello_remove value %d to device.", val);
if(hello_device) {
close(hello_device->fd);
free(hello_device);
}
return 0;
}
JNI中通过GetMethodID方法实现,具体代码如下:
/frameworks/base/services/jni/com_android_server_HelloSerivce.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/hardware.h>
#include <hardware/hello.h>
#include <stdio.h>
#include <pthread.h>
static jobject mCallbacksObj = NULL;
static jmethodID method_receive;
namespace android
{
static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
if (env->ExceptionCheck()) {
LOGE("An exception was thrown by callback '%s'.", methodName);
LOGE_EX(env);
env->ExceptionClear();
}
}
static void hello_recval_callback(const char* buf,int len)
{
JNIEnv* env = AndroidRuntime::getJNIEnv();
jbyteArray var = NULL;
//jbyte buffer[100];
jbyte *buffer;
LOGI("hello recval_callback buf[0] %d len %d",buf[0],len);
if(len)
{
var = env->NewByteArray(len);
buffer = (jbyte*)calloc(len, sizeof(jbyte));
}
if(var)
{
for(int i=0;i<len;i++)
//buffer[i] = buf[i];
*(buffer+i)=*(buf+i);
env->SetByteArrayRegion(var,0,len,buffer);
}
//调用java方法上报数据
env->CallVoidMethod(mCallbacksObj, method_receive,var,len);
if(var){
env->DeleteLocalRef(var);
free(buffer);
buffer = NULL;
}
checkAndClearExceptionFromCallback(env, __FUNCTION__);
}
static pthread_t hello_thread_callback(const char* name, void (*start)(void *), void* arg)
{
return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);
}
HelloCallbacks sHelloCallback =
{
sizeof(HelloCallbacks),
hello_recval_callback,
hello_thread_callback
};
static void android_hello_class_init_native(JNIEnv* env, jclass clazz)
{
method_receive = env->GetMethodID(clazz, "Receive", "([BI)V");
}
/*在硬件抽象层中定义的硬件访问结构体,参考<hardware/hello.h>*/
struct hello_device_t* hello_device = NULL;
/*通过硬件抽象层定义的硬件访问接口设置硬件寄存器val的值*/
static void hello_setVal(JNIEnv* env, jobject clazz, jint value) {
int val = value;
LOGI("Hello JNI: set value %d to device.", val);
if(!hello_device) {
LOGI("Hello JNI: device is not open.");
return;
}
hello_device->set_val(hello_device, val);
}
/*通过硬件抽象层定义的硬件访问接口读取硬件寄存器val的值*/
static jint hello_getVal(JNIEnv* env, jobject clazz) {
int val = 0;
if(!hello_device) {
LOGI("Hello JNI: device is not open.");
return val;
}
hello_device->get_val(hello_device, &val);
LOGI("Hello JNI: get value %d from device.", val);
return val;
}
/*通过硬件抽象层定义的硬件模块打开接口打开硬件设备*/
static inline int hello_device_open(const hw_module_t* module, struct hello_device_t** device) {
return module->methods->open(module, HELLO_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
}
/*通过硬件模块ID来加载指定的硬件抽象层模块并打开硬件*/
static jboolean hello_init(JNIEnv* env, jobject clazz) {
hello_module_t* module;
// this must be set before calling into the HAL library
if (!mCallbacksObj)
mCallbacksObj = env->NewGlobalRef(clazz);
LOGI("Hello JNI: initializing......");
if(hw_get_module(HELLO_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) {
LOGI("Hello JNI: hello Stub found.");
if(hello_device_open(&(module->common), &hello_device) == 0) {
LOGI("Hello JNI: hello device is open.");
if(hello_device->init(&sHelloCallback)==0){
LOGI("Hello JNI: Init HelloCallback.");
return true;
}
LOGE("Hello JNI : Init HelloCallback Error");
return false;
}
LOGE("Hello JNI: failed to open hello device.");
return false;
}
LOGE("Hello JNI: failed to get hello stub module.");
return false;
}
static jboolean hello_remove(JNIEnv* env, jobject clazz) {
int val = 0;
if(!hello_device) {
LOGI("Hello JNI: device is not open.");
return false;
}
LOGI("hello_close 111");
if(hello_device->remove(hello_device,&val)!=0)
return false;
else
return true;
// LOGI("hello_close");
//return true;
}
/*JNI方法表*/
static const JNINativeMethod method_table[] = {
{"class_init_native", "()V", (void *)android_hello_class_init_native},
{"init_native", "()Z", (void*)hello_init},
{"remove_native", "()Z", (void*)hello_remove},
{"setVal_native", "(I)V", (void*)hello_setVal},
{"getVal_native", "()I", (void*)hello_getVal},
};
/*注册JNI方法*/
int register_android_server_HelloService(JNIEnv *env) {
return jniRegisterNativeMethods(env, "com/android/server/HelloService", method_table, NELEM(method_table));
}
};
Java中实现Receive方法,回调实现:
/framework/base/services/java/com/android/server/HelloService.java
package com.android.server;
import android.content.Context;
import android.os.IHelloService;
import android.util.Slog;
import android.util.Log;
import java.util.Arrays;
public class HelloService extends IHelloService.Stub {
private static final String TAG = "HelloService";
private static Context mContext = null;
HelloService(Context context)
{
mContext = context;
}
public void setVal(int val) {
setVal_native(val);
Log.d("Hello Test", "Setval");
}
public int getVal() {
Log.d("Hello Test", "getval");
return getVal_native();
}
public boolean hello_init() {
Log.d("Hello Test","init");
return init_native();
}
public void hello_close(){
Log.d("Hello Test","close");
remove_native();
return;
}
private void Receive(byte[] buffer,int length){
//
Log.d("Hello Test", "buffer "+(buffer[0]&0xFF)+" length "+length);
}
static { class_init_native(); }
private static native boolean init_native();
private static native boolean remove_native();
private static native void class_init_native();
private static native void setVal_native(int val);
private static native int getVal_native();
};
实现aidl接口,/frameworks/base/core/java/android/os/IHelloService.aidl
package android.os;
interface IHelloService {
boolean hello_init();
void hello_close();
void setVal(int val);
int getVal();
}
package com.harvey.hello;
import com.harvey.hello.R;
import android.app.Activity;
import android.os.ServiceManager;
import android.os.Bundle;
import android.os.IHelloService;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
public class Hello extends Activity implements OnClickListener {
private final static String LOG_TAG = "com.harvey.renju.Hello";
private IHelloService helloService = null;
private EditText valueText = null;
private Button readButton = null;
private Button writeButton = null;
private Button clearButton = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
helloService = IHelloService.Stub.asInterface(
ServiceManager.getService("hello"));
try {
helloService.hello_init();
} catch (RemoteException e) {
Log.e(LOG_TAG, "Remote Exception while init_native device.");
}
valueText = (EditText)findViewById(R.id.edit_value);
readButton = (Button)findViewById(R.id.button_read);
writeButton = (Button)findViewById(R.id.button_write);
clearButton = (Button)findViewById(R.id.button_clear);
readButton.setOnClickListener(this);
writeButton.setOnClickListener(this);
clearButton.setOnClickListener(this);
Log.i(LOG_TAG, "Hello Activity Created");
}
@Override
public void onClick(View v) {
if(v.equals(readButton)) {
try {
int val = helloService.getVal();
String text = String.valueOf(val);
valueText.setText(text);
} catch (RemoteException e) {
Log.e(LOG_TAG, "Remote Exception while reading value from device.");
}
}
else if(v.equals(writeButton)) {
try {
String text = valueText.getText().toString();
int val = Integer.parseInt(text);
helloService.setVal(val);
} catch (RemoteException e) {
Log.e(LOG_TAG, "Remote Exception while writing value to device.");
}
}
else if(v.equals(clearButton)) {
String text = "";
valueText.setText(text);
// try {
// helloService.hello_close();
// } catch (RemoteException e) {
// Log.e(LOG_TAG, "Remote Exception while Destroy device.");
// }
}
}
public void onDestroy() {
Log.i(LOG_TAG, "Hello Activity onDestroy called!");
try {
helloService.hello_close();
} catch (RemoteException e) {
Log.e(LOG_TAG, "Remote Exception while Destroy device.");
}
super.onDestroy();
}
}
注意:在编译时,一定要在添加文件下面通过mm编译后,再打包系统,或者是在make 文件中把添加的lib和apk添加到PRODUCT_PACKAGES下面才可以打包进去