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