|
Sensors in Android 總述 如下圖,應用程序開發(fā)者使用幾個sensor的幾個API類進行應用程序的開發(fā)。Java的部分的API使用C/C++來實現(xiàn),也就是調(diào)用到JNI層。左側(cè)運行于應用程序的進程空間,右側(cè)運行于system server進程空間。雙方通過ISensorEventConnection/SensorChannel進行通訊。SensorService負責與Sensors的硬件適配層HAL進行通訊,后者與驅(qū)動和硬件進行交互。 Java API Java層的API類有SensorManager,利用它才可以使用系統(tǒng)的各種感應器(sensor)。sensor的采樣值、精確度、時間戳以及信息是自哪個感應器等信息封裝在Java類SensorEvent中。Java類Sensor代表一個感應器,包含感應器的各種信息,它的成員數(shù)據(jù)與本地Sensor類以及HAL層的sensor_t對應(見后述章節(jié))。作為父類的SensorEventListener是一個監(jiān)聽器接口,應用開發(fā)者編寫它的一個子類可以實現(xiàn)對SensorEvent的監(jiān)聽并做出相應反應。 在獲取sensor service創(chuàng)建SensorManager時,會創(chuàng)建一個線程去輪詢(poll,調(diào)用sensors_data_poll)去取sensor的數(shù)據(jù),然后以發(fā)送消息的形式將SensorEvent發(fā)送給ListenerDelegate中的Handler,由handler在新一輪的線程循環(huán)中調(diào)用對應的sensorListener進行處理。
JNI與native層 JNI層位于frameworks/base/core/jni/下面,主要就是一個文件android_hardware_SensorManager.cpp。它使用的類如Sensor、SensorChannel、SensorEventQueue、、ISensorEventConnection和ISensorServer則放在libgui.so中,見目錄frameworks/base/libs/gui。
Java層在輪詢之前,必須調(diào)用sensors_create_queue創(chuàng)建(見SensorThreadRunnable的open函數(shù))一個本地的SensorEventQueue隊列,這個C++對象的指針被轉(zhuǎn)換為int型后保存為SensorManager的靜態(tài)成員變量sQueue。當輪詢時,將該隊列傳遞給JNI層的sensors_data_poll,用于從該隊列中讀取Event數(shù)據(jù)(具體數(shù)據(jù)類型是ASensorEvent)。 本地SensorEventQueue類主要借助于兩個類進行工作。一是封裝了管道的SensorChannel類,event的讀取和寫入都是針對封裝的管道進行的;二是libutils庫中的Looper類,Looper類實現(xiàn)了在調(diào)用者線程中對文件描述符的輪詢(內(nèi)部使用的epoll),甚至可以注冊回調(diào)函數(shù),當有文件描述符對應的文件有數(shù)據(jù)到達時使用回調(diào)函數(shù)進行處理。這樣,隊列類SensorEventQueue使用Looper監(jiān)聽著管道對應的描述符,當有數(shù)據(jù)達到時,就可以讀取,沒有使用回調(diào)機制。整個過程是:在Java層的SensorManager的線程中不斷調(diào)用sensors_data_poll查詢數(shù)據(jù),這導致其JNI層的native實現(xiàn)在隊列上等待event事件(見隊列的成員函數(shù)waitForEvent,它使用poll進行輪詢),也就是說,直到有管道中有數(shù)據(jù)可用才返回。當沒有發(fā)生錯誤返回時,表示有數(shù)據(jù)可讀,然后對數(shù)據(jù)進行讀取。一次讀取單位為一個event。 下面是JNI層中的sensors_data_poll代碼片段: res = queue->read(&event, 1); 封裝管道的SensorChannel類的對象由ISensorEventConnection接口獲取。另外,對sensor的激活/去激活也是通過ISensorEventConnection調(diào)用到server側(cè)的SensorService完成的。 C++類Sensor代表了一個sensor,它是HAL層sensor_t的封裝,同時又為Java層的Sensor類中的數(shù)據(jù)成員變量提供數(shù)據(jù)“源”,也就是說,Java中的Sensor的成員變量信息是由該C++中的Sensor類設置,后者又是根據(jù)sensor_t而獲取對應的sensor信息。Java中的Sensor是應用開發(fā)的API類。在C++中的Sensor類中定義了sensor的枚舉類型: enum {
SensorService 在frameworks/base/services/sensorservice/下面給出sensorService的相關實現(xiàn)代碼,它們最終生成libsensorservice.so庫文件,作為service被注冊到system server后,最終運行于system_server后臺進程空間。 Sensor service模塊的核心部分是SensorService類。另外還定義了幾個邏輯上的虛擬sensor:GravitySensor、LinearAccelerationSensor和RotationVectorSensor,它們的接口由抽象類SensorInterface定義,物理意義上實際傳感器HardwareSensor也同樣遵循該接口規(guī)范。 SensorInterface與四個子類繼承關系圖如下: SensorInterface是個抽象類,定義了五個接口: virtual bool process(sensors_event_t* outEvent,const sensors_event_t& event) = 0; //處理原始數(shù)據(jù),換成上層應用希望得到的數(shù)據(jù) virtual status_t activate(void* ident, bool enabled) = 0; //激活與去激活 virtual sttus_t setDelay(void* ident, int handle, int64_t ns) = 0;//設置報告處理頻率 virtual Sensor getSensor() const = 0;//獲取對應的sensor virtual bool isVirtual() const = 0;//是否為虛擬的,即是否為邏輯(虛擬)傳感器 GravitySensor和LinearAccelerationSensor,它們不是物理意義上的傳感器,只是邏輯意義上的傳感器,可稱之為虛擬(virtual)傳感器。它們實際上是將加速器(即gsensor)的值經(jīng)過處理過濾后再上報。 RotationVectorSensor方向向量傳感器,實際上它由加速器和磁場傳感器(compass)組成,根據(jù)它們上報的值來判斷是否旋轉(zhuǎn)屏幕。 引入虛擬傳感器的目的是方便上層程序的處理。在上層看來,它不需要關注設備上的傳感器的某些原始數(shù)據(jù),只需要經(jīng)過加工處理后的數(shù)據(jù),如是否旋轉(zhuǎn)屏幕,它是依據(jù)虛擬的“傳感器”sensorRotationVectorSensor得來的經(jīng)過加工后的數(shù)據(jù)。這些虛擬傳感器包含了處理原始數(shù)據(jù)的算法。算法包含在重載的process函數(shù)中。 HardwareSensor代表了真正的傳感器,它繼承自SensorInterface,實現(xiàn)了各個抽象接口,但其實現(xiàn)是借助于與位于下層的HAL層的sensor硬件模塊打交道的類SensorDevice來完成的。 SensorDevice與HAL中的libsensors.so打交道,如獲取對應的硬件module,打開sensor設備,參見其構造函數(shù): SensorDevice::SensorDevice() LOGE_IF(err, “couldn’t load %s module (%s)”, if (mSensorModule) { 其結(jié)構圖如下: 作為核心代碼的SensorService類有三個父類: BinderService<SensorService>:繼承該父類使其成為一個標準的本地(native) service,將自己添加到系統(tǒng)的system server中去,其它感興趣者可以使用該service。 BnSensorServer:意味著作為子類,SensorService是抽象類ISensorServer中定義的兩個接口(getSensorList和createSensorEventConnection)的server側(cè)的真正實現(xiàn)者。一個接口是用來獲取系統(tǒng)的sensor列表,另一個則是創(chuàng)建一個事件連接(EventConnection),用于基于管道加上輪詢方式的event傳輸。
Thread:意味著它也是一個線程類,在SensorService創(chuàng)建后,有個單獨的線程去執(zhí)行重載的threadLoop。 這個threadLoop可以說是整個sensor的調(diào)度處理中心,讓sensor相關的模塊都動起來。作為一個后臺線程,它是個無限循環(huán),不斷去處理 bool SensorService::threadLoop() const size_t numEventMax = 16 * (1 + mVirtualSensorList.size()); ssize_t count; recordLastValue(buffer, count);//記錄每個sensor最新的值,記入到mLastEventSeen這個KeyedVector(從sensor標識符到sensors_event_t的映射)中。 // handle virtual sensors const size_t activeVirtualSensorCount = virtualSensors.size(); if (activeVirtualSensorCount) { if (k) { // send our events to clients… LOGW(“Exiting SensorService::threadLoop!”); 因此,可以看出,SensorService的工作線程不斷去輪詢設備中是否有數(shù)據(jù)可用。當有數(shù)據(jù)可用時,將它們寫入管道。對方的應用程序中的線程也不斷輪詢管道,當有數(shù)據(jù)時,便調(diào)用對應的listener進行處理。它們工作在不斷的線程中,或使用looper,或使用handler,在不同的線程循環(huán)中進行處理,多次的異步操作構成了sensor的處理過程。
HAL 在Android HAL中只對sensors的數(shù)據(jù)結(jié)構進行了定義(見頭文件hardware/libhardware/include/hardware/sensors.h),其具體實現(xiàn)應由芯片廠家給出。 在使用sensors的HAL時,首先使用HAL提供的hw_get_module函數(shù),根據(jù)其模塊ID字符串(SENSORS_HARDWARE_MODULE_ID)獲取硬件模塊sensors_module_t,然后借助于sensors_module_t枚舉中設備中所帶的所有sensors(sensor由結(jié)構體sensor_t定義)列表。 數(shù)據(jù)結(jié)構sensors_module_t定義了sensors硬件模塊,其中的get_sensors_list函數(shù)指針用于枚舉設備上的各種類型的sensor,實現(xiàn)由平臺廠商給出。 同樣,可以接著使用API函數(shù)sensors_open打開HAL中定義的sensors_poll_device_t類型的設備,該結(jié)構體定義三個API,用于激活/去激活sensor(見成員activate函數(shù)指針)、設置數(shù)據(jù)報告頻率(見setDelay函數(shù)指針)和輪訓(見poll函數(shù)指針)。同樣,這三個函數(shù)也由平臺廠家實現(xiàn)。 這樣,我們可以使用hw_get_module函數(shù)打開硬件模塊,并得到sensors列表,同時,也可以使用sensors_open打開sensors_poll_device_t類型的設備,對sensor進行激活/去激活,輪詢讀數(shù)和設置數(shù)據(jù)報告頻率等基本操作。 結(jié)構體sensor_t代表了一個sensor,定義了sensor的各種屬性,如:名稱、廠家、版本、句柄、類型、最大值范圍、解析度、功耗、數(shù)據(jù)上報頻率等。其定義具體如下: struct sensor_t { /* vendor of the hardware part */ /* version of the hardware part + driver. The value of this field is /* handle that identifies this sensors. This handle is used to activate /* this sensor’s type. */ /* maximaum range of this sensor’s value in SI units */ /* smallest difference between two values reported by this sensor */ /* rough estimate of this sensor’s power consumption in mA */ /* minimum delay allowed between events in microseconds. A value of zero means that this sensor doesn’t report events at a constant rate, but rather only when a new data is available */ /* reserved fields, must be zero */ sensor的采樣值的上報可以按照某個固定的頻率進行上報,也可以當有可用的數(shù)據(jù)時再上報(minDelay設為0)。上報數(shù)據(jù)以event的形式進行,見結(jié)構體sensors_event_t,它包含了sensor的標識符、類型、數(shù)據(jù)采樣時間戳以及采樣數(shù)據(jù)。因為各種sensor的采樣值各式各樣,它更多地是用聯(lián)合體union來定義,根據(jù)不同的sensor來解釋返回的值,比如,當是加速器sensor或磁場sensor時,就分別取聯(lián)合體中的acceleration和magnetic兩個字段,它們的類型是結(jié)構體sensors_vec_t,其中又包含有union聯(lián)合體。這樣,Android將各種sensor統(tǒng)一成一種接口,依據(jù)不同的sensor分別對其標識和類型對采樣值進行解釋。
本文鏈接地址: http://www./?p=953 原創(chuàng)文章,版權?紅狼博客所有, 轉(zhuǎn)載隨意,但請注明出處。 相關文章: |
|
|
來自: dwlinux_gs > 《重力感應專題》