首頁 收藏 QQ群
 網(wǎng)站導航

ZNDS智能電視網(wǎng) 推薦當貝市場

TV應用下載 / 資源分享區(qū)

軟件下載 | 游戲 | 討論 | 電視計算器

綜合交流 / 評測 / 活動區(qū)

交流區(qū) | 測硬件 | 網(wǎng)站活動 | Z幣中心

新手入門 / 進階 / 社區(qū)互助

新手 | 你問我答 | 免費刷機救磚 | ROM固件

查看: 18111|回復: 2
上一主題 下一主題
[教程]

在Ubuntu為Android硬件抽象層(HAL)模塊編寫JNI方法提供Java訪問

[復制鏈接]
跳轉到指定樓層
樓主
發(fā)表于 2013-8-28 16:30 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式 | 未知
在上兩篇文章中,我們介紹了如何為Android系統(tǒng)的硬件編寫驅動程序,包括如何在Linux內(nèi)核空間實現(xiàn)內(nèi)核驅動程序和在用戶空間實現(xiàn)硬件抽象層接口。實現(xiàn)這兩者的目的是為了向更上一層提供硬件訪問接口,即為Android的Application Frameworks層提供硬件服務。我們知道,Android系統(tǒng)的應用程序是用Java語言編寫的,而硬件驅動程序是用C語言來實現(xiàn)的,那么,Java接口如何去訪問C接口呢?眾所周知,Java提供了JNI方法調(diào)用,同樣,在Android系統(tǒng)中,Java應用程序通過JNI來調(diào)用硬件抽象層接口。在這一篇文章中,我們將介紹如何為Android硬件抽象層接口編寫JNI方法,以便使得上層的Java應用程序能夠使用下層提供的硬件服務。   
   
      一. 參照在Ubuntu上為Android增加硬件抽象層(HAL)模塊訪問Linux內(nèi)核驅動程序一文,準備好硬件抽象層模塊,確保Android系統(tǒng)鏡像文件system.img已經(jīng)包含hello.default模塊。   
   
      二. 進入到frameworks/base/services/jni目錄,新建com_android_server_HelloService.cpp文件:   
   
      USER-NAME@MACHINE-NAME:~/Android$ cd frameworks/base/services/jni   
   
      USER-NAME@MACHINE-NAME:~/Android/frameworks/base/services/jni$ vi com_android_server_HelloService.cpp   
   
      在com_android_server_HelloService.cpp文件中,實現(xiàn)JNI方法。注意文件的命令方法,com_android_server前綴表示的是包名,表示硬件服務HelloService是放在frameworks/base/services/java目錄下的com/android/server目錄的,即存在一個命令為com.android.server.HelloService的類。這里,我們暫時略去HelloService類的描述,在下一篇文章中,我們將回到HelloService類來。簡單地說,HelloService是一個提供Java接口的硬件訪問服務類。   
   
      首先是包含相應的頭文件:   
  1. #define LOG_TAG "HelloService"   
    #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/hello.h>   
    #include <stdio.h>
復制代碼
接著定義hello_init、hello_getVal和hello_setVal三個JNI方法:   
  1. namespace android   
    {   
            /*在硬件抽象層中定義的硬件訪問結構體,參考<hardware/hello.h>*/   
            struct hello_device_t* hello_device = NULL;   
            /*通過硬件抽象層定義的硬件訪問接口設置硬件寄存器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);   
            }   
            /*通過硬件抽象層定義的硬件訪問接口讀取硬件寄存器val的值*/   
            static jint hello_getVal(JNIEnv* env, jobject clazz) {   
                    int val = 0;   
                    if(!hello_device) {   
                            LOGI("Hello JNI: device is not open.");   
                            return val;   
                    }   
                    hello_device->get_val(hello_device, &val);   
                      
                    LOGI("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);   
            }   
            /*通過硬件模塊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;                  
            }   
            /*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},   
            };   
            /*注冊JNI方法*/   
            int register_android_server_HelloService(JNIEnv *env) {   
                        return jniRegisterNativeMethods(env, "com/android/server/HelloService", method_table, NELEM(method_table));   
            }   
    };
復制代碼
注意,在hello_init函數(shù)中,通過Android硬件抽象層提供的hw_get_module方法來加載模塊ID為HELLO_HARDWARE_MODULE_ID的硬件抽象層模塊,其中,HELLO_HARDWARE_MODULE_ID是在<hardware/hello.h>中定義的。Android硬件抽象層會根據(jù)HELLO_HARDWARE_MODULE_ID的值在Android系統(tǒng)的/system/lib/hw目錄中找到相應的模塊,然后加載起來,并且返回hw_module_t接口給調(diào)用者使用。在jniRegisterNativeMethods函數(shù)中,第二個參數(shù)的值必須對應HelloService所在的包的路徑,即com.android.server.HelloService。   
   
      三. 修改同目錄下的onload.cpp文件,首先在namespace android增加register_android_server_HelloService函數(shù)聲明:   
   
      namespace android {   
   
      ..............................................................................................   
   
      int register_android_server_HelloService(JNIEnv *env);   
   
      };   
   
      在JNI_onLoad增加register_android_server_HelloService函數(shù)調(diào)用:   
      extern "C" jint JNI_onLoad(JavaVM* vm, void* reserved)   
      {   
       .................................................................................................   
       register_android_server_HelloService(env);   
       .................................................................................................   
      }   
      這樣,在Android系統(tǒng)初始化時,就會自動加載該JNI方法調(diào)用表。   
      四. 修改同目錄下的Android.mk文件,在LOCAL_SRC_FILES變量中增加一行:   
      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 /   
      com_android_server_HelloService.cpp /   
      onload.cpp   
      五. 編譯和重新找億system.img:   
      USER-NAME@MACHINE-NAME:~/Android$ mmm frameworks/base/services/jni   
      USER-NAME@MACHINE-NAME:~/Android$ make snod   
      這樣,重新打包的system.img鏡像文件就包含我們剛才編寫的JNI方法了,也就是我們可以通過Android系統(tǒng)的Application Frameworks層提供的硬件服務HelloService來調(diào)用這些JNI方法,進而調(diào)用低層的硬件抽象層接口去訪問硬件了。前面提到,在這篇文章中,我們暫時忽略了HelloService類的實現(xiàn),在下一篇文章中,我們將描述如何實現(xiàn)硬件服務HelloService,敬請關注

上一篇:在Ubuntu上為Android系統(tǒng)的Application Frameworks層增加硬件訪問服務
下一篇:Android硬件抽象層(HAL)概要介紹和學習計劃
沙發(fā)
發(fā)表于 2014-1-6 14:26 | 只看該作者 | 來自河北
強烈支持樓主ing……
回復 支持 反對

使用道具 舉報

板凳
發(fā)表于 2016-3-10 19:46 | 只看該作者 | 來自山東
很給力,ZNDS有你更精彩!
回復 支持 反對

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

Archiver|新帖|標簽|軟件|Sitemap|ZNDS智能電視網(wǎng) ( 蘇ICP備2023012627號 )

網(wǎng)絡信息服務信用承諾書 | 增值電信業(yè)務經(jīng)營許可證:蘇B2-20221768 丨 蘇公網(wǎng)安備 32011402011373號

GMT+8, 2024-12-28 03:48 , Processed in 0.062405 second(s), 15 queries , Redis On.

Powered by Discuz!

監(jiān)督舉報:report#znds.com (請將#替換為@)

© 2007-2024 ZNDS.Com

快速回復 返回頂部 返回列表