Andriod Sensor

轉自:http://blog.sina.com.cn/s/blog_89f592f5010132qy.html


(一) HAL實現

1 Android sensor構建

Android4.1 系統內置對傳感器的支持達13種,他們分別是:加速度傳感器(accelerometer)、磁力傳感器(magnetic field)、方向傳感器(orientation)、陀螺儀(gyroscope)、環境光照傳感器(light)、壓力傳感器(pressure)、溫度傳感器(temperature)和距離傳感器(proximity)等。Android實現傳感器系統包括以下幾個部分:

n         java

n         JNI 

n         HAL

n         驅動層

各部分之間架構圖如下:

Andriod <wbr>Sensor <wbr>HAL實現

2 Sensor HAL層接口

GoogleSensor提供了統一的HAL接口,不同的硬件廠商需要根據該接口來實現並完成具體的硬件抽象層,AndroidSensorHAL接口定義在:

hardware/libhardware/include/hardware/sensors.h

n         對傳感器類型的定義:

#define SENSOR_TYPE_ACCELEROMETER       1  //加速度傳感器

#define SENSOR_TYPE_MAGNETIC_FIELD        //磁力傳感器

#define SENSOR_TYPE_ORIENTATION            //方向

#define SENSOR_TYPE_GYROSCOPE             //陀螺儀

#define SENSOR_TYPE_LIGHT                   //環境光照傳感器

#define SENSOR_TYPE_PRESSURE               //壓力傳感器

#define SENSOR_TYPE_TEMPERATURE           //溫度傳感器

#define SENSOR_TYPE_PROXIMITY               //距離傳感器

#define SENSOR_TYPE_GRAVITY             9

#define SENSOR_TYPE_LINEAR_ACCELERATION 10   //線性加速度

#define SENSOR_TYPE_ROTATION_VECTOR     11

#define SENSOR_TYPE_RELATIVE_HUMIDITY   12    //溼度傳感器

#define SENSOR_TYPE_AMBIENT_TEMPERATURE 13

 

n         傳感器模塊的定義結構體如下:

struct sensors_module_t {

    struct hw_module_t common;

    int (*get_sensors_list)(struct sensors_module_t* module,

            struct sensor_t const** list);

};

該接口的定義實際上是對標準的硬件模塊hw_module_t的一個擴展,增加了一個get_sensors_list函數,用於獲取傳感器的列表。

n         對任意一個sensor設備都會有一個sensor_t結構體,其定義如下:

struct sensor_t {

    const char*     name;       //傳感器名字

    const char*     vendor;

    int             version;     //版本

    int             handle;     //傳感器的handle句柄

    int             type;       //傳感器類型

    float           maxRange;   //最大範圍

    float           resolution;    //解析度

    float           power;       //消耗能源

    int32_t         minDelay;    //事件間隔最小時間

    void*           reserved[8];   //保留字段,必須爲0

};

n         每個傳感器的數據由sensors_event_t結構體表示,定義如下:

typedef struct sensors_event_t {

    int32_t version;

    int32_t sensor;            //標識符

    int32_t type;             //傳感器類型

    int32_t reserved0;

    int64_t timestamp;        //時間戳

    union {

        float           data[16];

        sensors_vec_t   acceleration;   //加速度

        sensors_vec_t   magnetic;      //磁矢量

        sensors_vec_t   orientation;     //方向

        sensors_vec_t   gyro;          //陀螺儀

        float           temperature;     //溫度

        float           distance;        //距離

        float           light;           //光照

        float           pressure;         //壓力

        float           relative_humidity;  //相對溼度

    };

    uint32_t        reserved1[4];

} sensors_event_t;

其中,sensor爲傳感器的標誌符,而不同的傳感器則採用union方式來表示,sensors_vec_t結構體用來表示不同傳感器的數據,

n         sensors_vec_t定義如下:

typedef struct {

    union {

        float v[3];

        struct {

            float x;

            float y;

            float z;

        };

        struct {

            float azimuth;

            float pitch;

            float roll;

        };

    };

    int8_t status;

    uint8_t reserved[3];

} sensors_vec_t;

n         Sensor設備結構體sensors_poll_device_t,對標準硬件設備hw_device_t結構體的擴展,主要完成讀取底層數據,並將數據存儲在struct sensors_poll_device_t結構體中,poll函數用來獲取底層數據,調用時將被阻塞定義如下:

struct sensors_poll_device_t {

struct hw_device_t common;

//Activate/deactivate one sensor

    int (*activate)(struct sensors_poll_device_t *dev,

            int handle, int enabled);

    //Set the delay between sensor events in nanoseconds for a given sensor.

    int (*setDelay)(struct sensors_poll_device_t *dev,

            int handle, int64_t ns);

    //獲取數據

    int (*poll)(struct sensors_poll_device_t *dev,

            sensors_event_t* data, int count);

};

n         控制設備打開/關閉結構體定義如下:

static inline int sensors_open(const struct hw_module_t* module,

        struct sensors_poll_device_t** device) {

    return module->methods->open(module,

            SENSORS_HARDWARE_POLL, (struct hw_device_t**)device);

}

 

static inline int sensors_close(struct sensors_poll_device_t* device) {

    return device->common.close(&device->common);

}

3 Sensor HAL實現(bma250爲例子)

3.1打開設備流程圖

Andriod <wbr>Sensor <wbr>HAL實現

SensorDevice屬於JNI層,與HAL進行通信的接口, JNI層調用了HAL層的open_sensors()方法打開設備模塊,再調用poll__activate()對設備使能,然後調用poll__poll讀取數據。

3.2 實現代碼分析

bma250傳感器中,只有加速度傳感器,所以在sensor.cpp中,首先需要定義傳感器數組sSensorList,其實就是初始化struct sensor_t結構體,只有加速傳感器,初始化如下:

static const struct sensor_t sSensorList[] = {

 

        {     "BMA250 3-axis Accelerometer",

                "Bosch",

                1, 0,

                SENSOR_TYPE_ACCELEROMETER,

              4.0f*9.81f,

              (4.0f*9.81f)/1024.0f,

              0.2f,

              0,

              { }

       },

};

 

n         定義open_sensors函數,來打開Sensor模塊,代碼如下:

static struct hw_module_methods_t sensors_module_methods = {

       open : open_sensors

};

static int open_sensors(const struct hw_module_t* module, const char* name,

        struct hw_device_t** device)

{

       int status = -EINVAL;

 

       sensors_poll_context_t *dev = new sensors_poll_context_t();

       memset(&dev->device, 0, sizeof(sensors_poll_device_t));

 

       dev->device.common.tag = HARDWARE_DEVICE_TAG;

       dev->device.common.version  = 0;

       dev->device.common.module   = const_cast<hw_module_t*>(module);

       dev->device.common.close    = poll__close;

       dev->device.activate        = poll__activate;

       dev->device.setDelay        = poll__setDelay;

       dev->device.poll            = poll__poll;

 

       if(sensor_get_class_path(dev) < 0) {

              ALOGD("g sensor get class path error \n");

              return -1;

       }

 

       dev->fd = open_input_device();

       *device = &dev->device.common;

       status = 0;

 

       return status;

}

在這個方法中,首先需要爲hw_device_t分配內存空間,並對其初始化,設置重要方法的實現,然後調用open_input_device打開設備節點,返回文件描述符。

 

n         poll__activate()對設備使能

static int poll__activate(struct sensors_poll_device_t *device,

        int handle, int enabled) {

       sensors_poll_context_t *dev = (sensors_poll_context_t *)device;

       char buffer[20];

       int bytes = sprintf(buffer, "%d\n", enabled);

       set_sysfs_input_attr(dev->class_path,"enable",buffer,bytes);

       return 0;

}

static int set_sysfs_input_attr(char *class_path,

                            const char *attr, char *value, int len)

{

       char path[256];

       int fd;

       if (class_path == NULL || *class_path == '\0'

           || attr == NULL || value == NULL || len < 1) {

              return -EINVAL;

       }

       snprintf(path, sizeof(path), "%s/%s", class_path, attr);

       path[sizeof(path) - 1] = '\0';

       fd = open(path, O_RDWR);

       if (fd < 0) {

              return -errno;

       }

       if (write(fd, value, len) < 0) {

              close(fd);

              return -errno;

       }

       close(fd);

       return 0;

}

代碼很簡單,通過系統調用open方法打開設備,然後調用write()方法寫指令使能。

n         poll__poll(),讀取數據

static int poll__poll(struct sensors_poll_device_t *device,

        sensors_event_t* data, int count) {

      

       struct input_event event;

       int ret;

       sensors_poll_context_t *dev = (sensors_poll_context_t *)device;

 

       if (dev->fd < 0)

       return 0;

       while (1) {

              ret = read(dev->fd, &event, sizeof(event));

              if (event.type == EV_ABS) {

 

                     switch (event.code) {

                            #ifdef GSENSOR_XY_REVERT

                     case ABS_Y:

                            data->acceleration.x =

                                          event.value * CONVERT_X;

                            break;

                     case ABS_X:

                            data->acceleration.y =

                                          event.value * CONVERT_Y;

                            break;                         

                            #else

                     case ABS_X:

                            data->acceleration.x =

                                          event.value * CONVERT_X;

                            break;

                     case ABS_Y:

                            data->acceleration.y =

                                          event.value * CONVERT_Y;

                            break;

                            #endif

                     case ABS_Z:

                            data->acceleration.z =

                                          event.value * CONVERT_Z;

                            break;

                     }

              } else if (event.type == EV_SYN) {

 

                     data->timestamp =

                     (int64_t)((int64_t)event.time.tv_sec*1000000000

                                   + (int64_t)event.time.tv_usec*1000);

                     data->sensor = 0;

                     data->type = SENSOR_TYPE_ACCELEROMETER;

                     data->acceleration.status = SENSOR_STATUS_ACCURACY_HIGH;

              return 1; 

              }

       }

      

       return 0;

}

通過read讀取設備數據,並存儲在sensors_event_t結構體中





(二)Framework原理

1 總體調用關係圖

Sensor <wbr>Framework原理

Sensor 框架分爲三個層次,客戶度、服務端、HAL層,服務端負責從HAL讀取數據,並將數據寫到管道中,客戶端通過管道讀取服務端數據。下面簡單解釋類的功能

1.1客戶端主要類

n         SensorManager.java

android4.1開始,把SensorManager定義爲一個抽象類,定義了一些主要的方法,類主要是應用層直接使用的類,提供給應用層的接口

n         SystemSensorManager.java

繼承於SensorManager,客戶端消息處理的實體,應用程序通過獲取其實例,並註冊監聽接口,獲取sensor數據

n         sensorEventListener接口

用於註冊監聽的接口

n         sensorThread

SystemSensorManager的一個內部類,開啓一個新線程負責讀取讀取sensor數據,當註冊了sensorEventListener接口的時候纔會啓動線程

n         android_hardware_SensorManager.cpp

負責與java層通信的JNI接口

n         SensorManager.cpp

sensorNative層的客戶端,負責與服務端SensorService.cpp的通信

n         SenorEventQueue.cpp

消息隊列

1.2服務端主要類

n         SensorService.cpp

服務端數據處理中心

n         SensorEventConnection

 BnSensorEventConnection繼承來,實現接口ISensorEventConnection的一些方法,ISensorEventConnectionSensorEventQueue會保存一個指針,指向調用服務接口創建的SensorEventConnection對象

n         Bittube.cpp

在這個類中創建了管道,即共享內存,用於服務端與客戶端讀寫數據

n         SensorDevice

負責與HAL讀取數據

1.3 HAL

   Sensor.hgoogleSensor定義的Hal接口,這裏我們主要介紹Framework層。sensor HAL介紹http://blog.sina.com.cn/s/blog_89f592f5010130c8.html

2客戶端讀取數據

2.1 調用時序圖

Sensor <wbr>Framework原理


2.2 代碼分析

2.2.1 apk註冊監聽器

SensorManager  mSensorManager =

 (SensorManager)getSystemService(SENSOR_SERVICE);

 Sensor   mAccelerometer =

 mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

 

    protected void onResume() {

           super.onResume();

          mSensorManager. registerListenerImpl (this, mAccelerometer,

     SensorManager.SENSOR_DELAY_NORMAL);

     }

     protected void onPause() {

           super.onPause();

         mSensorManager.unregisterListener(this);

     }

 

public interface SensorEventListener {

    public void onSensorChanged(SensorEvent event);

    public void onAccuracyChanged(Sensor sensor, int accuracy);   

}

 

沒有把全部代碼寫出來,Activity實現了SensorEventListener接口,在onCreate方法中,獲取SystemSensorManager,並獲取到加速傳感器的Sensor,在onResume方法中調用SystemSensorManager. registerListenerImpl註冊監聽器,當Sensor數據有改變的時候將會回調onSensorChanged方法。

2.2.2初始化SystemSensorManager

    public SystemSensorManager(Context context,Looper mainLooper) {

        mMainLooper = mainLooper;       

              mContext = context;

             

        synchronized(sListeners) {

            if (!sSensorModuleInitialized) {

                sSensorModuleInitialized = true;

 

                nativeClassInit();

 

                // initialize the sensor list

                sensors_module_init();

                final ArrayList<Sensor> fullList = sFullSensorsList;

                int i = 0;

                do {

                    Sensor sensor = new Sensor();

                    i = sensors_module_get_next_sensor(sensor, i);

 

                    if (i>=0) {

                        //Log.d(TAG, "found sensor: " + sensor.getName() +

                        //        ", handle=" + sensor.getHandle());

                        fullList.add(sensor);

                        sHandleToSensor.append(sensor.getHandle(), sensor);

                    }

                } while (i>0);

 

                sPool = new SensorEventPool( sFullSensorsList.size()*2 );

                sSensorThread = new SensorThread();

            }

        }

    }

 

系統開機啓動的時候,會創建SystemSensorManager的實例,在其構造函數中,主要做了四件事情:

n         初始化JNI

調用JNI函數nativeClassInit()進行初始化

n         初始化Sensor列表

調用JNI函數sensors_module_init,對Sensor模塊進行初始化。創建了nativeSensorManager的實例。

n         獲取Sensor列表

調用JNI函數sensors_module_get_next_sensor()獲取Sensor,並存在sHandleToSensor列表中

n         構造SensorThread

構造線程的類函數,並沒有啓動線程,當有應用註冊的時候纔會啓動線程

2.2.3啓動SensorThread線程讀取消息隊列中數據

protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,

            int delay, Handler handler) {

    

        synchronized (sListeners) {

            ListenerDelegate l = null;

            for (ListenerDelegate i : sListeners) {

                if (i.getListener() == listener) {

                    l = i;

                }

            }

            …….

            // if we don't find it, add it to the list

            if (l == null) {

                l = new ListenerDelegate(listener, sensor, handler);

                sListeners.add(l);

                  ……

                    if (sSensorThread.startLocked()) {

                        if (!enableSensorLocked(sensor, delay)) {

                          …….

                        }

                 ……

            } else if (!l.hasSensor(sensor)) {

                l.addSensor(sensor);

                if (!enableSensorLocked(sensor, delay)) {

                    ……

                }

            }

        }

        return result;

    }

當有應用程序調用registerListenerImpl()方法註冊監聽的時候,會調用SensorThread.startLoacked()啓動線程,線程只會啓動一次,並調用enableSensorLocked()接口對指定的sensor使能,並設置採樣時間。

 

SensorThreadRunnable實現了Runnable接口,在SensorThread類中被啓動

  boolean startLocked() {

            try {

                if (mThread == null) {

                    SensorThreadRunnable runnable = new SensorThreadRunnable();

                    Thread thread = new Thread(runnable, SensorThread.class.getName());

                    thread.start();

                    synchronized (runnable) {  //隊列創建成功,線程同步

                        while (mSensorsReady == false) {

                            runnable.wait();

                        }

                    }

                  

        }

private class SensorThreadRunnable implements Runnable {

            SensorThreadRunnable() {

            }

            private boolean open() {

                sQueue = sensors_create_queue();

                return true;

            }

            public void run() {

                …….

                if (!open()) {

                    return;

                }

                synchronized (this) {

                    mSensorsReady = true;

                    this.notify();

                }

                while (true) {

                    final int sensor = sensors_data_poll(sQueue, values, status, timestamp);

                    …….

            }

        }

    }

open函數中調用JNI函數sensors_create_queue()來創建消息隊列,然後調用SensorManager. createEventQueue()創建。

startLocked函數中啓動新的線程後,做了一個while的等待while (mSensorsReady == false),只有當mSensorsReady等於true的時候,纔會執行enableSensorLocked()函數對sensor使能。而mSensorsReady變量,是在open()調用創建消息隊列成功之後纔會true,所以我們認爲,三個功能調用順序是如下:

n         調用open函數創建消息隊列

n         調用enableSensorLocked()函數對sensor使能

n         調用sensors_data_poll從消息隊列中讀取數據,而且是在while (true)循環裏一直讀取

3 服務端實現

3.1 調用時序圖

Sensor <wbr>Framework原理

3.2代碼分析

3.2.1啓動SensorService服務

SystemServer進程中的main函數中,通過JNI調用,調用到

com_android_server_SystemServer.cppandroid_server_SystemServer_init1()方法,該方法又調用system_init.cpp中的system_init():

extern "C" status_t system_init()

{

    ……

    property_get("system_init.startsensorservice", propBuf, "1");

    if (strcmp(propBuf, "1") == 0) {

        // Start the sensor service

        SensorService::instantiate();

    }

    …..

    return NO_ERROR;

}

在這裏創建了SensorService的實例。

3.2.2 SensorService初始化

SensorService創建完之後,將會調用SensorService::onFirstRef()方法,在該方法中完成初始化工作。

     首先獲取SensorDevice實例,在其構造函數中,完成了對Sensor模塊HAL的初始化:

SensorDevice::SensorDevice()

    :  mSensorDevice(0),

       mSensorModule(0)

{

    status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID,

            (hw_module_t const**)&mSensorModule);

 

    if (mSensorModule) {

        err = sensors_open(&mSensorModule->common, &mSensorDevice);

 

        ALOGE_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);

            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);

            }

        }

    }

}

這裏主要做了三個工作:

n         調用HAL層的hw_get_modele()方法,加載Sensor模塊so文件

n         調用sensor.hsensors_open方法打開設備

n         調用sensors_poll_device_t->activate()Sensor模塊使能

 

再來看看SensorService::onFirstRef()方法:

void SensorService::onFirstRef()

{

    SensorDevice& dev(SensorDevice::getInstance());

 

    if (dev.initCheck() == NO_ERROR) {

        sensor_t const* list;

        ssize_t count = dev.getSensorList(&list);

        if (count > 0) {

            ……

            for (ssize_t i=0 ; i<count ; i++) {

                registerSensor( new HardwareSensor(list[i]) );

                ……

            }

 

            // it's safe to instantiate the SensorFusion object here

            // (it wants to be instantiated after h/w sensors have been

            // registered)

            const SensorFusion& fusion(SensorFusion::getInstance());

 

            if (hasGyro) {

               ……

            }

            ……

            run("SensorService", PRIORITY_URGENT_DISPLAY);

            mInitCheck = NO_ERROR;

        }

    }

}

在這個方法中,主要做了4件事情:

n         創建SensorDevice實例

n         獲取Sensor列表

調用SensorDevice.getSensorList(),獲取Sensor模塊所有傳感器列表

n         爲每個傳感器註冊監聽器

registerSensor( new HardwareSensor(list[i]) );

void SensorService::registerSensor(SensorInterface* s)

{

    sensors_event_t event;

    memset(&event, 0, sizeof(event));

 

    const Sensor sensor(s->getSensor());

    // 添加到Sensor列表,給客戶端使用

    mSensorList.add(sensor);

    // add to our handle->SensorInterface mapping

    mSensorMap.add(sensor.getHandle(), s);

    // create an entry in the mLastEventSeen array

    mLastEventSeen.add(sensor.getHandle(), event);

}

     HardwareSensor實現了SensorInterface接口。

n         啓動線程讀取數據

調用run方法啓動新線程,將調用SensorService::threadLoop()方法。

3.2.3 在新的線程中讀取HAL層數據

SensorService實現了Thread類,當在onFirstRef中調用run方法的後,將在新的線程中調用SensorService::threadLoop()方法。

bool SensorService::threadLoop()

{

    ……

    do {

        count = device.poll(buffer, numEventMax);

 

        recordLastValue(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);

            }

        }

    } while (count >= 0 || Thread::exitPending());

    return false;

}

while循環中一直讀取HAL層數據,再調用SensorEventConnection->sendEvents將數據寫到管道中。

4客戶端與服務端通信

4.1 數據傳送

客戶端與服務端通信的狀態圖:

Sensor <wbr>Framework原理

這是我對數據傳輸的理解畫出的一張圖,可以更好的去理解數據是如何從服務端傳到客戶端的。

n         客戶端服務端線程

在圖中我們可以看到有兩個線程,一個是服務端的一個線程,這個線程負責源源不斷的從HAL讀取數據。另一個是客戶端的一個線程,客戶端線程負責從消息隊列中讀數據。

n         創建消息隊列

客戶端可以創建多個消息隊列,一個消息隊列對應有一個與服務器通信的連接接口

n         創建連接接口

服務端與客戶端溝通的橋樑,服務端讀取到HAL層數據後,會掃面有多少個與客戶端連接的接口,然後往每個接口的管道中寫數據

n         創建管道

每一個連接接口都有對應的一個管道。

上面是設計者設計數據傳送的原理,但是目前Android4.1上面的數據傳送不能完全按照上面的理解。因爲在實際使用中,消息隊列只會創建一個,也就是說客戶端與服務端之間的通信只有一個連接接口,只有一個管道傳數據。那麼數據的形式是怎麼從HAL層傳到JAVA層的呢?其實數據是以一個結構體sensors_event_t的形式從HAL層傳到JNI層。看看HALsensors_event_t結構體:

typedef struct sensors_event_t {

    int32_t version;

    int32_t sensor;            //標識符

    int32_t type;             //傳感器類型

    int32_t reserved0;

    int64_t timestamp;        //時間戳

    union {

        float           data[16];

        sensors_vec_t   acceleration;   //加速度

        sensors_vec_t   magnetic;      //磁矢量

        sensors_vec_t   orientation;     //方向

        sensors_vec_t   gyro;          //陀螺儀

        float           temperature;     //溫度

        float           distance;        //距離

        float           light;           //光照

        float           pressure;         //壓力

        float           relative_humidity;  //相對溼度

    };

    uint32_t        reserved1[4];

} sensors_event_t;

JNI層有一個ASensorEvent結構體與sensors_event_t向對應,

frameworks/native/include/android/sensor.h

 

typedef struct ASensorEvent {

    int32_t version;

    int32_t sensor;

    int32_t type;

    int32_t reserved0;

    int64_t timestamp;

    union {

        float           data[16];

        ASensorVector   vector;

        ASensorVector   acceleration;

        ASensorVector   magnetic;

        float           temperature;

        float           distance;

        float           light;

        float           pressure;

    };

    int32_t reserved1[4];

} ASensorEvent;

JNI層,只會將結構體數據中一部分的信息傳到JAVA層:

sensors_data_poll(JNIEnv *env, jclass clazz, jint nativeQueue,

        jfloatArray values, jintArray status, jlongArray timestamp)

{

    sp<SensorEventQueue> queue(reinterpret_cast<SensorEventQueue *>(nativeQueue));

    if (queue == 0) return -1;

    status_t res;

    ASensorEvent event;

    ……

    jint accuracy = event.vector.status;

    env->SetFloatArrayRegion(values, 0, 3, event.vector.v);

    env->SetIntArrayRegion(status, 0, 1, &accuracy);

    env->SetLongArrayRegion(timestamp, 0, 1, &event.timestamp);

 

    return event.sensor;

}

其實只是傳送了加速度傳感器其的數據event.vector.v其實是一個數組,裏面包含了xyz三軸的的加速度。

 

 

4.2調用時序圖

Sensor <wbr>Framework原理

4.3 代碼分析

經過前面的介紹,我們知道了客戶端實現的方式及服務端的實現,但是沒有具體講到它兩是如何進行通信的,這節我們專門介紹客戶端與服務端之間的通信。

這裏主要涉及的是進程間通信,有IBind和管道通信。客戶端通過IBind通信獲取到服務端的遠程調用,然後通過管道進行sensor數據的傳輸。

管道是Linux 支持的最初Unix IPC形式之一,具有以下特點:

管道是半雙工的,數據只能向一個方向流動;需要雙方通信時,需要建立起兩個管道;只能用於父子進程或者兄弟進程之間(具有親緣關係的進程);單獨構成一種獨立的文件系統:管道對於管道兩端的進程而言,就是一個文件,但它不是普通的文件,它不屬於某種文件系統,而是自立門戶,單獨構成一種文件系統,並且只存在與內存中。數據的讀出和寫入:一個進程向管道中寫的內容被管道另一端的進程讀出。寫入的內容每次都添加在管道緩衝區的末尾,並且每次都是從緩衝區的頭部讀出數據。管道兩端可分別用描述字fd[0]以及fd[1]來描述,需要注意的是,管道的兩端是固定了任務的。即一端只能用於讀,由描述字fd[0]表示,稱其爲管道讀端;另一端則只能用於寫,由描述字fd[1]來表示,稱其爲管道寫端。如果試圖從管道寫端讀取數據,或者向管道讀端寫入數據都將導致錯誤發生。一般文件的I/O函數都可以用於管道,如closereadwrite等等。

4.3.1 服務端

native層實現了sensor服務的核心實現,Sensor服務的主要流程的實現在sensorservice類中,下面重點分析下這個類的流程。

class SensorService :

        public BinderService<SensorService>,

        public BnSensorServer,

        protected Thread

看看sensorService繼承的類:

n         繼承BinderService<SensorService>這個模板類添加到系統服務,用於Ibinder進程間通信。

template<typename SERVICE>

class BinderService

{

public:

    static status_t publish() {

        sp<IServiceManager> sm(defaultServiceManager());

        return sm->addService(String16(SERVICE::getServiceName()), new SERVICE());

    }

 

    static void publishAndJoinThreadPool() {

        sp<ProcessState> proc(ProcessState::self());

        sp<IServiceManager> sm(defaultServiceManager());

        sm->addService(String16(SERVICE::getServiceName()), new SERVICE());

        ProcessState::self()->startThreadPool();

        IPCThreadState::self()->joinThreadPool();

    }

 

    static void instantiate() { publish(); }

};

}; // namespace android

在前面的介紹中,SensorService服務的實例是在System_init.cpp中調用SensorService::instantiate()創建的,即調用了上面的instantiate()方法,接着調用了publish(),在該方法中,我們看到了new SensorService的實例,並且調用了defaultServiceManager::addService()Sensor服務添加到了系統服務管理中,客戶端可以通過defaultServiceManager:getService()獲取到Sensor服務的實例。

 

n         繼承BnSensorServer這個是sensor服務抽象接口類提供給客戶端調用:

class Sensor;

class ISensorEventConnection;

 

class ISensorServer : public IInterface

{

public:

    DECLARE_META_INTERFACE(SensorServer);

    //獲取Sensor列表

virtual Vector<Sensor> getSensorList() = 0;

//創建一個連接的接口,這些都是提供給客戶端的抽象接口,服務端實例化時候必須實現

    virtual sp<ISensorEventConnection> createSensorEventConnection() = 0;

};

class BnSensorServer : public BnInterface<ISensorServer>

{

public:

    //傳輸打包數據的通訊接口,BnSensorServer被實現

    virtual status_t    onTransact( uint32_t code,

                                    const Parcel& data,

                                    Parcel* reply,

                                    uint32_t flags = 0);

};

}; // namespace android

ISensorServer接口提供了兩個抽象方法給客戶端調用,關鍵在於

createSensorEventConnection()方法,該在服務端被實現,在客戶端被調用,並返回一個SensorEventConnection的實例,創建連接,客戶端拿到SensorEventConnection實例之後,可以對sensor進行通信操作,僅僅作爲通信的接口而已,它並沒有用來傳送Sensor數據,因爲Sensor數據量比較打,IBind實現比較困難。真正實現Sensor數據傳送的是管道,在創建SensorEventConnection實例中,創建了BitTube對象,裏面創建了管道,用於客戶端與服務端的通信。

4.3.2客戶端

客戶端主要在SensorManager.cpp中創建消息隊列

class ISensorEventConnection;

class Sensor;

class Looper;

 

// ----------------------------------------------------------------------------

 

class SensorEventQueue : public ASensorEventQueue, public RefBase

{

public:

            SensorEventQueue(const sp<ISensorEventConnection>& connection);

    virtual ~SensorEventQueue();

    virtual void onFirstRef();

    //獲取管道句柄

    int getFd() const;

    //向管道寫數據

    static ssize_t write(const sp<BitTube>& tube,

            ASensorEvent const* events, size_t numEvents);

    //向管道讀數據

    ssize_t read(ASensorEvent* events, size_t numEvents);

 

    status_t waitForEvent() const;

    status_t wake() const;

    //使能Sensor傳感器

    status_t enableSensor(Sensor const* sensor) const;

    status_t disableSensor(Sensor const* sensor) const;

    status_t setEventRate(Sensor const* sensor, nsecs_t ns) const;

 

    // these are here only to support SensorManager.java

    status_t enableSensor(int32_t handle, int32_t us) const;

    status_t disableSensor(int32_t handle) const;

 

private:

sp<Looper> getLooper() const;

//連接接口,在SensorService中創建的

sp<ISensorEventConnection> mSensorEventConnection;

//管道指針

    sp<BitTube> mSensorChannel;

    mutable Mutex mLock;

    mutable sp<Looper> mLooper;

};

SensorEventQueue類作爲消息隊列,作用非常重要,在創建其實例的時候,傳入了SensorEventConnection的實例,SensorEventConnection繼承於ISensorEventConnectionSensorEventConnection其實是客戶端調用SensorServicecreateSensorEventConnection()方法創建的,它是客戶端與服務端溝通的橋樑,通過這個橋樑,可以完成一下任務:

n         獲取管道的句柄

n         往管道讀寫數據

n         通知服務端對Sensor使能

4.4流程解析

4.4.1 客戶端獲取SensorService服務實例

客戶端初始化的時候,即SystemSensorManager的構造函數中,通過JNI調用,創建nativeSensorManager的實例,然後調用SensorManager::assertStateLocked()方法做一些初始化的動作。

status_t SensorManager::assertStateLocked() const {

    if (mSensorServer == NULL) {

        // try for one second

        const String16 name("sensorservice");

        ……

            status_t err = getService(name, &mSensorServer);

        ……

        mSensors = mSensorServer->getSensorList();

        size_t count = mSensors.size();

        mSensorList = (Sensor const**)malloc(count * sizeof(Sensor*));

        for (size_t i=0 ; i<count ; i++) {

            mSensorList[i] = mSensors.array() + i;

        }

    }

    return NO_ERROR;

}

前面我們講到過,SensorService的創建的時候調用了defaultServiceManager:getService()將服務添加到了系統服務管理中。現在我們又調用defaultServiceManager::geService()獲取到SensorService服務的實例。在通過IBind通信,就可以獲取到Sensor列表,所以在客戶端初始化的時候,做了兩件事情:

n         獲取SensorService實例引用

n         獲取Sensor傳感器列表

4.4.2創建消息隊列

當客戶端第一次註冊監聽器的時候,就需要創建一個消息隊列,也就是說,android在目前的實現中,只創建了一個消息隊列,一個消息隊列中有一個管道,用於服務端與客戶斷傳送Sensor數據。

SensorManager.cpp中的createEventQueue方法創建消息隊列:

sp<SensorEventQueue> SensorManager::createEventQueue()

{

    sp<SensorEventQueue> queue;

    Mutex::Autolock _l(mLock);

while (assertStateLocked() == NO_ERROR) {

    //創建連接接口

        sp<ISensorEventConnection> connection =

                mSensorServer->createSensorEventConnection();

        if (connection == NULL) {

            // SensorService just died.

            LOGE("createEventQueue: connection is NULL. SensorService died.");

            continue;

        }

//創建消息隊列

        queue = new SensorEventQueue(connection);

        break;

    }

    return queue;

}

客戶端與服務器創建一個SensorEventConnection連接接口,而一個消息隊列中包含一個連接接口。

創建連接接口:

sp<ISensorEventConnection> SensorService::createSensorEventConnection()

{

    sp<SensorEventConnection> result(new SensorEventConnection(this));

    return result;

}

SensorService::SensorEventConnection::SensorEventConnection(

        const sp<SensorService>& service)

    : mService(service), mChannel(new BitTube ())

{

}

關鍵在於BitTube,在構造函數中創建了管道:

BitTube::BitTube()

    : mSendFd(-1), mReceiveFd(-1)

{

    int sockets[2];

    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) {

        int size = SOCKET_BUFFER_SIZE;

        setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));

        setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));

        setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));

        setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));

        fcntl(sockets[0], F_SETFL, O_NONBLOCK);

        fcntl(sockets[1], F_SETFL, O_NONBLOCK);

        mReceiveFd = sockets[0];

        mSendFd = sockets[1];

    } else {

        mReceiveFd = -errno;

        ALOGE("BitTube: pipe creation failed (%s)", strerror(-mReceiveFd));

    }

}

其中:fds[0]就是對應的mReceiveFd,是管道的讀端,sensor數據的讀取端,對應的是客戶端進程訪問的。fds[1]就是對應mSendFd,是管道的寫端,sensor數據寫入端,sensor的服務進程訪問的一端。通過pipe(fds)創建管道,通過fcntl來設置操作管道的方式,設置通道兩端的操作方式爲O_NONBLOCK ,非阻塞IO方式,readwrite調用返回-1EAGAIN錯誤。

總結下消息隊列:

客戶端第一次註冊監聽器的時候,就需要創建一個消息隊列,客戶端創了SensorThread線程從消息隊列裏面讀取數據。

SensorEventQueue中有一個SensorEventConnection實例的引用,SensorEventConnection中有一個BitTube實例的引用。

4.4.3使能Sensor

客戶端創建了連接接口SensorEventConnection後,可以調用其方法使能Sensor傳感器:

status_t SensorService::SensorEventConnection::enableDisable(

        int handle, bool enabled)

{

    status_t err;

    if (enabled) {

        err = mService->enable(this, handle);

    } else {

        err = mService->disable(this, handle);

    }

    return err;

}

handle對應着Sensor傳感器的句柄

4.4.4 服務端往管道寫數據

bool SensorService::threadLoop()

{

    ……

    do {

        count = device.poll(buffer, numEventMax);

 

        recordLastValue(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);

            }

        }

    } while (count >= 0 || Thread::exitPending());

    return false;

}

前面介紹過,在SensorService中,創建了一個線程不斷從HAL層讀取Sensor數據,就是在threadLoop方法中。關鍵在與下面了一個for循環,其實是掃描有多少個客戶端連接接口,然後就往沒每個連接的管道中寫數據。

status_t SensorService::SensorEventConnection::sendEvents(

        sensors_event_t const* buffer, size_t numEvents,

        sensors_event_t* scratch)

{

    // filter out events not for this connection

    size_t count = 0;

    if (scratch) {

      ……

    }

    ……

    if (count == 0)

        return 0;

 

    ssize_t size = mChannel->write(scratch, count*sizeof(sensors_event_t));

    ……

}

調用該連接接口的BitTube::write():

ssize_t BitTube::write(void const* vaddr, size_t size)

{

    ssize_t err, len;

    do {

        len = ::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL);

        err = len < 0 ? errno : 0;

    } while (err == EINTR);

    return err == 0 ? len : -err;

 

} }

到此,服務端就完成了往管道的寫端寫入數據。

4.4.5 客戶端讀管道數據

ssize_t SensorEventQueue::read(ASensorEvent* events, size_t numEvents)

{

    return BitTube::recvObjects(mSensorChannel, events, numEvents);

}

調用到了BitTube::read():

static ssize_t recvObjects(const sp<BitTube>& tube,

            T* events, size_t count) {

        return recvObjects(tube, events, count, sizeof(T));

    }

ssize_t BitTube::recvObjects(const sp<BitTube>& tube,

        void* events, size_t count, size_t objSize)

{

    ssize_t numObjects = 0;

    for (size_t i=0 ; i<count ; i++) {

        char* vaddr = reinterpret_cast<char*>(events) + objSize * i;

        ssize_t size = tube->read(vaddr, objSize);

        if (size < 0) {

            // error occurred

            return size;

        } else if (size == 0) {

            // no more messages

            break;

        }

        numObjects++;

    }

    return numObjects;

}

 

ssize_t BitTube::read(void* vaddr, size_t size)

{

    ssize_t err, len;

    do {

        len = ::recv(mReceiveFd, vaddr, size, MSG_DONTWAIT);

        err = len < 0 ? errno : 0;

    } while (err == EINTR);

    if (err == EAGAIN || err == EWOULDBLOCK) {

        return 0;

    }

    return err == 0 ? len : -err;

}

 


 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章