Android平台讀寫i2c裝置開發筆記二

來源:互聯網
上載者:User

二、 使用JNI在應用程式架構層添加服務提供者

       APP應用不能直接存取HAL層,需要JNI層訪問HAL模組並向上提供API介面。可以直接提供介面,但建議最好使用服務的方式提供訪問。

       我們先看JNI如何訪問剛才的HAL模組。

       進入源碼根目錄下的frameworks/base/service/jni目錄,建立com_android_server_IICService.cpp,代碼如下:

#include "jni.h"  #include "JNIHelp.h"  #include "android_runtime/AndroidRuntime.h"  #include <utils/misc.h>  #include <cutils/log.h>  #include <hardware/hardware.h>  #include <hardware/iic.h>  #include <stdio.h>namespace android  {      /*在硬體抽象層中定義的硬體訪問結構體,參考<hardware/iic.h>*/          struct iic_device_t* iic_device = NULL;      /*通過硬體抽象層定義的硬體提供者設定硬體寄存器val的值*/      static void iic_setVal(JNIEnv* env, jobject clazz, jstring val, jint slaveAddr, jint subAddr, jint len) {          const char *str = env->GetStringUTFChars(val, NULL);          LOGI("iic JNI: set value %s to device.", str);          if(!iic_device) {              LOGI("iic JNI: device is not open.");              return;          }          iic_device->iic_write(iic_device, (unsigned char*)str, slaveAddr, subAddr, len);  env->ReleaseStringUTFChars(val, str);  //注意釋放資源    }         /*通過硬體抽象層定義的硬體提供者讀取硬體寄存器val的值*/      static jstring iic_getVal(JNIEnv* env, jobject clazz, jint slaveAddr, jint len) {unsigned char* data = (unsigned char*)malloc(len);iic_device->iic_read(iic_device, data, slaveAddr, len);        if(!iic_device) {              LOGI("iic JNI: device is not open.");          }int i = 0;for(;i<strlen((const char*)data);i++){  LOGI("data: %c ", data[i]);}          //LOGI("iic JNI: get value %s from device @ %x address!", data, subAddr);jstring tmp = env->NewStringUTF((const char*)data);free(data);data = NULL;return tmp;       }           /*通過硬體抽象層定義的硬體模組open介面開啟硬體裝置*/      static inline int iic_device_open(const hw_module_t* module, struct iic_device_t** device) {          return module->methods->open(module, IIC_HARDWARE_MODULE_ID, (struct hw_device_t**)device);      }          /*通過硬體模組ID來載入指定的硬體抽象層模組並開啟硬體*/      static jboolean iic_init(JNIEnv* env, jclass clazz) {          iic_module_t* module;                    LOGI("iic JNI: initializing......");          if(hw_get_module(IIC_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) {              LOGI("iic JNI: iic Stub found.");              if(iic_device_open(&(module->common), &iic_device) == 0) {                  LOGI("eeprom JNI: iic device is opening...");                  return 0;              }              LOGE("eeprom JNI: failed to open iic device.");              return -1;          }          LOGE("eeprom JNI: failed to get iic stub module.");          return -1;            }          /*JNI方法表*/      static const JNINativeMethod method_table[] = {          {"init_native", "()Z", (void*)iic_init},          {"setVal_native", "(Ljava/lang/String;III)V", (void*)iic_setVal},          {"getVal_native", "(III)Ljava/lang/String;", (void*)iic_getVal},      };          /*註冊JNI方法*/      int register_android_server_IICService(JNIEnv *env) {              return jniRegisterNativeMethods(env, "com/android/server/IICService", method_table, NELEM(method_table));      }  };

然後需要讓android啟動時載入此jni模組

在同目錄下修改onload.cpp:

在namespace android中添加一行    int register_android_server_IICService(JNIEnv *env);

在JNI_onLoad方法中添加一行  register_android_server_IICService(env);

在同目錄下修改Android.mk:

LOCAL_SRC_FILES增加一行   com_android_server_IICService \

編譯命令:mmm frameworks/base/services/jni

注意: HAL是根據iic_init中的IIC_HARDWARE_MODULE_ID載入相應模組。

然後,使用AIDL進行處理序間通訊,使APP能訪問自訂的硬體服務。

我們需要在frameworks/base/core/java/android/os中建立IIICService.aidl(注意是III)

package android.os;  
interface IIICService {  
    void setVal(String val, int slaveAddr, int regAddr, int len);  
    String getVal(int slaveAddr, int len);  

它定義了服務的介面,介面在IICService中實現並關聯到jni本地方法中。

同時我們需要修改frameworkd/base下的Android.mk編譯檔案,在LOCAL_SRC_FILES中增加 core/java/android/os/IIICService.aidl

編譯命令: mmm frameworks/base

下面是AIDL的實現方法類:com.android.server.IICService 位置為:frameworks/base/services/java/com/android/server 代碼如下:

package com.android.server;  import android.content.Context;  import android.os.IIICService;  import android.util.Slog;  public class IICService extends IIICService.Stub {      private static final String TAG = "IICService";      IICService() {          init_native();      }      public void setVal(String val,int slaveAddr, int regAddr, int len) {          setVal_native(val, slaveAddr, regAddr, len);      }         public String getVal(int slaveAddr,int len) {          return getVal_native( slaveAddr, len);      }           //本地方法     private static native boolean init_native();      private static native void setVal_native(String val, int slaveAddr, int regAddr, int len);      private static native String getVal_native(int slaveAddr, int len);  }; 

從代碼中我們可以看到它繼承了IIICService.Stub,實現兩個介面方法。因為硬體訪問一般需要放在一個獨立的線程中,這裡使用了代理的方法來處理app與硬體服務的通訊。

最後需要把新增的IICService服務加入到ServiceManager中,這樣就可以通過ServiceManager進行調用。

修改frameworks/base/services/java/com/android/server下的SystemServer.java
 在run()方法中添加

try{

    Slog.i(TAG, "IIC SERVICE");

    ServiceManager.addService("iic", new IICService());

}catch(Throwable e){

    Slog.e(TAG, "Failure starting IIC Service", e);

}
編譯命令:mmm frameworks/base/services/java

或者使用另一種形式來調用服務:如同使用binder機制綁定service一樣的方法, 具體就不詳細寫了。 


注意:有可能會編譯不通過,因為這裡修改了android的官方api, 需要運行make update-api更新frameworks/base/api/current.xml

打包後,app就可以使用IICService介面來訪問硬體了。
下一節發上app相關代碼

(待續)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.