文件位置:
frameworks\base\services\jni
动态注册文件:onload.cpp
#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_BatteryService(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_VibratorService(JNIEnv* env);
int register_android_server_SystemServer(JNIEnv* env);
int register_android_server_location_GpsLocationProvider(JNIEnv* env);
};
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) {
LOGE("GetEnv failed!");
return result;
}
LOG_ASSERT(env, "Could not retrieve the env!");
register_android_server_PowerManagerService(env);
register_android_server_InputManager(env);
register_android_server_LightsService(env);
register_android_server_AlarmManagerService(env);
register_android_server_BatteryService(env);
register_android_server_VibratorService(env);
register_android_server_SystemServer(env);
register_android_server_location_GpsLocationProvider(env);
return JNI_VERSION_1_4;
}
注册文件主要做了两件事情:1在android空间声明注册函数2.在C空间注册jni中注册相关的服务
将注册文件编译进内核
LOCAL_SRC_FILES:= \
com_android_server_AlarmManagerService.cpp \
com_android_server_BatteryService.cpp \
com_android_server_InputManager.cpp \
com_android_server_LightsService.cpp \
com_android_server_PowerManagerService.cpp \
com_android_server_SystemServer.cpp \
com_android_server_UsbService.cpp \
com_android_server_VibratorService.cpp \
com_android_server_location_GpsLocationProvider.cpp \
onload.cpp
3.JNI实现(com_android_server_LightsService.cpp)
/*
* 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.
*/
#define LOG_TAG "LightsService"
#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/lights.h>
#include <stdio.h>
namespace android
{
// These values must correspond with the LIGHT_ID constants in
// LightsService.java
enum {
LIGHT_INDEX_BACKLIGHT = 0,
LIGHT_INDEX_KEYBOARD = 1,
LIGHT_INDEX_BUTTONS = 2,
LIGHT_INDEX_BATTERY = 3,
LIGHT_INDEX_NOTIFICATIONS = 4,
LIGHT_INDEX_ATTENTION = 5,
LIGHT_INDEX_BLUETOOTH = 6,
LIGHT_INDEX_WIFI = 7,
LIGHT_COUNT
};
struct Devices {
light_device_t* lights[LIGHT_COUNT];
};
static light_device_t* get_device(hw_module_t* module, char const* name)
{
int err;
hw_device_t* device;
err = module->methods->open(module, name, &device);
if (err == 0) {
return (light_device_t*)device;
} else {
return NULL;
}
}
static jint init_native(JNIEnv *env, jobject clazz)
{
int err;
hw_module_t* module;
Devices* devices;
devices = (Devices*)malloc(sizeof(Devices));
err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
if (err == 0) {
devices->lights[LIGHT_INDEX_BACKLIGHT]
= get_device(module, LIGHT_ID_BACKLIGHT);
devices->lights[LIGHT_INDEX_KEYBOARD]
= get_device(module, LIGHT_ID_KEYBOARD);
devices->lights[LIGHT_INDEX_BUTTONS]
= get_device(module, LIGHT_ID_BUTTONS);
devices->lights[LIGHT_INDEX_BATTERY]
= get_device(module, LIGHT_ID_BATTERY);
devices->lights[LIGHT_INDEX_NOTIFICATIONS]
= get_device(module, LIGHT_ID_NOTIFICATIONS);
devices->lights[LIGHT_INDEX_ATTENTION]
= get_device(module, LIGHT_ID_ATTENTION);
devices->lights[LIGHT_INDEX_BLUETOOTH]
= get_device(module, LIGHT_ID_BLUETOOTH);
devices->lights[LIGHT_INDEX_WIFI]
= get_device(module, LIGHT_ID_WIFI);
} else {
memset(devices, 0, sizeof(Devices));
}
return (jint)devices;
}
static void finalize_native(JNIEnv *env, jobject clazz, int ptr)
{
Devices* devices = (Devices*)ptr;
if (devices == NULL) {
return;
}
free(devices);
}
static void setLight_native(JNIEnv *env, jobject clazz, int ptr,
int light, int colorARGB, int flashMode, int onMS, int offMS, int brightnessMode)
{
Devices* devices = (Devices*)ptr;
light_state_t state;
if (light < 0 || light >= LIGHT_COUNT || devices->lights[light] == NULL) {
return ;
}
memset(&state, 0, sizeof(light_state_t));
state.color = colorARGB;
state.flashMode = flashMode;
state.flashOnMS = onMS;
state.flashOffMS = offMS;
state.brightnessMode = brightnessMode;
devices->lights[light]->set_light(devices->lights[light], &state);
}
static JNINativeMethod method_table[] = {
{ "init_native", "()I", (void*)init_native },//int init_native()
{ "finalize_native", "(I)V", (void*)finalize_native },//void finalize_native(int)
{ "setLight_native", "(IIIIIII)V", (void*)setLight_native },//void setLight_native(int,int,int,int,int,int,int)
};
int register_android_server_LightsService(JNIEnv *env)
{
return jniRegisterNativeMethods(env, "com/android/server/LightsService",
method_table, NELEM(method_table));
}
};
这个文件主要完成的事情有
1.完成JNI向java的注册:
jniRegisterNativeMethods,这个函数体现JNI大部分的关键点,主要有env,JNI命名规则,函数签名。
当VM载入libxxx_jni.so这个库时,就会呼叫JNI_OnLoad()函数。在JNI_OnLoad()中注册本地函数,继续调用到AndroidRuntime::registerNativeMethods(),该函数向VM(即AndroidRuntime)注册gMethods[]数组中包含的本地函数了。AndroidRuntime::registerNativeMethods()起到了以下两个作用:
1,registerNativeMethods()函数使得java空间中的Native函数更加容易的找到对应的本地函数。(通过gMethods[]中的函数指针)
2,可以在执行期间进行本地函数的替换。因为gMethods[]数组是一个<java中函数名字,本地函数指针>的对应表,所以可以在程序的执行过程中,多次呼叫registerNativeMethods()函数来更换本地函数的指针,提高程序的弹性。
2.JNIEnv 介绍
JNIEnv 是一个与线程相关的变量,由于线程相关,所以线程B中不能使用线程A中的JNIEnv函数。那个多个线程由谁来保存并保证每个线程的JNIEnv结构体正确呢?
jint JNI_OnLoad(JavaVM* vm, void* reserved)全进程只有一个JavaVM对象,可以保存并在任何地方使用没有问题,独此一份。利用JavaVM中的 AttachCurrentThread函数,就可以得到这个线程的 JNIEnv结构体,利用用DetachCurrnetThread释放相应资源。
一般通过JNIEnv 操作jobject的jfieldID 操作成员变量和jmethodID 操作成员函数。这个再JNI中创建的每个资源都有自己的ID,在Java空间中通过找到这些ID,就可以找到相对应的成员变量和成员函数。
static jfieldID GetFieldID(JNIEnv* env, jclass jclazz,const char* name, const char* sig)
static jmethodID GetMethodID(JNIEnv* env, jclass jclazz, const char* name,const char* sig)
3.JNI命名规则
com_android_server_LightsService.cpp,表明这个服务是在com/android/server/下的LightsService.cpp文件,在注册的时候以com/android/server/LightsService作为参数传下去。
4.函数签名
因为JAVA支持函数重载,可以定义同名但不同参数的函数,但直接根据函数名是没法找到具体函数的,因此利用参数类型及返回类型组成签名信息。利用JNINativeMethod结构保存其关系。
typedef struct
{
//JAVA中native函数名字
const char *name;
//签名信息,用字符串表示,参数类型及返回值类型的组合
const char *signature;
///JNI层函数函数指针,转换为void*类型
void *fnPtr;
};
常用类型标识符:
类型标识 JAVA类型 字长
Z boolean 8位
B byte 8位
C char 16位 -- 注意哟
S short 16位
I int 32位
J long 64位
F float 32位
D double 64位
L/java/languageString String
[I int[] int数组
[L/java/lang/object Object[] 对象数组
在method_table中主要完成了JNI对HAL的封装函数。
5.垃圾回收
finalize_native
4.JNI其他功能
1.异常处理
常用的异常处理函数
Throw():丢弃一个现有的异常对象;在固有方法中用于重新丢弃一个异常。
ThrowNew():生成一个新的异常对象,并将其丢弃。
ExceptionOccurred():判断一个异常是否已被丢弃,但尚未清除。
ExceptionDescribe():打印一个异常和堆栈跟踪信息。
ExceptionClear():清除一个待决的异常。
FatalError():造成一个严重错误,不返回。
在所有这些函数中,最不能忽视的就是ExceptionOccurred()和ExceptionClear()。大多数JNI函数都能产生异常,而且没有象在Java的try块内的那种语言特性可供利用。所以在每一次JNI函数调用之后,都必须调用ExceptionOccurred(),了解异常是否已被丢弃。若侦测到一个异常,可选择对其加以控制(可能时还要重新丢弃它)。然而,必须确保异常最终被清除。这可以在自己的函数中用ExceptionClear()来实现;若异常被重新丢弃,也可能在其他某些函数中进行。