1. 程式人生 > >Android HAL介面實現

Android HAL介面實現

總體結構

如果要實現一個HAL對應native層的介面,必須要明確一下整個結構。
HAL層的程式碼將會被封裝成一個硬體模組,比如sensor.xxx.so的so庫,該模組會通過kernel註冊,然後在native程式碼層次呼叫該系統模組,使用其中的函式,類等等。
native層的實現可以有很多的用途,比如寫成java的JNI實現,或則是編譯成so庫供其他的native層程式碼使用。

流程圖

HAL層實現

HAL函式實現

自己比較熟悉的是Sensor感測器模組,就以這個模組為例。
首先,在libhardware/sensor.h檔案中新增想要新增的功能函式的介面。

    int
(*get_val)(struct sensors_poll_device_t *dev,float* data);

然後在HAL層添加註冊硬體模組的程式碼

struct sensors_module_t HAL_MODULE_INFO_SYM = {
        common: {
                tag: HARDWARE_MODULE_TAG,
                version_major: 1,
                version_minor: 0,
                id: SENSORS_HARDWARE_MODULE_ID,
                name: "XXX module"
, author: "XXX", methods: &sensors_module_methods, dso: NULL, reserved: {0} }, get_sensors_list: sensors__get_sensors_list, };

其中tag: HARDWARE_MODULE_TAG是固定的寫法,這樣寫才能被kernel註冊模組時所識別。

之後在HAL新增具體的函式實現

int sensors_poll_context_t::get_val(float
* data){ LOGD("get_val into in HAL......"); int i; //返回了0-15共16個數字做示例 for(i=0;i<16;i++) { data[i]=i; } return 0; }

編譯HAL程式碼成so庫

編譯的話就需要用到Android.mk檔案了,語法不在細講,需要根據自己的需求去更改。我的示例程式碼中,會生成一個snesors.xxx.so的庫檔案,這個so檔案放至Android機器的system/lib/hw的資料夾下,就可以被使用了。

Native層實現

Native程式碼實現

可以新建 xxSensor.cpp和xxSensor.h檔案,在cpp檔案中實現module的開啟。

 status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID,
            (hw_module_t const**)&mSensorModule);

然後呼叫模組中的open函式開啟sensor硬體(開啟實際上就是傳回了一個類,該類實現了HAL層的函式功能等等)

err = sensors_open_1(&mSensorModule->common, &mSensorDevice);

之後直接呼叫mSensorDevice->get_val()就能使用該函數了。
當然,在native層,我們還是封裝一下這個呼叫比較好.

status_t SensorDevice::get_val(float* data){
    if (!mSensorDevice) return NO_INIT;

    int temp= mSensorDevice->get_val(reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice),data);

    ALOGD("SensorDevice get_val");
    return temp;
}

JAVA介面JNI的實現

封裝成so庫供其他的native層程式碼呼叫

在native層可以自己新建一個cpp和h檔案,在裡面直接使用SensorDevice的函式比如

int mySensor::get_val(float data[16]){

      android::SensorDevice& dev(android::SensorDevice::getInstance());

      ALOGD("mySensor get_val");

      return dev.get_val(data);
  }

如果想要封裝成直接可以用dlopen開啟的so庫的話,可以新增一個extern"c"將函式開一個介面

extern "C"{

  int n_get_val(float data[16])
  {
      return mySensor.get_val(data);
  }
  }

最後在mk檔案中將自己寫的程式碼編譯成so庫

include $(CLEAR_VARS)
LOCAL_SRC_FILES:=\
    mySensor.cpp \
    SensorDevice.cpp
LOCAL_SHARED_LIBRARIES := \
        libcutils \
        libhardware \
        libhardware_legacy \
        libutils \
        liblog \
        libbinder \
        libui \
        libgui \
        libsensorservice
LOCAL_MODULE:=mysensor
include $(BUILD_SHARED_LIBRARY)

其中SRC_FILE要包含自己的cpp檔案和引用的cpp檔案,SHARED_LIBRARIES檔案則包含應用的所有庫。
編譯生成mysensor.so檔案,最後將mysensor.so和mysensor.h給其他人就可以直接在native層使用了。