打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
探秘SensorHAL
分析背景:

Android4.1.2(Based on CyanogenMod 10)

DASH(https://github.com/sonyxperiadev/DASH



1.接口头文件sensors.h(hardware/libhardware/include/sensors.h)

    刚一打开就看到SENSOR HAL的ID 为"SENSORS_HARDWARE_MODULE_ID"。



[mw_shl_code=java,true]/**

* Handles must be higher than SENSORS_HANDLE_BASE and must be unique.

* A Handle identifies a given sensors. The handle is used to activate

* and/or deactivate sensors.

* In this version of the API there can only be 256 handles.

*/

#define SENSORS_HANDLE_BASE             0

#define SENSORS_HANDLE_BITS             8

#define SENSORS_HANDLE_COUNT            (1<<SENSORS_HANDLE_BITS)

/* 8位能够支持256个handle */



/**

* Sensor types

*/

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

#define SENSOR_TYPE_MAGNETIC_FIELD      2  //磁力传感器

#define SENSOR_TYPE_ORIENTATION         3  //方向传感器

#define SENSOR_TYPE_GYROSCOPE           4  //陀螺仪

#define SENSOR_TYPE_LIGHT               5  //亮度传感器

#define SENSOR_TYPE_PRESSURE            6  //压力传感器

#define SENSOR_TYPE_TEMPERATURE         7   // deprecated  温度传感器,以后的版本中将看不到任何身影

#define SENSOR_TYPE_PROXIMITY           8  //距离传感器[/mw_shl_code]



[mw_shl_code=java,true]#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  //环境温度传感器[/mw_shl_code]



支持的传感器还很多,但是 一般设备并不会用到这么多传感器,也就是加速度传感器、重力传感器、方向传感器、距离传感器、光线传感器这些,陀螺仪都很少见。

[mw_shl_code=java,true]/**

* Definition of the axis

* ----------------------

*

* This API is relative to the screen of the device in its default orientation,

* that is, if the device can be used in portrait or landscape, this API

* is only relative to the NATURAL orientation of the screen. In other words,

* the axis are not swapped when the device's screen orientation changes.

* Higher level services /may/ perform this transformation.

*

*   x<0         x>0

*                ^

*                |

*    +-----------+-->  y>0

*    |           |

*    |           |

*    |    设备    |

*    |           |   / z<0

*    |  面朝天空  |  /

*    |           | /

*    O-----------+/

*    |[]  [ ]  []/

*    +----------/+     y<0

*              /

*             /

*           |/ z>0 (toward the sky)

*

*    O: Origin (x=0,y=0,z=0)[/mw_shl_code]



还用有趣的符号图形形象的描述了“轴”的概念。然后就是一坨坨的传感器知识,blablabla......



定义了几个结构体:

1) sensors_vec_t 对单个传感器的泛用性封装,包含坐标、角度、状态等信息;

2) sensors_event_t 对传感器细致的数据再封装,包含版本号、传感器类型、数据、加速度、磁力、角度、重力等等等等的信息;

3) sensor_t 对应每个传感器,是都会有的数据,包括传感器名称、版本、handle句柄、类型、最大范围、解析度、耗能、最小延迟等信息;

4) sensors_module_t 对hw_module_t的扩展,不仅有common为hw_module_t,还定义了一个函数get_sensors_list用来获取所支持的传感器,返回值为传感器总数;

5) sensors_poll_device_t 每个传感器所私有的数据操作,包括(反)激活、设置延时、提取数据等动作。



最后定义了两个API函数用来打开/关闭一个传感器。



[mw_shl_code=java,true]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);

}[/mw_shl_code]



2. 服务开启之路(1)

sensor服务由system_server开启:

frameworks/base/cmds/system_server/system_init.cpp



[mw_shl_code=java,true]extern "C" status_t system_init()

{

    ALOGI("Entered system_init()");



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



    sp<IServiceManager> sm = defaultServiceManager();

    ALOGI("ServiceManager: %p\n", sm.get());



...

    }



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

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

        // Start the sensor service

        SensorService::instantiate();

    }

...

}[/mw_shl_code]



调用到frameworks/base/services/sensorservice/SensorService.cpp

[mw_shl_code=java,true]void SensorService::onFirstRef()

{

    ALOGD("nuSensorService starting...");



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

[/mw_shl_code]



之后又调用到了SensorDevice.cpp(同目录下)



[mw_shl_code=java,true]SensorDevice::SensorDevice()

    :  mSensorDevice(0),

       mSensorModule(0)

{

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

        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.handle, model);

                mSensorDevice->activate(mSensorDevice, list.handle, 0);

            }

        }

    }

}

[/mw_shl_code]



这段负责打开HAL,取得需要的数据及handle,对应的部分在HAL的代码中,见DASH/sensors_module.c

[mw_shl_code=java,true]struct sensors_module_t HAL_MODULE_INFO_SYM = {

        common: {

                tag: HARDWARE_MODULE_TAG,

                version_major: 1,

                version_minor: 0,

                id: SENSORS_HARDWARE_MODULE_ID,

                name : "dash",

                author : "oskar.andero@sonymobile.com",

                methods: &sensors_module_methods,

        },

        get_sensors_list: sensors_list_get

};[/mw_shl_code]



ID对上了,即可以成功打开,mSensorModule变得有效了。

然后SensorDevice.cpp调用API sensors_open,这个函数在接口头文件中有定义:



[mw_shl_code=java,true]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);

}[/mw_shl_code]



是开调用HAL的open方法:

[mw_shl_code=java,true]static int sensors_module_open(const struct hw_module_t* module, const char* id, struct hw_device_t** device)

{

        struct sensors_poll_device_t *dev;





        if (strcmp(id, SENSORS_HARDWARE_POLL))

                return 0;





        dev = malloc(sizeof(*dev));

        if (!dev)

                return -1;





        memset(dev, 0, sizeof(*dev));

        dev->common.tag = HARDWARE_DEVICE_TAG;

        dev->common.version = 0;

        dev->common.module = (struct hw_module_t*)module;

        dev->common.close = sensors_module_close;

        dev->activate = sensors_module_activate;

        dev->setDelay = sensors_module_set_delay;

        dev->poll = sensors_module_poll;





        *device = (struct hw_device_t*) dev;





        sensors_config_read(NULL);

        sensors_fifo_init();

        sensors_list_foreach_api(sensors_init_iterator, NULL);





        return 0;

}





struct hw_module_methods_t sensors_module_methods = {

        open: sensors_module_open

};[/mw_shl_code]



实际调用到了sensors_module_open,此函数返回0代表成功,-1代表打开失败,主要工作是组装device,最终将句柄交给mSensorDevice,即:

[mw_shl_code=java,true]        mSensorDevice->common.tag = HARDWARE_DEVICE_TAG;

        mSensorDevice->common.version = 0;

        mSensorDevice->common.module = (struct hw_module_t*)module;

        mSensorDevice->common.close = sensors_module_close;

        mSensorDevice->activate = sensors_module_activate;

        mSensorDevice->setDelay = sensors_module_set_delay;

        mSensorDevice->poll = sensors_module_poll;

[/mw_shl_code]



之前在说明接口头文件时,说明了,对于传感器的数据操作有三个重要函数就是avtivate, setDelay, poll。记住这几个函数,稍后做分析。

在mSensorDevice成功被组装后,调用sensors_module_t自创的另一重要接口:get_sensors_list。瞧一瞧此函数在本实例中的具体实现(DASH/sensors_list.c):



[mw_shl_code=java,true]static struct sensor_t sensors[DASH_MAX_SENSORS];

static struct sensor_api_t* sensor_apis[DASH_MAX_SENSORS];

static int number_of_sensors = 0;

[/mw_shl_code]



[mw_shl_code=java,true]int sensors_list_get(struct sensors_module_t* module, struct sensor_t const** plist)

{

        *plist = sensors;

        return number_of_sensors;

}[/mw_shl_code]



此函数完成两个工作,一将传感器列表赋给指针plist,二返回传感器数量。这里sensors列表和number_of_sensors是如何运作的:

[mw_shl_code=java,true]int sensors_list_register(struct sensor_t* sensor, struct sensor_api_t* api)

{

        if (!sensor || !api)

                return -1;





        if (number_of_sensors > DASH_MAX_SENSORS-1)

                return -1;





        sensor_apis[number_of_sensors] = api;

        /* We have to copy due to sensor API */

        memcpy(&sensors[number_of_sensors++], sensor, sizeof(*sensor));





        return 0;

}[/mw_shl_code]



每个传感器都会调用sensors_list_register将自己注册进sensors列表中,并且会将自己的API也注册进sensors_apis列表中,来一个例子吧(DASH/sensors/bma150_input.c):

[mw_shl_code=java,true]struct sensor_desc {

        struct sensors_select_t select_worker;

        struct sensor_t sensor;

        struct sensor_api_t api;



        int input_fd;

        float current_data[3];



        char *rate_path;



        /* config options */

        int axis_x;

        int axis_y;

        int axis_z;



        int neg_x;

        int neg_y;

        int neg_z;

        int64_t  delay_requests[MAX_CLIENTS];

};



static struct sensor_desc bma150_input = {

        .sensor = {

                name: "BMA150 accelerometer",

                vendor: "Bosch Sensortec GmbH",

                version: sizeof(sensors_event_t),

                handle: SENSOR_ACCELEROMETER_HANDLE,

                type: SENSOR_TYPE_ACCELEROMETER,

                maxRange: 9.81,

                resolution: 20,

                power: 0.13,

                minDelay: 5000

        },

        .api = {

                init: bma150_input_init,

                activate: bma150_input_activate,

                set_delay: bma150_input_fw_delay,

                close: bma150_input_close

        },

        .input_fd = -1,

        .axis_x = 0,

        .axis_y = 1,

        .axis_z = 2,

        .neg_x = 0,

        .neg_y = 0,

        .neg_z = 0

};[/mw_shl_code]



以上是BMA150注册了属于自己的初始化、激活、延迟、关闭等操作。

每次注册完成后自会对number_of_sensors进行+1操作。这样所有的传感器注册完成后,就会形成两个列表和一个传感器总数。sensors_list_get也就理解了。

在获取到总数后,会根据总数进行循环遍历,挨个激活传感器。



[mw_shl_code=java,true]for (size_t i=0 ; i<size_t(count) ; i++) {

                mActivationCount.add(list.handle, model);

                mSensorDevice->activate(mSensorDevice, list.handle, 0);

            }[/mw_shl_code]



OK,这下,引出了三大数据处理函数之一:activate。

sensors_module.c



[mw_shl_code=java,true]/* mSensorDevice->activate = sensors_module_activate; */

static int sensors_module_activate(struct sensors_poll_device_t *dev,

                                   int handle, int enabled)

{

        struct sensor_api_t* api = sensors_list_get_api_from_handle(handle);





        if (!api) {

                ALOGE("%s: unable to find handle!", __func__);

                return -1;

        }





        if (api->activate(api, enabled) < 0)

                return -1;





        return 0;

}

[/mw_shl_code]



sensors_list.c

[mw_shl_code=java,true]struct sensor_api_t* sensors_list_get_api_from_handle(int handle)

{

        int i;

        for (i = 0; i < number_of_sensors; i++)

                if (sensors.handle == handle)

                        return sensor_apis;

        return NULL;

}[/mw_shl_code]



比如BMA150的handle就是SENSOR_ACCELEROMETER_HANDLE,通过简单的匹配后,就能找到对应的sensors_api[x],然后执行active也就是bma150_input_activate函数,有兴趣就简单看一下代码,大体意思就是打开驱动获取句柄,然后组装给相关参数。



至此SensorDevice的大体工作也就完成了,总结就是成功获取HAL后,对每个传感器执行activate操作。



3.服务开启之路(2)

之所分(1)(2)是觉得SensorDevice部分可以单独成一部分,毕竟多数是在跟HAL在交互,这部分将分析完服务部分。

回头看SensorService::onFirstRef()



[mw_shl_code=java,true]void SensorService::onFirstRef()

{

    ALOGD("nuSensorService starting...");



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



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



/**********************************

检测SensorDevice执行是否成功,所获取的数据是否有效。

>status_t SensorDevice::initCheck() const {

    return mSensorDevice && mSensorModule ? NO_ERROR : NO_INIT;

}

**********************************/

        sensor_t const* list;

        ssize_t count = dev.getSensorList(&list);

/* 执行与(1)中sensors_list_get一样的工作 */

        if (count > 0) {

            ssize_t orientationIndex = -1;

            bool hasGyro = false;

            uint32_t virtualSensorsNeeds =

                    (1<<SENSOR_TYPE_GRAVITY) |

                    (1<<SENSOR_TYPE_LINEAR_ACCELERATION) |

                    (1<<SENSOR_TYPE_ROTATION_VECTOR);



            mLastEventSeen.setCapacity(count);

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

                registerSensor( new HardwareSensor(list) );

                switch (list.type) {

                    case SENSOR_TYPE_ORIENTATION:

                        orientationIndex = i;

                        break;

                    case SENSOR_TYPE_GYROSCOPE:

                        hasGyro = true;

                        break;

                    case SENSOR_TYPE_GRAVITY:

                    case SENSOR_TYPE_LINEAR_ACCELERATION:

                    case SENSOR_TYPE_ROTATION_VECTOR:

                        virtualSensorsNeeds &= ~(1<<list.type);

                        break;

                }

            }

/* 遍历查看SENSOR HAL都支持哪些类型的传感器 */



            // 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) {

                // Always instantiate Android's virtual sensors. Since they are

                // instantiated behind sensors from the HAL, they won't

                // interfere with applications, unless they looks specifically

                // for them (by name).



                registerVirtualSensor( new RotationVectorSensor() );

                registerVirtualSensor( new GravitySensor(list, count) );

                registerVirtualSensor( new LinearAccelerationSensor(list, count) );



                // these are optional

                registerVirtualSensor( new OrientationSensor() );

                registerVirtualSensor( new CorrectedGyroSensor(list, count) );



                // virtual debugging sensors...

                char value[PROPERTY_VALUE_MAX];

                property_get("debug.sensors", value, "0");

                if (atoi(value)) {

                    registerVirtualSensor( new GyroDriftSensor() );

                }

            } else if (orientationIndex != -1) {

                // If we don't have a gyro but have a orientation sensor from

                // elsewhere, we can compute rotation vector from that.

                // (Google Maps expects rotation vector sensor to exist.)



                registerVirtualSensor( &RotationVectorSensor2::getInstance() );

            }



            // build the sensor list returned to users

            mUserSensorList = mSensorList;

            if (hasGyro &&

                    (virtualSensorsNeeds & (1<<SENSOR_TYPE_ROTATION_VECTOR))) {

                // if we have the fancy sensor fusion, and it's not provided by the

                // HAL, use our own (fused) orientation sensor by removing the

                // HAL supplied one form the user list.

                if (orientationIndex >= 0) {

                    mUserSensorList.removeItemsAt(orientationIndex);

                }

            }



            run("SensorService", PRIORITY_URGENT_DISPLAY);

            mInitCheck = NO_ERROR;

        }

    }

}

[/mw_shl_code]



从上面可以看出,如果传感器中有SENSOR_TYPE_GYROSCOPE类型的话,也就是陀螺仪(高端传感器),会定义hasGyro,从而注册多个虚拟传感器,blablabla……

最后会触发一个重要动作:run。

回头查看SensorService类的定义:



[mw_shl_code=java,true]从上面可以看出,如果传感器中有SENSOR_TYPE_GYROSCOPE类型的话,也就是陀螺仪(高端传感器),会定义hasGyro,从而注册多个虚拟传感器,blablabla……



最后会触发一个重要动作:run。



回头查看SensorService类的定义:

[/mw_shl_code]



发现SensorService是继承了Thread的。

那么run的工作实际是启动了线程,threadLoop:



[mw_shl_code=java,true]bool SensorService::threadLoop()

{

    ALOGD("nuSensorService thread starting...");



    const size_t numEventMax = 16;

    const size_t minBufferSize = numEventMax + numEventMax * mVirtualSensorList.size();

    sensors_event_t buffer[minBufferSize];

    sensors_event_t scratch[minBufferSize];

    SensorDevice& device(SensorDevice::getInstance());

    const size_t vcount = mVirtualSensorList.size();



    ssize_t count;

    do {

        count = device.poll(buffer, numEventMax);

        if (count<0) {

            ALOGE("sensor poll failed (%s)", strerror(-count));

            break;

        }



...

}[/mw_shl_code]



发现这个线程会一直执行poll操作,这个操作是什么呢?还记得“服务开启之路(1)”中提到的吗?

[mw_shl_code=java,true]mSensorDevice->poll = sensors_module_poll;[/mw_shl_code]



是在HAL中的函数,最终指向sensors_module_poll ( DASH/sensors_module.c )

[mw_shl_code=java,true]static int sensors_module_poll(struct sensors_poll_device_t *dev,

                               sensors_event_t* data, int count)

{

        int ret;



        while ((ret = sensors_fifo_get_all(data, count)) == 0)

                ;



        return ret;

}[/mw_shl_code]



( DASH/sensors_fifo.c )

[mw_shl_code=java,true]void sensors_fifo_put(sensors_event_t *data)

{

        pthread_mutex_lock(&sensors_fifo.mutex);



        if (sensors_fifo.fifo_i < FIFO_LEN)

                sensors_fifo.fifo[sensors_fifo.fifo_i++] = *data;



        pthread_cond_broadcast(&sensors_fifo.data_cond);

        pthread_mutex_unlock(&sensors_fifo.mutex);

}



int sensors_fifo_get_all(sensors_event_t *data, int len)

{

        int i;



        /* This function deliberately drops all packets above len. */

        pthread_mutex_lock(&sensors_fifo.mutex);

        pthread_cond_wait(&sensors_fifo.data_cond, &sensors_fifo.mutex);



        for (i = 0; (i < sensors_fifo.fifo_i) && (i < len); i++)

                data = sensors_fifo.fifo;

        sensors_fifo.fifo_i = 0;

        pthread_mutex_unlock(&sensors_fifo.mutex);



        return i;

}[/mw_shl_code]



上边的函数用到了线程等待,有兴趣的可以去百度,很好理解,就是两个线程等待一个变量data_cond,sensors_fifo_put在放置完data后会释放掉data_cond,而sensors_fifo_get_all在data_cond释放之前会一直进行等待。

继续向前跟踪sensors_fifo_put ( DASH/sensors/bma150_input.c ):



[mw_shl_code=java,true]static void *bma150_input_read(void *arg)

{

        struct sensor_api_t *s = arg;

        struct sensor_desc *d = container_of(s, struct sensor_desc, api);

        struct input_event event;

        int fd = d->select_worker.get_fd(&d->select_worker);

        sensors_event_t data;



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

        while (read(fd, &event, sizeof(event)) > 0) {

                switch (event.type) {

                case EV_ABS:

                        switch (event.code) {

                        case ABS_X:

                                d->current_data[0] = ev2grav(event.value);

                                break;



                        case ABS_Y:

                                d->current_data[1] = ev2grav(event.value);

                                break;



                        case ABS_Z:

                                d->current_data[2] = ev2grav(event.value);

                                break;



                        case ABS_MISC:

                        default:

                                break;

                        }

                        break;



                case EV_SYN:



                        data.acceleration.x = (d->neg_x ? -d->current_data[d->axis_x] :

                                                           d->current_data[d->axis_x]);

                        data.acceleration.y = (d->neg_y ? -d->current_data[d->axis_y] :

                                                           d->current_data[d->axis_y]);

                        data.acceleration.z = (d->neg_z ? -d->current_data[d->axis_z] :

                                                           d->current_data[d->axis_z]);

                        data.acceleration.status = SENSOR_STATUS_ACCURACY_HIGH;



                        data.sensor = bma150_input.sensor.handle;

                        data.type = bma150_input.sensor.type;

                        data.version = bma150_input.sensor.version;

                        data.timestamp = get_current_nano_time();



                        sensors_fifo_put(&data);



                        goto exit;



                default:

                        goto exit;

                }

        }



exit:

        return NULL;

}[/mw_shl_code]



上述函数很好理解,首先取得此传感器的内核驱动句柄,然后等待此句柄输出信息,当取得信息后,对信息进行解析与再封装,最终写入到data中。那么bma150_input_read又是谁来调用呢?答案在此传感器的初始化过程中:

[mw_shl_code=java,true]static int bma150_input_init(struct sensor_api_t *s)

{

        struct sensor_desc *d = container_of(s, struct sensor_desc, api);

        int fd;

        bma150_input_read_config(d);



        /* check for availablity */

        fd = open_input_dev_by_name(BMA150_INPUT_NAME, O_RDONLY | O_NONBLOCK);

        if (fd < 0) {

                ALOGE("%s: unable to find %s input device!\n", __func__,

                        BMA150_INPUT_NAME);

                return -1;

        }

        d->rate_path = bma150_get_rate_path(fd);

        close(fd);



        sensors_select_init(&d->select_worker, bma150_input_read, s, -1);

        return 0;

}[/mw_shl_code]



可能现在会有迷惑,这个bma150_input_init是什么时候启动的呢?这是问题1,问题2是sensors_select_init是怎么吧bma150_input_read启动起来的?



下面一次解决,问题1:

[mw_shl_code=java,true]static struct sensor_desc bma150_input = {

...

        .api = {

                init: bma150_input_init,

                activate: bma150_input_activate,

                set_delay: bma150_input_fw_delay,

                close: bma150_input_close

        },

...

};[/mw_shl_code]



bma150_input_init被注册到api->init.

( DASH/sensors_module.c )



[mw_shl_code=java,true]static int sensors_module_open(const struct hw_module_t* module, const char* id, struct hw_device_t** device)

{

        ...

        sensors_list_foreach_api(sensors_init_iterator, NULL);



        return 0;

}



static int sensors_init_iterator(struct sensor_api_t* api, void *arg)

{

        return api->init(api);

}

[/mw_shl_code]



( DASH/sensors_list.c )

[mw_shl_code=java,true]void sensors_list_foreach_api(int (*f)(struct sensor_api_t* api, void* arg),

                              void *arg)

{

        int i;

        for (i = 0; i < number_of_sensors; i++)

                if (f(sensor_apis, arg) != SENSOR_OK) {

                        sensors_list_deregister(sensor_apis);

                        /* need to revisit this position after deregister */

                        --i;

                }

}[/mw_shl_code]



遍历所有注册过的传感器,执行其api->init. 问题1解决完毕。

问题2:

( DASH/sensors_select.c )



[mw_shl_code=java,true]void sensors_select_init(struct sensors_select_t* s,

                        void* (*select_func)(void *arg), void* arg, int fd)

{

        s->suspend = sensors_select_suspend;

        s->resume = sensors_select_resume;

        s->destroy = sensors_select_destroy;

        s->set_delay = sensors_select_set_delay;

        s->set_fd = sensors_select_set_fd;

        s->get_fd = sensors_select_get_fd;

        s->select_callback = select_func;

        s->arg = arg;

        s->fd = fd;

        s->delay = 0;



        if (pipe(s->ctl_fds) < 0)

                ALOGE("%s: pipe failed: %s", __func__, strerror(errno));



        sensors_worker_init(&s->worker, sensors_select_callback, s);

        s->worker.set_delay(&s->worker, 0);

        pthread_mutex_init(&s->fd_mutex, NULL);

}[/mw_shl_code]



bma150_init_read为该函数的第二个参数,即select_func, 组装给了s->select_callback。送去sensors_worker_init函数( DASH/sensors_worker.c ):

[mw_shl_code=java,true]void sensors_worker_init(struct sensors_worker_t* worker,

                        void* (*work_func)(void *arg), void* arg)

{

        worker->mode = SENSOR_SLEEP;



        worker->poll_callback = work_func;

        worker->suspend = sensors_worker_suspend;

        worker->resume = sensors_worker_resume;

        worker->destroy = sensors_worker_destroy;

        worker->set_delay = sensors_worker_set_delay;

        worker->delay_ns = 200000000L;

        worker->arg = arg;



        pthread_mutex_init (&worker->mode_mutex, NULL);

        pthread_cond_init (&worker->suspend_cond, NULL);

        pthread_create(&worker->worker_thread_id, NULL,

                       sensors_worker_internal_worker, (void*) worker);

}[/mw_shl_code]



该函数第二个参数为sensors_select_init所送入的sensors_select_callback, 暂放此处,稍后分析,只记得他化身work_func组装给了worker->poll_callback, 最终被当作参数送入新开启的线程sensors_worker_internal_worker中:

[mw_shl_code=java,true]static void *sensors_worker_internal_worker(void *arg)

{

        struct sensors_worker_t* worker = (struct sensors_worker_t*) arg;

        enum sensors_worker_mode mode;



        while (1) {

                pthread_mutex_lock(&worker->mode_mutex);

                mode = worker->mode;

                pthread_mutex_unlock(&worker->mode_mutex);



                switch (mode) {

                case SENSOR_DESTROY:

                        goto exit;



                case SENSOR_SLEEP:

                        pthread_mutex_lock(&worker->mode_mutex);

                        pthread_cond_wait(&worker->suspend_cond, &worker->mode_mutex);

                        pthread_mutex_unlock(&worker->mode_mutex);

                        break;



                default:

                        worker->poll_callback(worker->arg);

                        break;

                }

                if (worker->delay_ns)

                        sensor_nano_sleep(worker->delay_ns);

        }

exit:

        return NULL;

}[/mw_shl_code]



这是一个工作线程,用来处理不同模式的不同动作,这些不同的模式由worker->mode来进行控制,同时worker->mode又由互斥锁worker->mode_mutex进行保护来防止读写冲突。此mode实际有三种:

SENSOR_SLEEP



SENSOR_RUNNING



SENSOR_DESTROY



分别对应三个工作函数:

sensors_worker_suspend



sensors_worker_resume



sensors_worker_destroy



这三个工作函数又在sensors_worker_init初始化时分别分配给了:

worker->suspend



worker->resume



worker->destroy



综上, sensors_worker_internal_worker中default即为SENSOR_RUNNING,其他状态暂不说明,先解决了这个RUNNING。在第一次初始化的时候默认给出的是SLEEP状态,则会等待suspend_cond变量,试看谁在使用这个变量。在sensors_worker.c中不难发现,在resume和destroy函数中,当前一状态为SLEEP时,会释放suspend_cond:



[mw_shl_code=java,true]static void sensors_worker_resume(struct sensors_worker_t* worker)

{

        enum sensors_worker_mode prev_mode;



        pthread_mutex_lock(&worker->mode_mutex);

        prev_mode = worker->mode;

        worker->mode = SENSOR_RUNNING;



        if (prev_mode == SENSOR_SLEEP)

                pthread_cond_broadcast(&worker->suspend_cond);



        pthread_mutex_unlock(&worker->mode_mutex);

}



static void sensors_worker_destroy(struct sensors_worker_t* worker)

{

        enum sensors_worker_mode prev_mode;



        pthread_mutex_lock(&worker->mode_mutex);

        prev_mode = worker->mode;

        worker->mode = SENSOR_DESTROY;



        if (prev_mode == SENSOR_SLEEP)

                pthread_cond_broadcast(&worker->suspend_cond);



        pthread_mutex_unlock(&worker->mode_mutex);

        pthread_join(worker->worker_thread_id, NULL);

}[/mw_shl_code]



两者不同之处在于,resume会让传感器的状态切换到RUNNING,而destroy会使其切换至DESTROY状态,从而导致线程sensors_worker_internal_worker退出,传感器工作停止。问题又来了,初始化的状态是SLEEP,什么时候?谁?来激活这个工作线程呢?问题的答案在bma150_input.c ( DASH/bma150_input.c ):

[mw_shl_code=java,true]static int bma150_input_activate(struct sensor_api_t *s, int enable)

{

        struct sensor_desc *d = container_of(s, struct sensor_desc, api);

        int fd = d->select_worker.get_fd(&d->select_worker);



        /* suspend/resume will be handled in kernel-space */

        if (enable && (fd < 0)) {

                fd = open_input_dev_by_name(BMA150_INPUT_NAME,

                        O_RDONLY | O_NONBLOCK);

                if (fd < 0) {

                        ALOGE("%s: failed to open input dev %s\n", __func__,

                                BMA150_INPUT_NAME);

                        return -1;

                }

                d->select_worker.set_fd(&d->select_worker, fd);

                d->select_worker.resume(&d->select_worker);

        } else if (!enable && (fd > 0)) {

                d->select_worker.set_fd(&d->select_worker, -1);

                d->select_worker.suspend(&d->select_worker);

        }



        return 0;

}[/mw_shl_code]



前面只是一代而过activate函数,没有进行分析,回头来看,原来resume与suspend操作就在这里,当未初始化且要求开启时,寻找驱动句柄,并设置句柄,然后执行resume操作,从而使sensors_worker_internal_worker工作线程开启,执行worker->poll_callback函数。在回去之前还是把avtivate看完,除了上边说的开启的情况,就是关闭的情况。当驱动句柄有效,且要求关闭时,设置句柄为-1(无效),并执行suspend操作,使传感器进入SLEEP状态,继续等待suspend_cond变量。

在执行poll_callback时候一层层向回摸吧,worker->arg就等于sensors_worker_init所带入的arg。

worker->poll_back = (work_func);

(work_func) = sensors_select_callback;

( DASH/sensors_select.c )



[mw_shl_code=java,true]static void *sensors_select_callback(void *arg)

{

        fd_set readfds;

        int ret;

        struct sensors_select_t *s = arg;

        int maxfd;



        LOCK(&s->fd_mutex);

        maxfd = s->ctl_fds[0] > s->fd ? s->ctl_fds[0] : s->fd;

        FD_ZERO(&readfds);

        FD_SET(s->ctl_fds[0], &readfds);

        FD_SET(s->fd, &readfds);

        UNLOCK(&s->fd_mutex);

        ret = select(maxfd + 1, &readfds, NULL, NULL, NULL);



        if (ret < 0) {

                ALOGE("%s: select failed!\n", __func__);

        } else if (ret) {

                if (FD_ISSET(s->ctl_fds[0], &readfds)) {

                        read(s->ctl_fds[0], &ret, sizeof(ret));

                } else if (FD_ISSET(s->fd, &readfds)) {

                        LOCK(&wrapper_mutex);

                        LOCK(&s->fd_mutex);

                        if (s->fd >= 0)

                            s->select_callback(s->arg);

                        UNLOCK(&s->fd_mutex);

                        UNLOCK(&wrapper_mutex);

                }

        }

        return NULL;

}[/mw_shl_code]



一层层的设置执行,最终执行到s->select_callback,参数为s->arg。

select_callback = (select_func);

(select_func) = bma150_input_read;

终于执行到了这一步,问题2解决。

总结: 一切的一切始于SensorService的threadLoop,他执行了一个poll操作,从而层层调用到SensorHAL,HAL经过初始化及激活后,开启了一个工作线程。当工作线程处于RUNNING(default)状态时,会无限循环来读取硬件驱动句柄所发出的数据,然后经过解析重构发回到SensorService中。至此,服务成功开启,从驱动中源源不断的获取数据。这个SensorService的threadLoop工作还有很多,大体概括就是对获取到的驱动数据进行分类,处理,最后发送……blablabla,这里边涉及到很多专业知识,也就不便再进行分析。总之SensorHAL的运作流程即使如此。





转帖呦

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
阅读android有关sensor的源码总结
VC挂线程钩子的小经验
CloseHandle 函数说明
为Android设备而生的Sensor Hubs终于来了
MATLAB函数画图
gdb动态库延迟断点及线程/进程创建相关事件处理(上)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服