电竞比分网-中国电竞赛事及体育赛事平台

分享

紅狼博客 ? Android源碼分析:傳感器系統(tǒng)

 dwlinux_gs 2014-08-09

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的采樣值、精確度、時間戳以及信息是自哪個感應器等信息封裝在JavaSensorEvent中。JavaSensor代表一個感應器,包含感應器的各種信息,它的成員數(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進行處理。

 

JNInative

JNI層位于frameworks/base/core/jni/下面,主要就是一個文件android_hardware_SensorManager.cpp。它使用的類如Sensor、SensorChannel、SensorEventQueue、、ISensorEventConnectionISensorServer則放在libgui.so中,見目錄frameworks/base/libs/gui。

 

Java層在輪詢之前,必須調(diào)用sensors_create_queue創(chuàng)建(見SensorThreadRunnableopen函數(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);
if (res == -EAGAIN) {
res = queue->waitForEvent();//
等待有數(shù)據(jù)可讀取
if (res != NO_ERROR)//
檢查是否發(fā)生錯誤
return -1;
res = queue->read(&event, 1);//
沒錯誤,進行數(shù)據(jù)讀取
}

封裝管道的SensorChannel類的對象由ISensorEventConnection接口獲取。另外,對sensor的激活/去激活也是通過ISensorEventConnection調(diào)用到server側(cè)的SensorService完成的。

C++Sensor代表了一個sensor,它是HALsensor_t的封裝,同時又為Java層的Sensor類中的數(shù)據(jù)成員變量提供數(shù)據(jù)“源”,也就是說,Java中的Sensor的成員變量信息是由該C++中的Sensor類設置,后者又是根據(jù)sensor_t而獲取對應的sensor信息。Java中的Sensor是應用開發(fā)的API類。在C++中的Sensor類中定義了sensor的枚舉類型:

enum {
TYPE_ACCELEROMETER = ASENSOR_TYPE_ACCELEROMETER, //
加速度
TYPE_MAGNETIC_FIELD = ASENSOR_TYPE_MAGNETIC_FIELD, //
磁場
TYPE_GYROSCOPE = ASENSOR_TYPE_GYROSCOPE, //
陀螺儀
TYPE_LIGHT = ASENSOR_TYPE_LIGHT, //
光傳感器
TYPE_PROXIMITY = ASENSOR_TYPE_PROXIMITY //
距離傳感器
};

 

SensorService

frameworks/base/services/sensorservice/下面給出sensorService的相關實現(xiàn)代碼,它們最終生成libsensorservice.so庫文件,作為service被注冊到system server后,最終運行于system_server后臺進程空間。

Sensor service模塊的核心部分是SensorService類。另外還定義了幾個邏輯上的虛擬sensorGravitySensorLinearAccelerationSensorRotationVectorSensor,它們的接口由抽象類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;//是否為虛擬的,即是否為邏輯(虛擬)傳感器

GravitySensorLinearAccelerationSensor,它們不是物理意義上的傳感器,只是邏輯意義上的傳感器,可稱之為虛擬(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來完成的。

SensorDeviceHAL中的libsensors.so打交道,如獲取對應的硬件module,打開sensor設備,參見其構造函數(shù):

SensorDevice::SensorDevice()
: mSensorDevice(0),
mSensorModule(0)
{
status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID,
(hw_module_t const**)&mSensorModule);//
打開sensor硬件模塊

LOGE_IF(err, “couldn’t load %s module (%s)”,
SENSORS_HARDWARE_MODULE_ID, strerror(-err));

if (mSensorModule) {
err = sensors_open(&mSensorModule->common, &mSensorDevice);//
打開HAL層的poll設備
LOGE_IF(err, “couldn’t open device for module %s (%s)”,
SENSORS_HARDWARE_MODULE_ID, strerror(-err));
if (mSensorDevice) {
sensor_t const* list;
ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);//
獲取sensor_t列表
mActivationCount.setCapacity(count);
Info model;
for (size_t i=0 ; i<size_t(count) ; i++) {
mActivationCount.add(list[i].handle, model);
mSensorDevice->activate(mSensorDevice, list[i].handle, 0);
}
}
}
}

其結(jié)構圖如下:

作為核心代碼的SensorService類有三個父類:

BinderService<SensorService>:繼承該父類使其成為一個標準的本地(nativeservice,將自己添加到系統(tǒng)的system server中去,其它感興趣者可以使用該service

BnSensorServer:意味著作為子類,SensorService是抽象類ISensorServer中定義的兩個接口(getSensorListcreateSensorEventConnection)的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()
{
LOGD(“nuSensorService thread starting…”);

const size_t numEventMax = 16 * (1 + mVirtualSensorList.size());
sensors_event_t buffer[numEventMax];
sensors_event_t scratch[numEventMax];
SensorDevice& device(SensorDevice::getInstance());
const size_t vcount = mVirtualSensorList.size();

ssize_t count;
do {
count = device.poll(buffer, numEventMax);//
輪詢event數(shù)據(jù)到緩沖區(qū)
if (count<0) {
LOGE(“sensor poll failed (%s)”, strerror(-count));
break;
}

recordLastValue(buffer, count);//記錄每個sensor最新的值,記入到mLastEventSeen這個KeyedVector(從sensor標識符到sensors_event_t的映射)中。

// handle virtual sensors
if (count && vcount) {//
下面是處理虛擬sensors數(shù)據(jù)
const DefaultKeyedVector<int, SensorInterface*> virtualSensors( getActiveVirtualSensors());

const size_t activeVirtualSensorCount = virtualSensors.size();

if (activeVirtualSensorCount) {
size_t k = 0;
for (size_t i=0 ; i<size_t(count) ; i++) {
sensors_event_t const * const event = buffer;
for (size_t j=0 ; j<activeVirtualSensorCount ; j++) {
sensors_event_t out;
if (virtualSensors.valueAt(j)->process(&out, event[i])) {//
處理原始數(shù)據(jù),經(jīng)過處理轉(zhuǎn)換后的數(shù)據(jù)信息保存在out這個event
buffer[count + k] = out;//
將它們添加到buffer
k++;
}
}
}

if (k) {
// record the last synthesized values
recordLastValue(&buffer[count], k);//
同樣對虛擬的sensorevent最新值添加到mLastEventSeen
count += k;
// sort the buffer by time-stamps
sortEventBuffer(buffer, count);//
按時間戳排序
}
}
}

// send our events to clients…
const SortedVector< wp<SensorEventConnection> > activeConnections(
getActiveConnections());
size_t numConnections = activeConnections.size();
for (size_t i=0 ; i<numConnections ; i++) {
sp<SensorEventConnection> connection(
activeConnections[i].promote());
if (connection != 0) {
connection->sendEvents(buffer, count, scratch);//
發(fā)送給client端,實際是寫入管道
}
}
} while (count >= 0 || Thread::exitPending());

LOGW(“Exiting SensorService::threadLoop!”);
return false;
}

因此,可以看出,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)應由芯片廠家給出。

在使用sensorsHAL時,首先使用HAL提供的hw_get_module函數(shù),根據(jù)其模塊ID字符串(SENSORS_HARDWARE_MODULE_ID)獲取硬件模塊sensors_module_t,然后借助于sensors_module_t枚舉中設備中所帶的所有sensorssensor由結(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 {
/* name of this sensors */
const char* name;//sensor
的名稱

/* vendor of the hardware part */
const char* vendor;//
廠家

/* version of the hardware part + driver. The value of this field is
* left to the implementation and doesn’t have to be monotonically
* increasing.
*/
int version;//
版本

/* handle that identifies this sensors. This handle is used to activate
* and deactivate this sensor. The value of the handle must be 8 bits
* in this version of the API.
*/
int handle;//
句柄,用于標識是激活/去激活哪個sensor,亦即sensors_event_t中的int32_t sensor;它實際是由四個字符的ascii碼值來填充

/* this sensor’s type. */
int type;//sensor
類型,在sensor.h中定義了多達12種類型(有的為邏輯上的sensor),并以注釋的方式對它們進行了詳細解釋

/* maximaum range of this sensor’s value in SI units */
float maxRange;//
最大取值范圍

/* smallest difference between two values reported by this sensor */
float resolution;//
解析度

/* rough estimate of this sensor’s power consumption in mA */
float power;//
估計的功耗,單位為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 */
int32_t minDelay;//
報告讀數(shù)值的events時間間隔(單位:ms),若為0,意味著不按該頻率報告,而是數(shù)據(jù)到來時才報告

/* reserved fields, must be zero */
void* reserved[8];//
保留
};

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)合體中的accelerationmagnetic兩個字段,它們的類型是結(jié)構體sensors_vec_t,其中又包含有union聯(lián)合體。這樣,Android將各種sensor統(tǒng)一成一種接口,依據(jù)不同的sensor分別對其標識和類型對采樣值進行解釋。

 

本文鏈接地址: http://www./?p=953

原創(chuàng)文章,版權?紅狼博客所有, 轉(zhuǎn)載隨意,但請注明出處。

    分享到:

相關文章:

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多