Android JNI是一种技术,提供Java调用Android native代码或者native调用Java代码的一种机制,并不提供策略。本文实现了基于前面两篇文章:
Android标准架构实例分析之编写最简单的hello驱动
http://blog.csdn.net/eliot_shao/article/details/51860229
Android架构实例分析之编写hello驱动的HAL层代码
http://blog.csdn.net/eliot_shao/article/details/51861905
所实现的JNI案例。对HAL层提供的方法进行“翻译”,并转化成android runtime的JNI方法表,当Java代码调用时候可以正确的寻找到native的代码。
首先上一张Android JNI技术的工作原理图:
在图中主要描述Java-jni-native的一个调用流程。下面进行按步骤讲解:
1、Java代码通过System.loadLibrary(“android_servers”); 加载JNI静态库;
2、Android runtime自动调用JNI静态库中的JNI_OnLoad函数;
3、JNI_OnLoad调用jniRegisterNativeMethods函数,注册多个或者一个JNINativeMethod到Android runtime的gMthods链表中;
4、Java代码声明并调用相关的native代码;
5、Android runtime查找gMthods链表找到前面注册的本地函数指针,然后执行。
注意:JNI和HAL的衔接是通过JNI的代码
hw_get_module(HELLO_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0)
实现的。
本文使用的hello的案例是以system_server进程上建立的,后面会创建一个hello的本地服务。下面是对system_server进程调用JNI过程进行分析。
1、frameworks\base\services\java\com\android\server\SystemServer.java
// Initialize native services.
System.loadLibrary("android_servers");
2、frameworks\base\services\core\jni\onload.cpp
jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
register_android_server_HelloService(env);//add by eliot_shao
3、frameworks\base\services\core\jni\com_android_server_HelloService.cpp
jniRegisterNativeMethods(env, "com/android/server/HelloService", method_table, NELEM(method_table));
static const JNINativeMethod method_table[] = {
{"init_native", "()Z", (void*)hello_init},
{"setVal_native", "(I)V", (void*)hello_setVal},
{"getVal_native", "()I", (void*)hello_getVal},
};
4、frameworks\base\services\Android.mk
LOCAL_MODULE:= libandroid_servers
rameworks\base\services\core\jni\com_android_server_HelloService.cpp
#define LOG_TAG "HelloService"
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
#include
#include
#include
#include
#include
namespace android
{
struct hello_device_t* hello_device = NULL;
static void hello_setVal(JNIEnv* env, jobject clazz, jint value) {
int val = value;
ALOGI("Hello JNI: set value %d to device.", val);
if(!hello_device) {
ALOGI("Hello JNI: device is not open.");
return;
}
hello_device->set_val(hello_device, val);
}
static jint hello_getVal(JNIEnv* env, jobject clazz) {
int val = 0;
if(!hello_device) {
ALOGI("Hello JNI: device is not open.");
return val;
}
hello_device->get_val(hello_device, &val);
ALOGI("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);
}
static jboolean hello_init(JNIEnv* env, jclass clazz) {
hello_module_t* module;
ALOGI("Hello JNI: initializing......");
if(hw_get_module(HELLO_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) {
ALOGI("Hello JNI: hello Stub found.");
if(hello_device_open(&(module->common), &hello_device) == 0) {
ALOGI("Hello JNI: hello device is open.");
return 0;
}
ALOGE("Hello JNI: failed to open hello device.");
return -1;
}
ALOGE("Hello JNI: failed to get hello stub module.");
return -1;
}
static const JNINativeMethod method_table[] = {
{"init_native", "()Z", (void*)hello_init},
{"setVal_native", "(I)V", (void*)hello_setVal},
{"getVal_native", "()I", (void*)hello_getVal},
};
int register_android_server_HelloService(JNIEnv *env) {
return jniRegisterNativeMethods(env, "com/android/server/HelloService", method_table, NELEM(method_table));
}
};
frameworks\base\services\core\jni\onload.cpp
/*
* Copyright (C) 2014 MediaTek Inc.
* Modification based on code covered by the mentioned copyright
* and/or permission notice(s).
*/
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "JNIHelp.h"
#include "jni.h"
#include "utils/Log.h"
#include "utils/misc.h"
namespace android {
int register_android_server_AlarmManagerService(JNIEnv* env);
int register_android_server_AssetAtlasService(JNIEnv* env);
int register_android_server_BatteryStatsService(JNIEnv* env);
int register_android_server_ConsumerIrService(JNIEnv *env);
int register_android_server_InputApplicationHandle(JNIEnv* env);
int register_android_server_InputWindowHandle(JNIEnv* env);
int register_android_server_InputManager(JNIEnv* env);
int register_android_server_LightsService(JNIEnv* env);
int register_android_server_PowerManagerService(JNIEnv* env);
int register_android_server_SerialService(JNIEnv* env);
int register_android_server_SystemServer(JNIEnv* env);
int register_android_server_UsbDeviceManager(JNIEnv* env);
int register_android_server_UsbMidiDevice(JNIEnv* env);
int register_android_server_UsbHostManager(JNIEnv* env);
int register_android_server_VibratorService(JNIEnv* env);
int register_android_server_location_GpsLocationProvider(JNIEnv* env);
int register_android_server_location_FlpHardwareProvider(JNIEnv* env);
int register_android_server_connectivity_Vpn(JNIEnv* env);
int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
int register_android_server_tv_TvInputHal(JNIEnv* env);
int register_android_server_PersistentDataBlockService(JNIEnv* env);
int register_android_server_Watchdog(JNIEnv* env);
int register_com_mediatek_perfservice_PerfServiceManager(JNIEnv* env);
#if defined (MTK_HDMI_SUPPORT)
int register_com_mediatek_hdmi_MtkHdmiManagerService(JNIEnv* env);
#endif
// Mediatek AAL support
int register_android_server_display_DisplayPowerController(JNIEnv* env);
#ifndef MTK_BSP_PACKAGE
int register_com_android_internal_app_ShutdownManager(JNIEnv *env);
#endif
int register_android_server_HelloService(JNIEnv *env);//add by eliot_shao
};
using namespace android;
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) {
ALOGE("GetEnv failed!");
return result;
}
ALOG_ASSERT(env, "Could not retrieve the env!");
register_android_server_PowerManagerService(env);
register_android_server_SerialService(env);
register_android_server_InputApplicationHandle(env);
register_android_server_InputWindowHandle(env);
register_android_server_InputManager(env);
register_android_server_LightsService(env);
register_android_server_AlarmManagerService(env);
register_android_server_UsbDeviceManager(env);
register_android_server_UsbMidiDevice(env);
register_android_server_UsbHostManager(env);
register_android_server_VibratorService(env);
register_android_server_SystemServer(env);
register_android_server_location_GpsLocationProvider(env);
register_android_server_location_FlpHardwareProvider(env);
register_android_server_connectivity_Vpn(env);
register_android_server_AssetAtlasService(env);
register_android_server_ConsumerIrService(env);
register_android_server_BatteryStatsService(env);
register_android_server_hdmi_HdmiCecController(env);
register_android_server_tv_TvInputHal(env);
register_android_server_PersistentDataBlockService(env);
register_android_server_Watchdog(env);
register_com_mediatek_perfservice_PerfServiceManager(env);
#if defined (MTK_HDMI_SUPPORT)
register_com_mediatek_hdmi_MtkHdmiManagerService(env);
#endif
// Mediatek AAL support
register_android_server_display_DisplayPowerController(env);
#ifndef MTK_BSP_PACKAGE
register_com_android_internal_app_ShutdownManager(env);
#endif
register_android_server_HelloService(env);//add by eliot_shao
return JNI_VERSION_1_4;
}
android 2.3 和android 6.0版本的JNI位置发生了一点变化。
将com_android_server_HelloService.cpp放入frameworks\base\services\core\jni\
修改: LOGI–>ALOGI
LOGE–>ALOGE
修改onload.cpp 和 Android.mk
编译:mmm frameworks/base/services/
生成system/lib/libandroid_servers.so