Android HAL开发之Java应用程序直接调用JNI库
2013-04-22 17:28
399 查看
这篇先介绍最简单的一种实现方式 - Java应用程序直接调用JNI库。
由于JNI技术的存在,在Android中,java程序能够很好的调用C/C++库。我们这里设计一个简单的HAL,一共只有三层: HAL stub <-> JNI 库 <-> JAVA应用程序。
我们现看看HAL stub的代码:
我在前面关于HAL技术的文章中已经介绍了如何写HAL stub,需要注意的只有hw_module_t和hw_device_t这两个数据结构,这里就不复述了。
下面看看JNI层代码:
上面的Jni代码首先通过hw_get_module得到HAL stub,open以后就可以直接使用HAL stub中定义的接口。这里还需要注意JNI_OnLoad这个函数,当Jni库被App load的时候,该函数将会自动被调用,所以我们在这里实现了注册Led Service的操作,也就是说把C/C++的接口映射到Java中去,这样在Java APP中就可以使用该接口了。在register_mokoid_server_LedService中,我们需要注意kclassname指定了需要调用该Jni库的Java
APP类 - com.mokoid.LedClient.LedClient,也就是说该Jni库只能提供给该Java程序使用。
最后是应用程序代码:
上面使用System.load来装载Jni库,当然我们也可以使用System.loadLibrary来装载,他们的唯一区别就是前者需要指定完整的路径,后者会在系统路径上(比如/system/lib/) 查找库。装载完该Jni库后,就可以使用映射后的接口了(_init, _set_on, _set_off)。
上面这种HAL的实现方式比较简单,但是也存在一个很大的问题,就是Jni库只能提供给某一个特定的Java使用,如何克服这个问题?我们可以在APP和Jni之间加一层Java service,该Jni提供给Java service使用,而所有的APP利用该service来使用Jni提供的接口。这样的话,在应用程序层,就不需要关心Jni是如何实现的了。下一篇我们会介绍这种方法。
本文出自 “Mobile
and Linux Deve..” 博客,请务必保留此出处/article/4442093.html
由于JNI技术的存在,在Android中,java程序能够很好的调用C/C++库。我们这里设计一个简单的HAL,一共只有三层: HAL stub <-> JNI 库 <-> JAVA应用程序。
我们现看看HAL stub的代码:
int led_device_close(struct hw_device_t* device) { struct led_control_device_t* ctx = (struct led_control_device_t*)device; if (ctx) { free(ctx); } return 0; } int led_on(struct led_control_device_t *dev, int32_t led) { LOGI("LED Stub: set %d on.", led); return 0; } int led_off(struct led_control_device_t *dev, int32_t led) { LOGI("LED Stub: set %d off.", led); return 0; } static int led_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device) { struct led_control_device_t *dev; dev = (struct led_control_device_t *)malloc(sizeof(*dev)); memset(dev, 0, sizeof(*dev)); dev->common.tag = HARDWARE_DEVICE_TAG; dev->common.version = 0; dev->common.module = module; dev->common.close = led_device_close; dev->set_on = led_on; dev->set_off = led_off; *device = &dev->common; success: return 0; } static struct hw_module_methods_t led_module_methods = { open: led_device_open }; const struct led_module_t HAL_MODULE_INFO_SYM = { common: { tag: HARDWARE_MODULE_TAG, version_major: 1, version_minor: 0, id: LED_HARDWARE_MODULE_ID, name: "Sample LED Stub", author: "The Mokoid Open Source Project", methods: &led_module_methods, } /* supporting APIs go here */ };
我在前面关于HAL技术的文章中已经介绍了如何写HAL stub,需要注意的只有hw_module_t和hw_device_t这两个数据结构,这里就不复述了。
下面看看JNI层代码:
struct led_control_device_t *sLedDevice = NULL; static jboolean mokoid_setOn(JNIEnv* env, jobject thiz, jint led) { LOGI("LedService JNI: mokoid_setOn() is invoked."); if (sLedDevice == NULL) { LOGI("LedService JNI: sLedDevice was not fetched correctly."); return -1; } else { return sLedDevice->set_on(sLedDevice, led); } } static jboolean mokoid_setOff(JNIEnv* env, jobject thiz, jint led) { LOGI("LedService JNI: mokoid_setOff() is invoked."); if (sLedDevice == NULL) { LOGI("LedService JNI: sLedDevice was not fetched correctly."); return -1; } else { return sLedDevice->set_off(sLedDevice, led); } } /** helper APIs */ static inline int led_control_open(const struct hw_module_t* module, struct led_control_device_t** device) { return module->methods->open(module, LED_HARDWARE_MODULE_ID, (struct hw_device_t**)device); } static jboolean mokoid_init(JNIEnv *env, jclass clazz) { led_module_t* module; if (hw_get_module(LED_HARDWARE_MODULE_ID, (const hw_module_t**)&module) == 0) { LOGI("LedService JNI: LED Stub found."); if (led_control_open(&module->common, &sLedDevice) == 0) { LOGI("LedService JNI: Got Stub operations."); return 0; } } LOGE("LedService JNI: Get Stub operations failed."); return -1; } static const JNINativeMethod gMethods[] = { { "_init", "()Z", (void *)mokoid_init }, { "_set_on", "(I)Z", (void *)mokoid_setOn }, { "_set_off", "(I)Z", (void *)mokoid_setOff }, }; int register_mokoid_server_LedService(JNIEnv* env) { static const char* const kClassName = "com/mokoid/LedClient/LedClient"; jclass clazz; /* look up the class */ clazz = env->FindClass(kClassName); if (clazz == NULL) { LOGE("Can't find class %s\n", kClassName); return -1; } /* register all the methods */ if (env->RegisterNatives(clazz, gMethods, sizeof(gMethods) / sizeof(gMethods[0])) != JNI_OK) { LOGE("Failed registering methods for %s\n", kClassName); return -1; } /* fill out the rest of the ID cache */ return 0; } extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env = NULL; jint result = -1; if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { LOGE("GetEnv failed!"); return result; } LOG_ASSERT(env, "Could not retrieve the env!"); register_mokoid_server_LedService(env); return JNI_VERSION_1_4; }
上面的Jni代码首先通过hw_get_module得到HAL stub,open以后就可以直接使用HAL stub中定义的接口。这里还需要注意JNI_OnLoad这个函数,当Jni库被App load的时候,该函数将会自动被调用,所以我们在这里实现了注册Led Service的操作,也就是说把C/C++的接口映射到Java中去,这样在Java APP中就可以使用该接口了。在register_mokoid_server_LedService中,我们需要注意kclassname指定了需要调用该Jni库的Java
APP类 - com.mokoid.LedClient.LedClient,也就是说该Jni库只能提供给该Java程序使用。
最后是应用程序代码:
public class LedClient extends Activity { static { System.load("/system/lib/libmokoid_runtime.so"); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Call an API on the library. _init(); _set_on(1); _set_off(2); TextView tv = new TextView(this); tv.setText("LED 1 is on. LED 2 is off."); setContentView(tv); } private static native boolean _init(); private static native boolean _set_on(int led); private static native boolean _set_off(int led); }
上面使用System.load来装载Jni库,当然我们也可以使用System.loadLibrary来装载,他们的唯一区别就是前者需要指定完整的路径,后者会在系统路径上(比如/system/lib/) 查找库。装载完该Jni库后,就可以使用映射后的接口了(_init, _set_on, _set_off)。
上面这种HAL的实现方式比较简单,但是也存在一个很大的问题,就是Jni库只能提供给某一个特定的Java使用,如何克服这个问题?我们可以在APP和Jni之间加一层Java service,该Jni提供给Java service使用,而所有的APP利用该service来使用Jni提供的接口。这样的话,在应用程序层,就不需要关心Jni是如何实现的了。下一篇我们会介绍这种方法。
本文出自 “Mobile
and Linux Deve..” 博客,请务必保留此出处/article/4442093.html
相关文章推荐
- Android HAL实现1——Java应用程序直接调用JNI库
- android jni开发 把一段java代码转换成c++方式调用
- 【学习Android NDK开发】Java通过JNI调用native方法
- [原创]Android 基于NDK的JNI开发 C调用java和java调用C的进阶教程
- Android-本地方法与Java相互调用-自定义ProgressBar(锅炉压力监测例子)/NDK-JNI开发实例(七)
- Cocos2d-x游戏开发之Cocos2dx通过JNI调用Android的Java代码(webView实例)
- Android JNI开发之c语言调用java方法
- 【iOS-cocos2d-X 游戏开发之十三】cocos2dx通过Jni调用Android的Java层代码(上)
- android jni开发 把一段java代码转换成c++方式调用
- Android-NDK开发之基础--Android JNI实例代码(一)-- 在JNI中执行Java方法--C/C++调用Java
- tiny210 hal 4 Android系统中编写JNI方法在应用程序框架层提供Java接口访问硬件
- Android JNI/NDK开发(2)JNI实现C/C++与Android/JAVA相互调用
- 【iOS-cocos2d-X 游戏开发之十三】cocos2dx通过Jni调用Android的Java层代码(下)
- Android JNI开发之C/C++层调用JAVA
- Android-NDK开发之基础--Android JNI实例代码(一)-- 在JNI中执行Java方法--C/C++调用Java
- Android-本地方法C调用Java中的方法/NDK-JNI开发实例(六)
- Android 基于NDK的JNI开发 C调用java和java调用C的进阶教程
- Android 基于NDK的JNI开发 C调用java和java调用C的进阶教程
- 【iOS-cocos2d-X 游戏开发之十三】详细讲解在Xcode中利用预编译并通过Jni调用Android的Java层代码(cocos2dx里访问调用Android函数)!
- Android Studio Jni开发(二)实现Native调用java方法和Native调用Android API