歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Android下如何通過JNI方法向上提供接口總結

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

日期:2017/3/1 10:41:20   编辑:Linux編程

1 什麼是JNI

JNI是Java Native Interface的縮寫,即Java本地接口.從Java1.1開始,JNI標准成為Java平台的一部分,它允許java代碼和用其它語言編寫的代碼進行交互.JNI是本地編程接口,它使得在Java虛擬機(VM)內部運行的Java代碼能夠與用其他編程語言(如C,C++和匯編語言)的應用程序和庫進行交互操作.

在Android中提供的JNI的方式,讓Java程序可以調用C語言程序。Android中很多Java類都具有native接口,這些native接口就是同本地實現,然後注冊到系統中的.

JNI在Android層次結構中的作用如下圖所示:


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

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

這個路徑中的內容將被編譯成庫libandroid_runtime.so,這就是一個普通的動態庫,被放置在目標系統的/system/lib目錄中.

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

JNI中的各個文件實際上就是C++的普通文件,其命名一般和支持的Java類有對應關系。這種關系是習慣上的寫法,而不是強制的。

在Android中實現的JNI庫,需要連接動態庫libnativehelper.so.

2 注冊JNI方法

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

  1. /*
  2. * Copyright (C) 2009 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "JNIHelp.h"
  17. #include "jni.h"
  18. #include "utils/Log.h"
  19. #include "utils/misc.h"
  20. namespace android {
  21. int register_android_server_AlarmManagerService(JNIEnv* env);
  22. int register_android_server_BatteryService(JNIEnv* env);
  23. int register_android_server_InputApplicationHandle(JNIEnv* env);
  24. int register_android_server_InputWindowHandle(JNIEnv* env);
  25. int register_android_server_InputManager(JNIEnv* env);
  26. int register_android_server_LightsService(JNIEnv* env);
  27. int register_android_server_PowerManagerService(JNIEnv* env);
  28. int register_android_server_UsbDeviceManager(JNIEnv* env);
  29. int register_android_server_UsbHostManager(JNIEnv* env);
  30. int register_android_server_VibratorService(JNIEnv* env);
  31. int register_android_server_SystemServer(JNIEnv* env);
  32. int register_android_server_location_GpsLocationProvider(JNIEnv* env);
  33. int register_android_server_connectivity_Vpn(JNIEnv* env);
  34. int register_android_server_HelloService(JNIEnv *env);
  35. };
  36. using namespace android;
  37. extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
  38. {
  39. JNIEnv* env = NULL;
  40. jint result = -1;
  41. if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
  42. LOGE("GetEnv failed!");
  43. return result;
  44. }
  45. LOG_ASSERT(env, "Could not retrieve the env!");
  46. register_android_server_PowerManagerService(env);
  47. register_android_server_InputApplicationHandle(env);
  48. register_android_server_InputWindowHandle(env);
  49. register_android_server_InputManager(env);
  50. register_android_server_LightsService(env);
  51. register_android_server_AlarmManagerService(env);
  52. register_android_server_BatteryService(env);
  53. register_android_server_UsbDeviceManager(env);
  54. register_android_server_UsbHostManager(env);
  55. register_android_server_VibratorService(env);
  56. register_android_server_SystemServer(env);
  57. register_android_server_location_GpsLocationProvider(env);
  58. register_android_server_connectivity_Vpn(env);
  59. register_android_server_HelloService(env);
  60. return JNI_VERSION_1_4;
  61. }
onload.cpp文件上部分為注冊函數的聲明,下部分為調用各種注冊函數,而這些注冊函數就是JNI方法的注冊函數! 正有通過這些注冊函數,上層才有可能調用注冊的JNI方法.

這些注冊函數是由同目錄下的其他.cpp文件中實現,如上面的register_android_server_HelloService(env)這個函數是在com_android_service_HelloService.cpp文件中實現的.那麼編譯器又是如何知道這點的呢? 答案當然是Android.mk這個文件,打開這個文件,其內容如下:

  1. LOCAL_PATH:= $(call my-dir)
  2. include $(CLEAR_VARS)
  3. LOCAL_SRC_FILES:= \
  4. com_android_server_AlarmManagerService.cpp \
  5. com_android_server_BatteryService.cpp \
  6. com_android_server_InputApplicationHandle.cpp \
  7. com_android_server_InputManager.cpp \
  8. com_android_server_InputWindowHandle.cpp \
  9. com_android_server_LightsService.cpp \
  10. com_android_server_PowerManagerService.cpp \
  11. com_android_server_SystemServer.cpp \
  12. com_android_server_UsbDeviceManager.cpp \
  13. com_android_server_UsbHostManager.cpp \
  14. com_android_server_VibratorService.cpp \
  15. com_android_server_location_GpsLocationProvider.cpp \
  16. com_android_server_connectivity_Vpn.cpp \
  17. com_android_server_HelloService.cpp \
  18. onload.cpp
  19. LOCAL_C_INCLUDES += \
  20. $(JNI_H_INCLUDE) \
  21. frameworks/base/services \
  22. frameworks/base/core/jni \
  23. external/skia/include/core
  24. LOCAL_SHARED_LIBRARIES := \
  25. libandroid_runtime \
  26. libcutils \
  27. libhardware \
  28. libhardware_legacy \
  29. libnativehelper \
  30. libsystem_server \
  31. libutils \
  32. libui \
  33. libinput \
  34. libskia \
  35. libgui \
  36. libusbhost
  37. ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
  38. LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
  39. endif
  40. LOCAL_MODULE:= libandroid_servers
  41. include $(BUILD_SHARED_LIBRARY)
在LOCAL_SRC_FILE中給出了所有實現文件(cpp文件)的路徑,因此編譯就能找到各個注冊函數對應的實現文件了.

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

  1. int register_android_server_HelloService(JNIEnv *env) {
  2. return jniRegisterNativeMethods(env, "com/android/server/HelloService", method_table, NELEM(method_table));
  3. }
其中jniRegisterNativeMethods為注冊JNI方法函數,此函數在JNI方法使用中非常重要,此函數的第二個參數為對應著java類即HelloService.java的文件名,第三個參數為注冊的方法表:
  1. /*JNI方法表*/
  2. static const JNINativeMethod method_table[] = {
  3. {"init_native", "()Z", (void*)hello_init},
  4. {"setVal_native", "(I)V", (void*)hello_setVal},
  5. {"getVal_native", "()I", (void*)hello_getVal},
  6. };
Copyright © Linux教程網 All Rights Reserved