亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Android下如何通過JNI方法向上提供接口總結(jié)

系統(tǒng) 2127 0

參考文獻(xiàn):

http://blog.csdn.net/luoshengyang/article/details/6575988

http://www.androidmi.com/Androidkaifa/rumen/201005/633.html

1 什么是JNI

JNI是Java Native Interface的縮寫,即Java本地接口.從Java1.1開始,JNI標(biāo)準(zhǔn)成為Java平臺的一部分,它允許java代碼和用其它語言編寫的代碼進(jìn)行交互.JNI是本地編程接口,它使得在Java虛擬機(jī)(VM)內(nèi)部運(yùn)行的Java代碼能夠與用其他編程語言(如C,C++和匯編語言)的應(yīng)用程序和庫進(jìn)行交互操作.

在Android中提供的JNI的方式,讓Java程序可以調(diào)用C語言程序。Android中很多Java類都具有native接口,這些native接口就是同本地實(shí)現(xiàn),然后注冊到系統(tǒng)中的.

JNI在Android層次結(jié)構(gòu)中的作用如下圖所示:

Android下如何通過JNI方法向上提供接口總結(jié)

在Android中,主要的JNI代碼在以下的路徑中:

Android源碼根目錄/frameworks/base/core/jni/

這個(gè)路徑中的內(nèi)容將被編譯成庫libandroid_runtime.so,這就是一個(gè)普通的動態(tài)庫,被放置在目標(biāo)系統(tǒng)的/system/lib目錄中.

除此之外,Android還包含其他的JNI庫,例如,媒體部分的JNI目錄frameworks/base/media/jni/中,被編譯成庫libmedia_jni.so.

JNI中的各個(gè)文件實(shí)際上就是C++的普通文件,其命名一般和支持的Java類有對應(yīng)關(guān)系。這種關(guān)系是習(xí)慣上的寫法,而不是強(qiáng)制的。

在Android中實(shí)現(xiàn)的JNI庫,需要連接動態(tài)庫libnativehelper.so.

2 注冊JNI方法

在Android源碼根目錄/frameworks/base/services/jni/目錄下有一個(gè)onload.cpp文件,其內(nèi)容如下:

    /*
 * 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_BatteryService(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_UsbDeviceManager(JNIEnv* env);
int register_android_server_UsbHostManager(JNIEnv* env);
int register_android_server_VibratorService(JNIEnv* env);
int register_android_server_SystemServer(JNIEnv* env);
int register_android_server_location_GpsLocationProvider(JNIEnv* env);
int register_android_server_connectivity_Vpn(JNIEnv* env);
int register_android_server_HelloService(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_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_BatteryService(env);
    register_android_server_UsbDeviceManager(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_connectivity_Vpn(env);
    register_android_server_HelloService(env);

    return JNI_VERSION_1_4;
}

  

onload.cpp文件上部分為注冊函數(shù)的聲明,下部分為調(diào)用各種注冊函數(shù),而 這些注冊函數(shù)就是JNI方法的注冊函數(shù) ! 正有通過這些注冊函數(shù),上層才有可能調(diào)用注冊的JNI方法.

這些注冊函數(shù)是由同目錄下的其他.cpp文件中實(shí)現(xiàn),如上面的register_android_server_HelloService(env)這個(gè)函數(shù)是在com_android_service_HelloService.cpp文件中實(shí)現(xiàn)的.那么編譯器又是如何知道這點(diǎn)的呢? 答案當(dāng)然是Android.mk這個(gè)文件,打開這個(gè)文件,其內(nèi)容如下:

    LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
    com_android_server_AlarmManagerService.cpp \
    com_android_server_BatteryService.cpp \
    com_android_server_InputApplicationHandle.cpp \
    com_android_server_InputManager.cpp \
    com_android_server_InputWindowHandle.cpp \
    com_android_server_LightsService.cpp \
    com_android_server_PowerManagerService.cpp \
    com_android_server_SystemServer.cpp \
    com_android_server_UsbDeviceManager.cpp \
    com_android_server_UsbHostManager.cpp \
    com_android_server_VibratorService.cpp \
    com_android_server_location_GpsLocationProvider.cpp \
    com_android_server_connectivity_Vpn.cpp \
    com_android_server_HelloService.cpp \
    onload.cpp

LOCAL_C_INCLUDES += \
    $(JNI_H_INCLUDE) \
    frameworks/base/services \
    frameworks/base/core/jni \
    external/skia/include/core

LOCAL_SHARED_LIBRARIES := \
    libandroid_runtime \
    libcutils \
    libhardware \
    libhardware_legacy \
    libnativehelper \
    libsystem_server \
    libutils \
    libui \
    libinput \
    libskia \
    libgui \
    libusbhost

ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
    LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
endif

LOCAL_MODULE:= libandroid_servers

include $(BUILD_SHARED_LIBRARY)

  
在LOCAL_SRC_FILE中給出了所有實(shí)現(xiàn)文件(cpp文件)的路徑,因此編譯就能找到各個(gè)注冊函數(shù)對應(yīng)的實(shí)現(xiàn)文件了.

接下來讓我們來看看其中一個(gè)注冊函數(shù)的具體實(shí)現(xiàn)過程是如何的,比如:register_android_server_HelloService(env),打開com_android_service_HelloService.cpp文件,其下有注冊函數(shù)的實(shí)現(xiàn)代碼,如下:

    int register_android_server_HelloService(JNIEnv *env) {
    	return jniRegisterNativeMethods(env, "com/android/server/HelloService", method_table, NELEM(method_table));
}
  
其中jniRegisterNativeMethods為注冊JNI方法函數(shù),此函數(shù)在JNI方法使用中非常重要,此函數(shù)的第二個(gè)參數(shù)為對應(yīng)著java類即HelloService.java的文件名,第三個(gè)參數(shù)為注冊的方法表:

    /*JNI方法表*/
static const JNINativeMethod method_table[] = {
	{"init_native", "()Z", (void*)hello_init},
	{"setVal_native", "(I)V", (void*)hello_setVal},
	{"getVal_native", "()I", (void*)hello_getVal},
};
  
接下來就是方法表內(nèi)各個(gè)接口的實(shí)現(xiàn)代碼了.

如hello_setVal函數(shù)的實(shí)現(xiàn):

    /*通過硬件抽象層定義的硬件訪問接口設(shè)置硬件寄存器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);
}
  
方法列表中的hello_init的實(shí)現(xiàn)代碼中展現(xiàn)了如何調(diào)用下層HAL提供的接口, 還記得上一章: Android中HAL如何向上層提供接口總結(jié) 一文中描述HAL是如何向上層提供接口的嗎?這個(gè)hello_init函數(shù)的實(shí)現(xiàn)就是典型的調(diào)用HAL提供的初始化接口的例子,下面見hello_init這個(gè)函數(shù)的實(shí)現(xiàn)代碼:

    /*通過硬件抽象層定義的硬件模塊打開接口打開硬件設(shè)備*/
	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, jclass clazz) {
		hello_module_t* module;
		
		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.");
				return 0;
			}
			LOGE("Hello JNI: failed to open hello device.");
			return -1;
		}
		LOGE("Hello JNI: failed to get hello stub module.");
		return -1;		
	}
  
上述的module->methods->open這個(gè)open函數(shù)就是HAL提供的接口,其函數(shù)原型在hardware.h頭文件中有定義,只能返回struct hw_device_t類型的指針,而在JNI方法中,我們關(guān)心的是struct hello_device_t,只有通過struct hello_device_t,我們才能獲取其所有的成員函數(shù)(接HAL提供的接口函數(shù)),由于struct hello_device_t的第一個(gè)成員就是struct hw_device_t類型的數(shù)據(jù),因此在這里可以將獲取的struct hw_device_t強(qiáng)制轉(zhuǎn)化為struct hello_device_t來用。還沒有明白過來的,建議回過頭去看上一篇文章: Android中HAL如何向上層提供接口總結(jié) .

3 方法列表說明

關(guān)于static const JNINativeMethod method_table[]方法列表的原型如下:

    typedef struct {
const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;
  
Andoird 中使用了一種不同傳統(tǒng)Java JNI的方式來定義其native的函數(shù)。其中很重要的區(qū)別是Andorid使用了一種Java 和 C 函數(shù)的映射表數(shù)組,并在其中描述了函數(shù)的參數(shù)和返回值。這個(gè)數(shù)組的類型就是JNINativeMethod,見上述定義.

第一個(gè)變量name是Java中函數(shù)的名字。第二個(gè)變量signature,用字符串是描述了函數(shù)的參數(shù)和返回值.第三個(gè)變量fnPtr是函數(shù)指針,指向C函數(shù)。

其中比較難以理解的是第二個(gè)參數(shù),例如:

"()V"

"(II)V"

"(Ljava/lang/String;Ljava/lang/String;)V"

實(shí)際上這些字符是與函數(shù)的參數(shù)類型一一對應(yīng)的。

"()" 中的字符表示參數(shù),后面的則代表返回值。例如"()V" 就表示void Func();

"(II)V" 表示 void Func(int, int);


具體的每一個(gè)字符的對應(yīng)關(guān)系如下
字符 Java類型 C類型

V void void
Z jboolean boolean
I jint int
J jlong long
D jdouble double
F jfloat float
B jbyte byte
C jchar char
S jshort short


數(shù)組則以"["開始,用兩個(gè)字符表示


[I jintArray int[]
[F jfloatArray float[]
[B jbyteArray byte[]
[C jcharArray char[]
[S jshortArray short[]
[D jdoubleArray double[]
[J jlongArray long[]
[Z jbooleanArray boolean[]


上面的都是基本類型。如果Java函數(shù)的參數(shù)是class,則以"L"開頭,以";"結(jié)尾.中間是用"/" 隔開的包及類名。而其對應(yīng)的C函數(shù)名的參數(shù)則為jobject. 一個(gè)例外是String類,其對應(yīng)的類為jstring


Ljava/lang/String; String jstring
Ljava/net/Socket; Socket jobject


如果JAVA函數(shù)位于一個(gè)嵌入類,則用$作為類名間的分隔符。

例如 "(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z"




Android下如何通過JNI方法向上提供接口總結(jié)


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 欧美福利视频在线观看 | 亚洲国产精品欧美日韩一区二区 | 四虎国产精品永久在线播放 | 国产高清在线a视频大全凹凸 | 四虎在线永久 | 国产成人精品亚洲77美色 | 欧美成人猛男性色生活 | 免费福利在线视频 | 欧美中文字幕在线播放 | 欧美亚洲精品小说一区二三区 | 国人精品视频在线观看 | 亚洲狠狠狠一区二区三区 | 国产视频久 | 亚洲国产日韩综合久久精品 | 五月婷婷婷婷婷 | 精品国产欧美 | 亚洲三级在线免费观看 | 香蕉在线精品亚洲第一区 | 天天射天天爱天天干 | 国产精品国产福利国产秒拍 | 国产福利91精品一区二区三区 | 久草手机视频 | 亚洲国产精品一区二区第四页 | 精品久久久久久中文字幕一区 | 久久99热这里只有精品免费看 | 99爱视频 | 美女视频免费在线观看 | 一级毛片在线观看视频 | 中文一级国产特级毛片视频 | 亚洲精品一区二区三区四区 | 一级做性色a爱片久久片 | 亚洲一区二区三区福利在线 | 欧美精品一区二区精品久久 | 年级的后妈妈2中文翻译 | 精品在线免费观看视频 | 欧美一级午夜免费视频你懂的 | 亚洲高清在线观看播放 | www.色94色.com| 欧美一级毛片图 | 九色蝌蚪自拍 | 欧美一级特黄乱妇高清视频 |