一、直通式HAL
這里使用一個案例來介紹直通式HAL,選擇MTK的NFC HIDL 1.0為例,因為比較簡單,代碼量也比較小,其源碼路徑:vendor/hardware/interfaces/nfc/1.0/
1、NFC HAL的定義
1)NFC HAL數據類型
通常定義在types.hal里面,其語法和java/c/c++可能不一致,詳細參考https://source.android.com/docs/core/architecture/hidl/types?hl=zh-cn
2)NFC HAL回調接口
HAL的回調接口,即通常被定義為IXXXCallback
INfcClientCallback從命名可以知道給客戶端的回調接口,即給客戶端進程或者framework層提供的回調接口,即hal可以通過該接口向對方回調數據
3)NFC HAL接口定義
HAL的正式接口,同前面的回調接口剛好相反,即
HAL接口:客戶端/Framework ------->? HAL進程(HAL進程是被調用者)
CALL接口:HAL進程? ------>客戶端/Framework (HAL進程主動發起)
2、NFC HAL的邏輯
NFC HAL 1.0的版本是一個典型的直通式,其源碼就nfc.cpp,邏輯相對比較簡單
//vendor/hardware/interfaces/nfc/1.0/default/Nfc.h
#ifndef ANDROID_HARDWARE_NFC_V1_0_NFC_H
#define ANDROID_HARDWARE_NFC_V1_0_NFC_H#include <android/hardware/nfc/1.0/INfc.h>
#include <hidl/Status.h>
#include <hardware/hardware.h>
#include <hardware/nfc.h>
namespace android {
namespace hardware {
namespace nfc {
namespace V1_0 {
namespace implementation {using ::android::hardware::nfc::V1_0::INfc;
using ::android::hardware::nfc::V1_0::INfcClientCallback;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::hidl_vec;
using ::android::hardware::hidl_string;
using ::android::sp;struct Nfc : public INfc, public hidl_death_recipient {Nfc(nfc_nci_device_t* device);::android::hardware::Return<NfcStatus> open(const sp<INfcClientCallback>& clientCallback) override;::android::hardware::Return<uint32_t> write(const hidl_vec<uint8_t>& data) override;::android::hardware::Return<NfcStatus> coreInitialized(const hidl_vec<uint8_t>& data) override;::android::hardware::Return<NfcStatus> prediscover() override;::android::hardware::Return<NfcStatus> close() override;::android::hardware::Return<NfcStatus> controlGranted() override;::android::hardware::Return<NfcStatus> powerCycle() override;static void eventCallback(uint8_t event, uint8_t status) {if (mCallback != nullptr) {auto ret = mCallback->sendEvent((::android::hardware::nfc::V1_0::NfcEvent)event,(::android::hardware::nfc::V1_0::NfcStatus)status);if (!ret.isOk()) {ALOGW("Failed to call back into NFC process.");}}}static void dataCallback(uint16_t data_len, uint8_t* p_data) {hidl_vec<uint8_t> data;data.setToExternal(p_data, data_len);if (mCallback != nullptr) {auto ret = mCallback->sendData(data);if (!ret.isOk()) {ALOGW("Failed to call back into NFC process.");}}}virtual void serviceDied(uint64_t /*cookie*/,const wp<::android::hidl::base::V1_0::IBase>& /*who*/) {close();}private:static sp<INfcClientCallback> mCallback;const nfc_nci_device_t* mDevice;
};extern "C" INfc* HIDL_FETCH_INfc(const char* name);} // namespace implementation
} // namespace V1_0
} // namespace nfc
} // namespace hardware
} // namespace android#endif // ANDROID_HARDWARE_NFC_V1_0_NFC_H//vendor/hardware/interfaces/nfc/1.0/default/Nfc.cpp
#define LOG_TAG "android.hardware.nfc@1.0-impl"#include <log/log.h>#include <hardware/hardware.h>
#include <hardware/nfc.h>
#include "Nfc.h"namespace android {
namespace hardware {
namespace nfc {
namespace V1_0 {
namespace implementation {sp<INfcClientCallback> Nfc::mCallback = nullptr;Nfc::Nfc(nfc_nci_device_t* device) : mDevice(device) {}// Methods from ::android::hardware::nfc::V1_0::INfc follow.
::android::hardware::Return<NfcStatus> Nfc::open(const sp<INfcClientCallback>& clientCallback) {mCallback = clientCallback;if (mDevice == nullptr || mCallback == nullptr) {return NfcStatus::FAILED;}mCallback->linkToDeath(this, 0 /*cookie*/);int ret = mDevice->open(mDevice, eventCallback, dataCallback);return ret == 0 ? NfcStatus::OK : NfcStatus::FAILED;
}::android::hardware::Return<uint32_t> Nfc::write(const hidl_vec<uint8_t>& data) {if (mDevice == nullptr) {return -1;}return mDevice->write(mDevice, data.size(), &data[0]);
}::android::hardware::Return<NfcStatus> Nfc::coreInitialized(const hidl_vec<uint8_t>& data) {hidl_vec<uint8_t> copy = data;if (mDevice == nullptr || copy.size() == 0) {return NfcStatus::FAILED;}int ret = mDevice->core_initialized(mDevice, ©[0]);return ret == 0 ? NfcStatus::OK : NfcStatus::FAILED;
}::android::hardware::Return<NfcStatus> Nfc::prediscover() {if (mDevice == nullptr) {return NfcStatus::FAILED;}return mDevice->pre_discover(mDevice) ? NfcStatus::FAILED : NfcStatus::OK;
}::android::hardware::Return<NfcStatus> Nfc::close() {if (mDevice == nullptr || mCallback == nullptr) {return NfcStatus::FAILED;}mCallback->unlinkToDeath(this);return mDevice->close(mDevice) ? NfcStatus::FAILED : NfcStatus::OK;
}::android::hardware::Return<NfcStatus> Nfc::controlGranted() {if (mDevice == nullptr) {return NfcStatus::FAILED;}return mDevice->control_granted(mDevice) ? NfcStatus::FAILED : NfcStatus::OK;
}::android::hardware::Return<NfcStatus> Nfc::powerCycle() {if (mDevice == nullptr) {return NfcStatus::FAILED;}return mDevice->power_cycle(mDevice) ? NfcStatus::FAILED : NfcStatus::OK;
}INfc* HIDL_FETCH_INfc(const char * /*name*/) {nfc_nci_device_t* nfc_device;int ret = 0;const hw_module_t* hw_module = nullptr;ret = hw_get_module (NFC_NCI_HARDWARE_MODULE_ID, &hw_module);if (ret == 0) {ret = nfc_nci_open (hw_module, &nfc_device);if (ret != 0) {ALOGE ("nfc_nci_open failed: %d", ret);}}elseALOGE ("hw_get_module %s failed: %d", NFC_NCI_HARDWARE_MODULE_ID, ret);if (ret == 0) {return new Nfc(nfc_device);} else {ALOGE("Passthrough failed to load legacy HAL.");return nullptr;}
}} // namespace implementation
} // namespace V1_0
} // namespace nfc
} // namespace hardware
} // namespace android
1)如何集成了驅動?
首先在nfc.h定義了很關鍵的成員變量mDevice,熟悉C/C++代碼的從命名來看應該是一個驅動關聯的句柄:
?const nfc_nci_device_t*?????? mDevice;
在nfc.cpp代碼中可以很明顯的看到通過linux和hal的機制去打開nfc驅動設備節點:
因此有理由相信這里的mDevice其實就是nfc驅動設備節點的一個句柄,所以解析來的代碼邏輯其實就是對nfc驅動設備節點的文件操作了。
2)客戶端如何通過hal調用驅動?
對驅動設備節點的第一個操作就是open,在open之后我們就可以對設備節點進行write或者其他操作,如下幾個函數,都是NFC HAL接口的定義,因此HAL進程這里都是作為被動調用的一方,最后通過mDevice->XXX的方式調用驅動代碼,驅動代碼實現具體功能。
3)驅動階段如何主動返回數據?
那么如果驅動程序想主動返回數據給到客戶端,或者給到系統framework層,那么如何操作呢?
這時需要在看看open函數:
我們來看看函數指針eventCallback和dataCallback如何實現?