程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> JNI對HAL的封裝

JNI對HAL的封裝

編輯:C++入門知識

文件位置: frameworks\base\services\jni 動態注冊文件:onload.cpp [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中注冊相關的服務 將注冊文件編譯進內核 [cpp]  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) [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()來實現;若異常被重新丟棄,也可能在其他某些函數中進行。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved