最近工作上有碰到sensor的相關問題,正好分析下其流程作個筆記。
這個筆記分三個部分:
- sensor硬體和驅動的工作機制
- sensor 上層app如何使用
- 從驅動到上層app這中間的流程是如何
Sensor硬體和驅動的工作機制
先看看Accerometer +Gyro Sensor的原理圖:

總結起來分四個部分(電源,地,通信接口,中斷腳)。電源和地與平台和晶片本身有關系,與我們分析的沒有多少關系,根據sensor的特性保證 sensor正常工作的上電時序。關于通信接口,sensor與ap之間通信一般有兩種接口(I2C/SPI)。因sensor資料量不大,I2C的速度 足矣,目前使用I2C的居多。SDA是I2C的資料線,SCL是I2C的clock線。關于中斷腳就是INT。Sensor有兩個工作模式。一種是主動上 報資料(每時每刻将擷取到的資料上報給系統),另個一種是中斷模式(當資料的變化大于了之前設定的觸發條件),比如手機翻轉大于45度,就會将目前的變化 及目前資料上報給系統。
Sensor上層app的使用
先要注冊指定sensor的事件監聽,然在在有事件上報上來時,擷取上報的資料。
具體代碼如下:
1 SensorManager mSensorManager = (SensorManager)mContext.getSystemService(Context.SENSOR_SERVICE);
2 Sensor mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
3
4 mSensorManager.registerListener(mSensorListener, mSensor, SensorManager.SENSOR_DELAY_GAME);
5 /*
6 public static final int SENSOR_DELAY_FASTEST = 0;
7 public static final int SENSOR_DELAY_GAME = 1;
8 public static final int SENSOR_DELAY_UI = 2;
9 public static final int SENSOR_DELAY_NORMAL = 3;
10 上報的速度可以根據需求來選擇
11 */
12
13 SensorEventListener mSensorListener = new SensorEventListener(){
14 public void onAccuracyChanged(Sensor arg0, int arg1){
15 }
16
17 public void onSensorChanged(SensorEvent event){
18 if(event.sensor == null){
19 return;
20 }
21 Log.d(TAG, "onSensorChanged");
22 if(Sensor.TYPE_ACCELEROMETER == event.sensor.getType()) {
23 mGsensor = (float)event.values[SensorManager.DATA_Z];
24 mSensorManager.unregisterListener(this);
25 Log.e(TAG, "mgsensor = " + mGsensor);
26 mOnSensorChangedFlag = false;
27 }
28 }
29 }
從驅動到上層App這中間的流程如何
前面二段分别說了驅動上報資料和app讀取資料,但中間的流程是如何的呢,這個是此篇部落格的重點了。
驅動層上報資料後,HAL層怎麼處理呢?這個屬于input hal層的接收和分發了。來,我們來啃啃這個骨頭:
frameworks/base/core/java/android/app/SystemServiceRegistry.java
419 registerService(Context.SENSOR_SERVICE, SensorManager.class,
420 new CachedServiceFetcher<SensorManager>() {
421 @Override
422 public SensorManager createService(ContextImpl ctx) {
423 return new SystemSensorManager(ctx.getOuterContext(),
424 ctx.mMainThread.getHandler().getLooper());
425 }});
mContext.getSystemService(Context.SENSOR_SERVICE) 傳回的就是SystemSensorManager 的對象(也是繼承SensorManager 類)。
frameworks/base/core/java/android/hardware/SensorManager.java
790 public Sensor getDefaultSensor(int type) {
......................................................................
841 List<Sensor> l = getSensorList(type);
842 boolean wakeUpSensor = false;
846 if (type == Sensor.TYPE_PROXIMITY || type == Sensor.TYPE_SIGNIFICANT_MOTION ||
847 type == Sensor.TYPE_TILT_DETECTOR || type == Sensor.TYPE_WAKE_GESTURE ||
848 type == Sensor.TYPE_GLANCE_GESTURE || type == Sensor.TYPE_PICK_UP_GESTURE ||
849 type == Sensor.TYPE_WRIST_TILT_GESTURE) {
850 wakeUpSensor = true;
851 }
852 //傳回支援喚醒的sensor
853 for (Sensor sensor : l) {
854 if (sensor.isWakeUpSensor() == wakeUpSensor) return sensor;
855 }
}
我們再看看getSensorList這裡面有啥玩意。。。。
public List<Sensor> getSensorList(int type) {
.......................................................................
final List<Sensor> fullList = getFullSensorList();
//然後再種所有sensor中找出對應的sensor
for (Sensor i : fullList) {
if (i.getType() == type)
list.add(i);
}
return list;
}
getFullSensorList這個函數傳回的是mFullSensorsList。
mFullSensorList是SystemSensorManager 周遊所有的sensor得到的集合。
下一步我們再來看看registerListener是怎麼回事。
frameworks/base/core/java/android/hardware/SystemSensorManager.java
protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor, int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags) {
synchronized (mSensorListeners) {
//先檢視下此sensor的監聽隊列是否已經存在,如果不存在,就重新new個
SensorEventQueue queue = mSensorListeners.get(listener);
if (queue == null) {
queue = new SensorEventQueue(listener, looper, this, fullClassName);
mSensorListeners.put(listener, queue);
return true;
} else {
return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs);
}
}
到這裡就明顯是一個消息隊列回調的問題了,肯定是發現消息隊列裡有消息時就會回調具體的事件。我們繼續撸代碼。
static final class SensorEventQueue extends BaseEventQueue {
protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy,
long timestamp) {
......................................................
// call onAccuracyChanged() only if the value changes
final int accuracy = mSensorAccuracies.get(handle);
if ((t.accuracy >= 0) && (accuracy != t.accuracy)) {
mSensorAccuracies.put(handle, t.accuracy);
mListener.onAccuracyChanged(t.sensor, t.accuracy);
}
mListener.onSensorChanged(t);
}
}
從這裡就可以看我們listener裡實作的onAccuracyChanged,onSensorChanged是怎麼被調用。
frameworks/base/core/java/android/hardware/SensorEventListener.java
public interface SensorEventListener {
public void onSensorChanged(SensorEvent event);
public void onAccuracyChanged(Sensor sensor, int accuracy);
}
就是一個接口,裡面聲明兩個函數。
看到回調是在dispatchSensorEvent裡做的,看看是誰調用的。。。
frameworks/base/core/jni/android_hardware_SensorManager.cpp
class Receiver : public LooperCallback {
virtual int handleEvent(int fd, int events, void* data) {
ASensorEvent buffer[16];
while ((n = q->read(buffer, 16)) > 0) {
for (int i=0 ; i<n ; i++) {
if (buffer[i].type == SENSOR_TYPE_META_DATA) {
// This is a flush complete sensor event. Call dispatchFlushCompleteEvent
// method.
if (receiverObj.get()) {
env->CallVoidMethod(receiverObj.get(),
gBaseEventQueueClassInfo.dispatchFlushCompleteEvent,
buffer[i].meta_data.sensor);
}
} else {
if (receiverObj.get()) {
env->CallVoidMethod(receiverObj.get(),
gBaseEventQueueClassInfo.dispatchSensorEvent,
buffer[i].sensor,
mScratch,
status,
buffer[i].timestamp);
}
}
}
}
}
讀到的資料,根據資料的類型去回調不同的接口。dispatchSensorEvent就是在這裡被調用的。
handleEvent這個是一個典型的eventQueue這事件處理,具體就不在這裡分析了。
回調這些都有分析了,那事件是哪裡加入到消息隊列中的,那些消息又是怎麼來的呢,話說問題問對了,就能找到往下查的路了。。哈哈
理論這些肯定會有sensor服務在開機的時候啟動的,那服務在哪裡,是怎麼啟動的呢。。。
frameworks/base/services/java/com/android/server/SystemServer.java
private void startBootstrapServices() {
...................................................
startSensorService();
}
這個startSensorService是個jni函數,調用的是:
frameworks/base/services/core/jni/com_android_server_SystemServer.cpp
static void android_server_SystemServer_startSensorService(JNIEnv* /* env */, jobject /* clazz */) {
//建立一個線程做sensorinit的工作
pthread_create( &sensor_init_thread, NULL, &sensorInit, NULL);
}
void* sensorInit(void *arg) {
SensorService::instantiate();
}
sensorService服務就做初始化了,服務啟動時會做threadLoop(),
bool SensorService::threadLoop()
{
ALOGD("nuSensorService thread starting...");
const size_t minBufferSize = SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT;
const size_t numEventMax = minBufferSize / (1 + mVirtualSensorList.size());
//device初始化
SensorDevice& device(SensorDevice::getInstance());
const size_t vcount = mVirtualSensorList.size();
const int halVersion = device.getHalDeviceVersion();
do {
//調用device.poll
ssize_t count = device.poll(mSensorEventBuffer, numEventMax);
if (count < 0) {
ALOGE("sensor poll failed (%s)", strerror(-count));
break;
}
}
再看看SensorDevice 裡初始化和poll裡做了啥 :
SensorDevice::SensorDevice()
: mSensorDevice(0),
mSensorModule(0)
{
//get HAL module
status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID,
(hw_module_t const**)&mSensorModule);
ALOGE_IF(err, "couldn't load %s module (%s)",
SENSORS_HARDWARE_MODULE_ID, strerror(-err));
if (mSensorModule) {
//open HAL module
err = sensors_open_1(&mSensorModule->common, &mSensorDevice);
...................................................
}
SensorDevice初始化做了兩個動作,一個是擷取sensor HAL module,緊接着打開sensor hal module。
再一起看年poll裡做啥了,
ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) {
if (!mSensorDevice) return NO_INIT;
ssize_t c;
do {
c = mSensorDevice->poll(reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice),
buffer, count);
} while (c == -EINTR);
return c;
}
poll也是調用 的是Hal module裡的poll。
那sensor HAL裡做了啥呢,子產品做了啥呢?
sensor hal路徑:hardware/libhardware/modules/sensors/
hardware/libhardware/modules/sensors/multihal.cpp
624 static int open_sensors(const struct hw_module_t* hw_module, const char* name,
625 struct hw_device_t** hw_device_out) {
626 ALOGV("open_sensors begin...");
627 //初始化加載高通的庫
628 lazy_init_modules();
629
630 // Create proxy device, to return later.
631 sensors_poll_context_t *dev = new sensors_poll_context_t();
632 memset(dev, 0, sizeof(sensors_poll_device_1_t));
633 dev->proxy_device.common.tag = HARDWARE_DEVICE_TAG;
634 dev->proxy_device.common.version = SENSORS_DEVICE_API_VERSION_1_3;
635 dev->proxy_device.common.module = const_cast<hw_module_t*>(hw_module);
636 dev->proxy_device.common.close = device__close;
637 dev->proxy_device.activate = device__activate;
638 dev->proxy_device.setDelay = device__setDelay;
639 dev->proxy_device.poll = device__poll;
640 dev->proxy_device.batch = device__batch;
641 dev->proxy_device.flush = device__flush;
.......................................
}
我們看看lazy_init_modules()這個,是把指定的的hal so加載起來。。
481 /*
482 * Ensures that the sub-module array is initialized.
483 * This can be first called from get_sensors_list or from open_sensors.
484 */
485 static void lazy_init_modules() {
486 pthread_mutex_lock(&init_modules_mutex);
487 if (sub_hw_modules != NULL) {
488 pthread_mutex_unlock(&init_modules_mutex);
489 return;
490 }
491 std::vector<std::string> *so_paths = new std::vector<std::string>();
481 /*
482 * Ensures that the sub-module array is initialized.
483 * This can be first called from get_sensors_list or from open_sensors.
484 */
485 static void lazy_init_modules() {
486 pthread_mutex_lock(&init_modules_mutex);
487 if (sub_hw_modules != NULL) {
488 pthread_mutex_unlock(&init_modules_mutex);
489 return;
490 }
491 std::vector<std::string> *so_paths = new std::vector<std::string>();
492 get_so_paths(so_paths);
493
494 // dlopen the module files and cache their module symbols in sub_hw_modules
495 sub_hw_modules = new std::vector<hw_module_t *>();
496 dlerror(); // clear any old errors
497 const char* sym = HAL_MODULE_INFO_SYM_AS_STR;
498 for (std::vector<std::string>::iterator it = so_paths->begin(); it != so_paths->end(); it++) {
499 const char* path = it->c_str();
500 void* lib_handle = dlopen(path, RTLD_LAZY);
501 if (lib_handle == NULL) {
502 ALOGW("dlerror(): %s", dlerror());
503 } else {
504 ALOGI("Loaded library from %s", path);
505 ALOGV("Opening symbol \"%s\"", sym);
506 // clear old errors
507 dlerror();
508 struct hw_module_t* module = (hw_module_t*) dlsym(lib_handle, sym);
509 const char* error;
510 if ((error = dlerror()) != NULL) {
511 ALOGW("Error calling dlsym: %s", error);
512 } else if (module == NULL) {
513 ALOGW("module == NULL");
514 } else {
515 ALOGV("Loaded symbols from \"%s\"", sym);
516 sub_hw_modules->push_back(module);
517 }
518 }
519 }
520 pthread_mutex_unlock(&init_modules_mutex);
521 }
//擷取的要加載so庫的路徑:/system/etc/sensors/hals.conf
492 get_so_paths(so_paths);
493
494 // dlopen the module files and cache their module symbols in sub_hw_modules
495 sub_hw_modules = new std::vector<hw_module_t *>();
496 dlerror(); // clear any old errors
497 const char* sym = HAL_MODULE_INFO_SYM_AS_STR;
498 for (std::vector<std::string>::iterator it = so_paths->begin(); it != so_paths->end(); it++) {
499 const char* path = it->c_str();
500 void* lib_handle = dlopen(path, RTLD_LAZY);
501 if (lib_handle == NULL) {
502 ALOGW("dlerror(): %s", dlerror());
503 } else {
504 ALOGI("Loaded library from %s", path);
505 ALOGV("Opening symbol \"%s\"", sym);
506 // clear old errors
507 dlerror();
508 struct hw_module_t* module = (hw_module_t*) dlsym(lib_handle, sym);
509 const char* error;
510 if ((error = dlerror()) != NULL) {
511 ALOGW("Error calling dlsym: %s", error);
512 } else if (module == NULL) {
513 ALOGW("module == NULL");
514 } else {
515 ALOGV("Loaded symbols from \"%s\"", sym);
516 sub_hw_modules->push_back(module);
517 }
518 }
519 }
520 pthread_mutex_unlock(&init_modules_mutex);
521 }
這個路徑下就一個庫:sensors.ssc.so
再來看看poll看名字就能猜到是從資料隊列裡等資料,看代碼:
330 int sensors_poll_context_t::poll(sensors_event_t *data, int maxReads) {
331 ALOGV("poll");
332 int empties = 0;
333 int queueCount = 0;
334 int eventsRead = 0;
335
336 pthread_mutex_lock(&queue_mutex);
337 queueCount = (int)this->queues.size();
338 while (eventsRead == 0) {
339 while (empties < queueCount && eventsRead < maxReads) {
340 SensorEventQueue* queue = this->queues.at(this->nextReadIndex);
341 sensors_event_t* event = queue->peek();
确實是消息隊列。。。
再來年看看加載的so庫這個是高通的sensor hal庫。
代碼路徑:vendor/qcom/proprietary/sensors/dsps/libhalsensors
看先從哪裡插入資料的:
vendor/qcom/proprietary/sensors/dsps/libhalsensors/src/Utility.cpp
bool Utility::insertQueue(sensors_event_t const *data_ptr){
..........................
if (q_head_ptr == NULL) {
/* queue is empty */
q_tail_ptr = q_ptr;
q_head_ptr = q_ptr;
} else {
/* append to tail and update tail ptr */
q_tail_ptr->next = q_ptr;
q_tail_ptr = q_ptr;
}
}
那看調用的有哪些呢?
Orientation.cpp (src): if (Utility::insertQueue(&la_sample)) {
PedestrianActivityMonitor.cpp (src): if (Utility::insertQueue(&sensor_data)) {
Pedometer.cpp (src): if (Utility::insertQueue(&la_sample)) {
PickUpGesture.cpp (src): if (Utility::insertQueue(&sensor_data)) {
QHeart.cpp (src): if (Utility::insertQueue(&la_sample)) {
RelativeMotionDetector.cpp (src): if (Utility::insertQueue(&sensor_data)) {
RotationVector.cpp (src): if (Utility::insertQueue(&la_sample)) {
Sensor.cpp (src): if (Utility::insertQueue(&flush_evt)){
....................................................................
都在各類sensor的processInd 這個函數中,每種sensor類型根據自身資料的特點,對其做資料結構做指定封裝。也就是所謂的工廠模式。
有一個調用比較特别:SMGRSensor.cpp 中processReportInd函數,這個函數中
void SMGRSensor::processReportInd(Sensor** mSensors, sns_smgr_periodic_report_ind_msg_v01* smgr_ind){
...............................
handle = getHandleFromInd(smgr_ind->ReportId, smgr_data->DataType,
smgr_data->SensorId);
if (handle == -1 ) {
HAL_LOG_ERROR(" %s: ReportId = %d DataType = %d SensorId = %d ", __FUNCTION__,
smgr_ind->ReportId, smgr_data->DataType, smgr_data->SensorId);
goto error;
}
/* Corresponds to screen orientation req, fill in the right type */
if ((handle == HANDLE_ACCELERATION) && (smgr_ind->ReportId == HANDLE_MOTION_ACCEL)) {
sensor_data.type = SENSOR_TYPE_SCREEN_ORIENTATION;
sensor_data.sensor = HANDLE_MOTION_ACCEL;
}
if (mSensors[handle] != NULL) {
(static_cast<SMGRSensor*>(mSensors[handle]))->processReportInd(smgr_ind, smgr_data, sensor_data);
}
................................
if (Utility::insertQueue(&sensor_data)) {
Utility::signalInd(data_cb);
}
}
這裡根據smgr_data->DataType又做了一次工廠模式的分發處理:
GyroscopeUncalibrated.cpp (src): FUNCTION: processReportInd
GyroscopeUncalibrated.cpp (src):void GyroscopeUncalibrated::processReportInd(
GyroscopeUncalibrated.cpp (src): HAL_LOG_DEBUG("GyroscopeUncalibrated::processReportInd");
GyroscopeUncalibrated.h (inc): FUNCTION: processReportInd
GyroscopeUncalibrated.h (inc): void processReportInd(sns_smgr_periodic_report_ind_msg_v01* smgr_ind,
HallEffect.cpp (src): FUNCTION: processReportInd
HallEffect.cpp (src):void HallEffect::processReportInd(sns_smgr_periodic_report_ind_msg_v01* smgr_ind,
HallEffect.h (inc): FUNCTION: processReportInd
HallEffect.h (inc): void processReportInd(sns_smgr_periodic_report_ind_msg_v01* smgr_ind,
Humidity.cpp (src): FUNCTION: processReportInd
Humidity.cpp (src):void Humidity::processReportInd(sns_smgr_periodic_report_ind_msg_v01* smgr_ind,
Humidity.h (inc): FUNCTION: processReportInd
Humidity.h (inc): void processReportInd(sns_smgr_periodic_report_ind_msg_v01* smgr_ind,
IRGesture.cpp (src): FUNCTION: processReportInd
IRGesture.cpp (src):void IRGesture::processReportInd(sns_smgr_periodic_report_ind_msg_v01* smgr_ind,
IRGesture.h (inc): FUNCTION: processReportInd
IRGesture.h (inc): void processReportInd(sns_smgr_periodic_report_ind_msg_v01* smgr_ind,
Light.cpp (src): FUNCTION: processReportInd
Light.cpp (src):void Light::processReportInd(sns_smgr_periodic_report_ind_msg_v01* smgr_ind,
Light.h (inc): FUNCTION: processReportInd
Light.h (inc): void processReportInd(sns_smgr_periodic_report_ind_msg_v01* smgr_ind,
Magnetic.cpp (src): FUNCTION: processReportInd
Magnetic.cpp (src):void Magnetic::processReportInd(sns_smgr_periodic_report_ind_msg_v01* smgr_ind,
Magnetic.h (inc): FUNCTION: processReportInd
Magnetic.h (inc): void processReportInd(sns_smgr_periodic_report_ind_msg_v01* smgr_ind
又是根據類型不同,做了另一批類型sensor的處理。
繼續反向推導,processReportInd其它這個也是processBufferingInd 調用的,processBufferingInd也是processInd 調用的。這就和其它的sensor到統一戰線上了。都是processInd處理的。
關鍵就是這processInd了,這個是一個回調SMGRSensor_sensor1_cb函數裡處理的。那這個回調是誰注冊,又是什麼調用的呢?
vendor/qcom/proprietary/sensors/dsps/libhalsensors/src/SensorsContext.cpp
這個裡面會在SensorContext執行個體化時注冊。
SensorsContext::SensorsContext()
: active_sensors(0),
is_accel_available(false),
is_gyro_available(false),
is_mag_available(false),
is_prox_available(false),
smgr_version(0)
{
。。。。。。。。。。。。。。。。。。。
err = sensor1_open(&sensor_info_sensor1_cb->sensor1_handle, &context_sensor1_cb, (intptr_t)this);
。。。。。。。。。
}
那得去撸代碼啊,不然不知道啥時候回調context_sensor1_cb這個函數啊。。。
這個函數在另一個庫中了libsensor1。。
這個函數做的事情比較多,分三部分:
sensor1_open( sensor1_handle_s **hndl,
sensor1_notify_data_cb_t data_cbf,
intptr_t cb_data )
{
.........................
sensor1_init();
............................
sockfd = socket(AF_UNIX, SOCK_SEQPACKET, 0))
strlcpy(address.sun_path, SENSOR_CTL_SOCKET, UNIX_PATH_MAX);
connect(sockfd, (struct sockaddr *)&address, len)
.....................................
libsensor_add_waiting_client(&cli_data);
libsensor_add_client( &new_cli, false )
.....................................
}
那第一步先看看sensor1_init做了啥?
相當于建立了一個讀線程,一直在poll讀消息隊列裡的消息,讀到消息後,會封裝資料,然後發一個資訊去喚醒另外一個線程,喚醒的線程後面再說。
第二步再看看,建立了一個socket(一個用戶端socket),去連接配接服務端的socket(服務端的socket又是什麼東東),上個讀線程讀到的消息就是從socket讀到的消息(libsensor_read_socket),那一定是服務端socket發送過來的嘛。。。
第三步增加client,再看看這個又做了啥?
這裡又建立了一個回調線程,等有消息來時,喚醒本線程,然後回調sensor.ssc.庫裡的context_sensor1_cb。這個線程就誰喚醒的呢,哈哈,大家就能想到就是init中的那個讀線程嘛。
總結sensor1_open就是建立一個讀線程從socket用戶端中讀資料,讀到資料後,就回調sensor.ssc庫中的context_sensor1_cb,進而上報資料做進一步回調。
那問題來了,那個socket服務端又是怎麼回事呢。。。慢慢接近真相了。。。。
這時又出現了一個服務SensorDaemon:
代碼路徑:vendor/qcom/proprietary/sensors/dsps/sensordaemon
sns_main_setup 裡建立了socket伺服器端,然後監聽用戶端socket的監聽,那什麼時候往socket裡寫東西呢?
這就涉及另一個回調函數了sns_main_notify_cb。這個回調函數則好就是sensor1_open裡注冊的。這個sensor1_open 與 libsensor1裡的sensor1_open不是同一個。
ok,那問題又來了,啥時候做的回調,和之前很類似,有一個讀線程,初始化後處理polling狀态,當收到消息時,就回調這個回調函數。
這個讀線程的資料是從哪裡來的呢,這就涉及到QMI service了。QMI service這部分代碼就不是AP這邊了,此份代碼就在modem的adsp代碼中了。
找時間再來續modem這邊的adsp。