Android GPS學習筆記—HAL實現
HAL的全稱是Hardware Abstraction Layer, 即硬體抽象層。
HAL層是介於Android核心與上層之間抽象出來的一層結構,它是對linux驅動的一個封裝,對上層提供統一介面,上層應用不必知道下層是如何實現的,它遮蔽了底層的實現細節。
1. HAL的由來
Android的HAL是為了保護一些硬體提供商的智慧財產權而提出的,是為了避開linux的GPL束縛。思路是把控制硬體的動作都放到了Android HAL中,而linux driver僅僅完成一些簡單的資料互動作用,甚至把硬體暫存器空間直接對映到user space。而Android是基於Aparch的license,因此硬體廠商可以只提供二進位制程式碼,所以說Android只是一個開放的平臺,並不是一個開源的平臺。也許也正是因為Android不遵從GPL,所以Greg Kroah-Hartman才在2.6.33核心將Andorid驅動從linux中刪除。GPL和硬體廠商目前還是有著無法彌合的裂痕。Android想要把這個問題處理好也是不容易的。
總結下來,Android HAL存在的原因主要有:
(1). 並不是所有的硬體裝置都有標準的linux kernel的介面
(2). KERNEL DRIVER涉及到GPL的版權。某些裝置製造商並不願意公開硬體驅動,所以才去用HAL方式繞過GPL。
(3). 針對某些硬體,An有一些特殊的需求
2. HAL的演進
HAL以前是以module來被呼叫的。所謂module,就是將c檔案編譯成so檔案,然後在jni中載入呼叫。此種方式現在在原始碼的libhardware_legacy資料夾下。後來HAL的架構改變,變成了以stub的形式來被上層呼叫。這樣就有種面向物件的思想了。雖然也是編譯成so檔案然後載入,但是JNI是直接呼叫c物件。這種層次更清晰,而且更易於維護和擴充套件。
3. 原始碼目錄
hardware/libhardware/include/hardware/gps.h
hardware/qcom/gps/loc_api/gps.c
其中gps.h中定義了GPS相關的結構體介面,在“重要結構體及介面”中已經介紹,在此不再贅述。
我們來看一下gps.c檔案:
首先定義了gps裝置模組例項,下面的註釋很重要,說明了如何構建一個模組,這是Android中標準的構建模組寫法。
/** * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM * and the fields of this data structure must begin with hw_module_t * followed by module specific information. */ struct hw_module_t HAL_MODULE_INFO_SYM = { .tag = HARDWARE_MODULE_TAG, .module_api_version = 1, .hal_api_version = 0, .id = GPS_HARDWARE_MODULE_ID, .name = "loc_api GPS Module", .author = "Qualcomm USA, Inc.", .methods = &gps_module_methods, };
這裡的id用來指定模組庫檔名的,methods指向gps.c檔案中的gps_module_methods:
static struct hw_module_methods_t gps_module_methods = {
.open = open_gps
};
gps_module_methods定義了裝置的open函式為open_gps,我們來看open_gps函式:
static int open_gps(const struct hw_module_t* module, char const* name,
struct hw_device_t** device)
{
struct gps_device_t *dev = (struct gps_device_t *) malloc(sizeof(struct gps_device_t));
if(dev == NULL)
return -1;
memset(dev, 0, sizeof(*dev));
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = 0;
dev->common.module = (struct hw_module_t*)module;
dev->get_gps_interface = gps__get_gps_interface;
*device = (struct hw_device_t*)dev;
return 0;
}
此處可以看作是GPS裝置的初始化函式,在使用裝置前必須執行此函式。函式裡面指定了hw_device_t的module成員,以及gps_device_t的get_gps_interface成員。上層可通過gps_device_t的get_gps_interface呼叫gps__get_gps_interface函式。gps__get_gps_interface的定義如下:
const GpsInterface* gps__get_gps_interface(struct gps_device_t* dev)
{
return get_gps_interface();
}
get_gps_interface的實現是在gps/loc_api/Loc.cpp:
// for gps.c
extern "C" const GpsInterface* get_gps_interface()
{
unsigned int target = TARGET_DEFAULT;
loc_eng_read_config();
target = loc_get_target();
LOC_LOGD("Target name check returned %s", loc_get_target_name(target));
int gnssType = getTargetGnssType(target);
switch (gnssType)
{
case GNSS_GSS:
//APQ8064
gps_conf.CAPABILITIES &= ~(GPS_CAPABILITY_MSA | GPS_CAPABILITY_MSB);
gss_fd = open("/dev/gss", O_RDONLY);
if (gss_fd < 0) {
LOC_LOGE("GSS open failed: %s\n", strerror(errno));
}
else {
LOC_LOGD("GSS open success! CAPABILITIES %0lx\n",
gps_conf.CAPABILITIES);
}
break;
case GNSS_NONE:
//MPQ8064
LOC_LOGE("No GPS HW on this target. Not returning interface.");
return NULL;
case GNSS_QCA1530:
// qca1530 chip is present
gps_conf.CAPABILITIES &= ~(GPS_CAPABILITY_MSA | GPS_CAPABILITY_MSB);
LOC_LOGD("qca1530 present: CAPABILITIES %0lx\n", gps_conf.CAPABILITIES);
break;
}
return &sLocEngInterface;
}
sLocEngInterface的定義如下:// Defines the GpsInterface in gps.h
static const GpsInterface sLocEngInterface =
{
sizeof(GpsInterface),
loc_init,
loc_start,
loc_stop,
loc_cleanup,
loc_inject_time,
loc_inject_location,
loc_delete_aiding_data,
loc_set_position_mode,
loc_get_extension
};
sLocEngInterface指定了GpsInterface結構體的各個回撥函式,如啟動定位/取消定位等,這些回撥函式的實現均在Loc.cpp中實現。