Android Sensor HAL层分析_sensor hal service-程序员宅基地

技术标签: Hal  android  sensor  

   SensorService在SystemServer进程中启动。

/frameworks/base/ervices/java/com/android/server/SystemServer.java

private void startBootstrapServices() {  
   ...  
   startSensorService();  
}  

  startSensorService是一个native函数,其具体实现在com_android_server_SystemServer.cpp的android_server_SystemServer_startSensorService函数中。

/frameworks/base/services/core/jni/com_android_server_SystemServer.cpp

static void android_server_SystemServer_startSensorService(JNIEnv* /* env */, jobject /* clazz */) {  
    char propBuf[PROPERTY_VALUE_MAX];  
    property_get("system_init.startsensorservice", propBuf, "1");  
    if (strcmp(propBuf, "1") == 0) {  
        // Start the sensor service  
        SensorService::instantiate();  
    }  
}  

  SensorService::instantiate()的instantiate函数定义在BinderService.h中,目的在于向ServiceManager注册SensorService组件。new SERVICE()参数的传入最终结果是创建SensorService的一个强引用。

/frameworks/native/include/binder/BinderService.h

static void instantiate() { publish(); } 

/frameworks/native/include/binder/BinderService.h


static status_t publish(bool allowIsolated = false) {  
        sp<IServiceManager> sm(defaultServiceManager());  
        return sm->addService(  
                String16(SERVICE::getServiceName()),  
                new SERVICE(), allowIsolated);  
}  

  onFirstRef函数是RefBase的一个空实现,SensorService继承自RefBase,onFirstRef在第一次被强指针引用时调用,首先是获得一个SensorDevice单例对象。

/frameworks/native/services/sensorservice/SensorService.cpp

void SensorService::onFirstRef()  
{  
    ALOGD("nuSensorService starting...");  
    SensorDevice& dev(SensorDevice::getInstance()); 
    ...
}

  看看SensorDevice的默认构造函数:

/frameworks/native/services/sensorservice/SensorDevice.cpp

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_1(&mSensorModule->common, &mSensorDevice);  

        ALOGE_IF(err, "couldn't open device for module %s (%s)",  
                SENSORS_HARDWARE_MODULE_ID, strerror(-err));  

        if (mSensorDevice) {  
            if (mSensorDevice->common.version == SENSORS_DEVICE_API_VERSION_1_1 ||  
                mSensorDevice->common.version == SENSORS_DEVICE_API_VERSION_1_2) {  
                ALOGE(">>>> WARNING <<< Upgrade sensor HAL to version 1_3");  
            }  

            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(  
                        reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),  
                        list[i].handle, 0);  
            }  
        }  
    }  
}  

  hw_get_module是jni层获取HAL层module的接口函数,原型为hareware.c中的:int hw_get_module(const char *id, const struct hw_module_t **module),第一个参数为硬件模块的id,第二个参数指向硬件模块对应的hw_module_t结构体地址。

/hardware/libhardware/hardware.c

int hw_get_module(const char *id, const struct hw_module_t **module)
{
    return hw_get_module_by_class(id, NULL, module);
}

/hardware/libhardware/hardware.c

int hw_get_module_by_class(const char *class_id, const char *inst,
                           const struct hw_module_t **module)
{
    int i = 0;
    char prop[PATH_MAX] = {
   0};
    char path[PATH_MAX] = {
   0};
    char name[PATH_MAX] = {
   0};
    char prop_name[PATH_MAX] = {
   0};


    if (inst)
        snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
    else
        strlcpy(name, class_id, PATH_MAX);//class_id拷贝到name

    /*
     * Here we rely on the fact that calling dlopen multiple times on
     * the same .so will simply increment a refcount (and not load
     * a new copy of the library).
     * We also assume that dlopen() is thread-safe.
     */

    /* First try a property specific to the class and possibly instance */
    //prop_name为ro.hardware.(name),SensorService传下来的class_id为sensors,则prop_name为ro.hardware.sensors
    snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);
    //获取prop_name的属性值,保存在prop中
    if (property_get(prop_name, prop, NULL) > 0) {
    //输出固定的文件名格式到path中
        if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
   //
            goto found;
        }
    }

    /* Loop through the configuration variants looking for a module */
    for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {
        if (property_get(variant_keys[i], prop, NULL) == 0) {
            continue;
        }
        if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
            goto found;
        }
    }

    /* Nothing found, try the default */
    if (hw_module_exists(path, sizeof(path), name, "default") == 0) {
        goto found;
    }

    return -ENOENT;

found:
    /* load the module, if this fails, we're doomed, and we should not try
     * to load a different variant. */
    return load(class_id, path, module);
}

/hardware/libhardware/hardware.c

//紧接上面,32位下生成/vendor/lib/hw.sensors.属性值.so或/system/lib/hw.sensors.属性值.so,64位下生成/vendor/lib64/hw.sensors.属性值.so或/system/lib64/hw.sensors.属性值.so
static int hw_module_exists(char *path, size_t path_len, const char *name,
                            const char *subname)
{
    snprintf(path, path_len, "%s/%s.%s.so",
             HAL_LIBRARY_PATH2, name, subname);
    if (access(path, R_OK) == 0)
        return 0;

    snprintf(path, path_len, "%s/%s.%s.so",
             HAL_LIBRARY_PATH1, name, subname);
    if (access(path, R_OK) == 0)
        return 0;

    return -ENOENT;
}

/hardware/libhardware/hardware.c

//尝试去加载上面路径的so文件
static int load(const char *id,
        const char *path,
        const struct hw_module_t **pHmi)
{
    int status = -EINVAL;
    void *handle = NULL;
    struct hw_module_t *hmi = NULL;

    /*
     * load the symbols resolving undefined symbols before
     * dlopen returns. Since RTLD_GLOBAL is not or'd in with
     * RTLD_NOW the external symbols will not be global
     */
    //dlopen以暂缓决定模式打开指定的动态连接库文件,并返回一个句柄给调用进程
    handle = dlopen(path, RTLD_NOW);
    if (handle == NULL) {
        char const *err_str = dlerror();
        ALOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
        status = -EINVAL;
        goto done;
    }

    /* Get the address of the struct hal_module_info. */
    //dlsym通过句柄和连接符名称获取函数名或者变量名,返回符号的地址
    const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
    hmi = (struct hw_module_t *)dlsym(handle, sym);
    if (hmi == NULL) {
        ALOGE("load: couldn't find symbol %s", sym);
        status = -EINVAL;
        goto done;
    }

    /* Check that the id matches */
    if (strcmp(id, hmi->id) != 0) {
        ALOGE("load: id=%s != hmi->id=%s", id, hmi->id);
        status = -EINVAL;
        goto done;
    }

    hmi->dso = handle;

    /* success */
    status = 0;

    done:
    if (status != 0) {
        hmi = NULL;
        if (handle != NULL) {
            dlclose(handle);
            handle = NULL;
        }
    } else {
        ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",
                id, path, *pHmi, handle);
    }

    *pHmi = hmi;

    return status;
}

  硬件抽象层模块中总会定义一个HAL_MODULE_INFO_SYM_AS_STR的符号,HAL_MODULE_INFO_SYM_AS_STR在宏定义中被定义为“HMI”,在这里HAL_MODULE_INFO_SYM_AS_STR是struct sensors_module_t的变量,struct sensors_module_t第一个成员common为struct hw_module_t类型。因为common成员和HAL_MODULE_INFO_SYM_AS_STR首地址相同,所以load函数末尾可以安全地将第二个参数的地址指向这个符号的地址。所以SensorDevice中类型为struct sensors_module_t*的mSensorModule成员指向了HAL_MODULE_INFO_SYM_AS_STR符号的地址。

/hardware/libhardware/include/hardware/sensors.h

struct sensors_module_t {
    struct hw_module_t common;

    /**
     * Enumerate all available sensors. The list is returned in "list".
     * @return number of sensors in the list
     */
    int (*get_sensors_list)(struct sensors_module_t* module,
            struct sensor_t const** list);

    /**
     *  Place the module in a specific mode. The following modes are defined
     *
     *  0 - Normal operation. Default state of the module.
     *  1 - Loopback mode. Data is injected for the the supported
     *      sensors by the sensor service in this mode.
     * @return 0 on success
     *         -EINVAL if requested mode is not supported
     *         -EPERM if operation is not allowed
     */
    int (*set_operation_mode)(unsigned int mode);
};

  此时,sensor模块的so已加载完成。回到SensorDevice的构造函数中,接着调用sensors_open_1函数打开sensor设备。sensors_open_1没有在SensorDevice.cpp中实现,而是在HAL层实现。

/frameworks/native/services/sensorservice/SensorDevice.cpp

...
if (mSensorModule) {
        err = sensors_open_1(&mSensorModule->common, &mSensorDevice);
        ...

/hardware/libhardware/include/hardware/sensors.h

static inline int sensors_open_1(const struct hw_module_t* module,
        sensors_poll_device_1_t** device) {
    return module->methods->open(module,
            SENSORS_HARDWARE_POLL, (struct hw_device_t**)device);
}

  该函数接收sensors_module_t的common成员的指针(struct hw_module_t*类型)作为第一个参数,调用参数的struct hw_module_methods_t*类型的methods成员的唯一函数指针成员,即open函数。其中,SENSORS_HARDWARE_POLL在宏定义被定义为“poll”。

/hardware/libhardware/include/hardware/hardware.h

typedef struct hw_module_t {
    /** tag must be initialized to HARDWARE_MODULE_TAG */
    uint32_t tag;

    /**
     * The API version of the implemented module. The module owner is
     * responsible for updating the version when a module interface has
     * changed.
     *
     * The derived modules such as gralloc and audio own and manage this field.
     * The module user must interpret the version field to decide whether or
     * not to inter-operate with the supplied module implementation.
     * For example, SurfaceFlinger is responsible for making sure that
     * it knows how to manage different versions of the gralloc-module API,
     * and AudioFlinger must know how to do the same for audio-module API.
     *
     * The module API version should include a major and a minor component.
     * For example, version 1.0 could be represented as 0x0100. This format
     * implies that versions 0x0100-0x01ff are all API-compatible.
     *
     * In the future, libhardware will expose a hw_get_module_version()
     * (or equivalent) function that will take minimum/maximum supported
     * versions as arguments and would be able to reject modules with
     * versions outside of the supplied range.
     */
    uint16_t module_api_version;
#define version_major module_api_version
    /**
     * version_major/version_minor defines are supplied here for temporary
     * source code compatibility. They will be removed in the next version.
     * ALL clients must convert to the new version format.
     */

    /**
     * The API version of the HAL module interface. This is meant to
     * version the hw_module_t, hw_module_methods_t, and hw_device_t
     * structures and definitions.
     *
     * The HAL interface owns this field. Module users/implementations
     * must NOT rely on this value for version information.
     *
     * Presently, 0 is the only valid value.
     */
    uint16_t hal_api_version;
#define version_minor hal_api_version

    /** Identifier of module */
    const char *id;

    /** Name of this module */
    const char *name;

    /** Author/owner/implementor of the module */
    const char *author;

    /** Modules methods */
    struct hw_module_methods_t* methods;

    /** module's dso */
    void* dso;

#ifdef __LP64__
    uint64_t reserved[32-7];
#else
    /** padding to 128 bytes, reserved for future use */
    uint32_t reserved[32-7];
#endif

} hw_module_t;

/hardware/libhardware/include/hardware/hardware.h

typedef struct hw_module_methods_t {
    /** Open a specific device */
    int (*open)(const struct hw_module_t* module, const char* id,
            struct hw_device_t** device);

} hw_module_methods_t;

  sensors.h为我们提供了HAL层的接口,实现部分则在sensors.c或sensors.cpp完成。sensors.cpp定义了一个hw_module_methods_t类型的变量sensors_module_methods,并且指定open函数的实现为open_sensors函数。

/hardware/akm/AK8975_FS/libsensors/Sensors.cpp

static struct hw_module_methods_t sensors_module_methods = {
        .open = open_sensors
};

/hardware/akm/AK8975_FS/libsensors/Sensors.cpp

static int open_sensors(const struct hw_module_t* module, const char* id,
                        struct hw_device_t** device)
{
    UNUSE(id);

    LOGD("open_sensors()");
    int status = -EINVAL;
    sensors_poll_context_t *dev = new sensors_poll_context_t();

    if (!dev->isValid()) {
        ALOGE("Failed to open the sensors");
        return status;
    }

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

    dev->device.common.tag = HARDWARE_DEVICE_TAG;
    dev->device.common.version  = SENSORS_DEVICE_API_VERSION_1_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;

    *device = &dev->device.common;
    status = 0;

    return status;
}

  open_sensors函数首先new了一个sensors_poll_context_t对象。

/hardware/akm/AK8975_FS/libsensors/Sensors.cpp

struct sensors_poll_context_t {
    struct sensors_poll_device_t device; // must be first

    sensors_poll_context_t();
    ~sensors_poll_context_t();
    int activate(int handle, int enabled);
    int setDelay(int handle, int64_t ns);
    int setDelay_sub(int handle, int64_t ns);
    int pollEvents(sensors_event_t* data, int count);

private:
    enum {
        acc          = 0,
        akm          = 1,
        numSensorDrivers,
        numFds,
    };

    static const size_t wake = numFds - 1;
    static const char WAKE_MESSAGE = 'W';
    struct pollfd mPollFds[numFds];
    int mWritePipeFd;
    SensorBase* mSensors[numSensorDrivers];

    /* These function will be different depends on
     * which sensor is implemented in AKMD program.
     */
    int handleToDriver(int handle);
    int proxy_enable(int handle, int enabled);
    int proxy_setDelay(int handle, int64_t ns);
};

/hardware/akm/AK8975_FS/libsensors/Sensors.cpp

sensors_poll_context_t::sensors_poll_context_t()
{
#ifdef SENSORHAL_ACC_ADXL346
    mSensors[acc] = new AdxlSensor();
#endif
#ifdef SENSORHAL_ACC_KXTF9
    mSensors[acc] = new KionixSensor();
#endif
    mPollFds[acc].fd = mSensors[acc]->getFd();
    mPollFds[acc].events = POLLIN;
    mPollFds[acc].revents = 0;

    mSensors[akm] = new AkmSensor();
    mPollFds[akm].fd = mSensors[akm]->getFd();
    mPollFds[akm].events = POLLIN;
    mPollFds[akm].revents = 0;

    int wakeFds[2];
    int result = pipe(wakeFds);
    ALOGE_IF(result<0, "error creating wake pipe (%s)", strerror(errno));
    fcntl(wakeFds[0], F_SETFL, O_NONBLOCK);
    fcntl(wakeFds[1], F_SETFL, O_NONBLOCK);
    mWritePipeFd = wakeFds[1];

    mPollFds[wake].fd = wakeFds[0];
    mPollFds[wake].events = POLLIN;
    mPollFds[wake].revents = 0;
}

  sensors_poll_context_t的构造函数主要工作是使用poll监听AdxlSensor,KionixSensor和创建的管道读端的POLLIN事件。
  回到open_sensors函数,接着对sensors_poll_context_t的成员作初始化。sensors_poll_context_t的首个成员为sensors_poll_device_t,而sensors_poll_device_t的首个成员是hw_device_t,这三个类型的变量首地址是相同的,所以它们的指针可以相互安全地进行转换。最后把传下来的第二个指针参数指向已被初始化的hw_device_t成员地址。
  hw_get_module和sensors_open_1这两个函数保存了HAL层对应的hw_module_t类型和hw_device_t类型的指针。再次返回SenosrDevice的构造函数,接下来用get_sensors_list去获取sensor的列表。

/frameworks/native/services/sensorservice/SensorDevice.cpp

...
sensor_t const* list;
ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);
mActivationCount.setCapacity(count);
...

  同样地,get_sensors_list方法的设置出现在HMI符号中,然后调到sensors__get_sensors_list方法,最后获取到struct sensor_t数组,并使传下来的第二个参数指向该数组的地址,其中sensor_t的作用是记录sensor的信息参数,一个sensor设备对应一个sensor_t结构体。

/hardware/akm/AK8975_FS/libsensors/Sensors.cpp

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 = "AKM Sensor module",
                .author = "Asahi Kasei Microdevices",
                .methods = &sensors_module_methods,
                .dso  = NULL,
                .reserved = {
   0},
        },
        .get_sensors_list = sensors__get_sensors_list,
};

/hardware/akm/AK8975_FS/libsensors/Sensors.cpp

static int sensors__get_sensors_list(struct sensors_module_t* module,
                                     struct sensor_t const** list)
{
        *list = sSensorList;
        return ARRAY_SIZE(sSensorList);
}

/hardware/akm/AK8975_FS/libsensors/Sensors.cpp

static const struct sensor_t sSensorList[] = {
        { "AK8975 3-axis Magnetic field sensor",
          "Asahi Kasei Microdevices",
          1,
          SENSORS_MAGNETIC_FIELD_HANDLE,
          SENSOR_TYPE_MAGNETIC_FIELD, 1228.8f,
          CONVERT_M, 0.35f, 10000, 0, 0, 0, 0, 0, 0, { } },
#ifdef SENSORHAL_ACC_ADXL346
        { "Analog Devices ADXL345/6 3-axis Accelerometer",
          "ADI",
          1, SENSORS_ACCELERATION_HANDLE,
          SENSOR_TYPE_ACCELEROMETER, (GRAVITY_EARTH * 16.0f),
          (GRAVITY_EARTH * 16.0f) / 4096.0f, 0.145f, 10000, 0, 0, 0, 0, 0, 0, { } },
        { "AK8975 Orientation sensor",
          "Asahi Kasei Microdevices",
          1, SENSORS_ORIENTATION_HANDLE,
          SENSOR_TYPE_ORIENTATION, 360.0f,
          CONVERT_O, 0.495f, 10000, 0, 0, 0, 0, 0, 0, { } }
#endif
#ifdef SENSORHAL_ACC_KXTF9
        { "Kionix KXTF9 3-axis Accelerometer",
          "Kionix",
          1, SENSORS_ACCELERATION_HANDLE,
          SENSOR_TYPE_ACCELEROMETER, (GRAVITY_EARTH * 2.0f),
          (GRAVITY_EARTH) / 1024.0f, 0.7f, 10000, 0, 0, 0, 0, 0, 0, { } },
        { "AK8975 Orientation sensor",
          "Asahi Kasei Microdevices",
          1, SENSORS_ORIENTATION_HANDLE,
          SENSOR_TYPE_ORIENTATION, 360.0f,
          CONVERT_O, 1.05f, 10000, 0, 0, 0, 0, 0, 0, { } }
#endif
};

  回到SensorDevice的构造函数中,最后一步是使用activate方法对上面sensor列表的sensor进行激活。同理,activate方法最终会调到sensors_poll_context_t::activate方法。

/hardware/akm/AK8975_FS/libsensors/Sensors.cpp

static int poll__activate(struct sensors_poll_device_t *dev,
        int handle, int enabled) {
    sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev;
    return ctx->activate(handle, enabled);
}

/hardware/akm/AK8975_FS/libsensors/Sensors.cpp

int sensors_poll_context_t::activate(int handle, int enabled) {
    int drv = handleToDriver(handle);
    int err;

    switch (handle) {
        case ID_A:
        case ID_M:
            /* No dependencies */
            break;

        case ID_O:
            /* These sensors depend on ID_A and ID_M */
            mSensors[handleToDriver(ID_A)]->setEnable(ID_A, enabled);
            mSensors[handleToDriver(ID_M)]->setEnable(ID_M, enabled);
            break;

        default:
            return -EINVAL;
    }
    err = mSensors[drv]->setEnable(handle, enabled);

    if (enabled && !err) {
        const char wakeMessage(WAKE_MESSAGE);
        int result = write(mWritePipeFd, &wakeMessage, 1);
        ALOGE_IF(result<0, "error sending wake message (%s)", strerror(errno));
    }
    return err;
}

  下面以AdxlSensor为例进行说明:
  如果AdxlSensor没有被激活且enabled参数为1,只将mEnables加1。
  如果AdxlSensor已经被首次激活了,则往/sys/class/input/(input_name)/device/device/disable中写入“1”,将mEnable减1。注意到这里传下来的enabled参数为0,AdxlSensor构造函数中把mEnabled初始化为0,也就是说SensorDevice初始化时不会将相关Sensor使能,要使Sensor使能,需要应用层调到native层使能。

/hardware/akm/AK8975_FS/libsensors/AdxlSensor.cpp

int AdxlSensor::setEnable(int32_t handle, int enabled) {
    int err = 0;
    char buffer[2];

    /* handle check */
    if (handle != ID_A) {
        ALOGE("AdxlSensor: Invalid handle (%d)", handle);
        return -EINVAL;
    }

    buffer[0] = '\0';
    buffer[1] = '\0';

    if (mEnabled <= 0) {
        if(enabled) buffer[0] = '0';
    } else if (mEnabled == 1) {
        if(!enabled) buffer[0] = '1';
    }
    if (buffer[0] != '\0') {
        strcpy(&input_sysfs_path[input_sysfs_path_len], "disable");
        err = write_sys_attribute(input_sysfs_path, buffer, 1);
        if (err != 0) {
            return err;
        }
        ALOGD("AdxlSensor: Control set %s", buffer);
        setInitialState();
    }

    if (enabled) {
        mEnabled++;
        if (mEnabled > 32767) mEnabled = 32767;
    } else {
        mEnabled--;
        if (mEnabled < 0) mEnabled = 0;
    }
    ALOGD("AdxlSensor: mEnabled = %d", mEnabled);

    return err;
}

  AdxlSensor传给SensorBase构造函数的两个参数分别是NULL, ADXL_DATA_NAME,在宏定义被定义为”ADXL34x accelerometer”。之后调用openInput(ADXL_DATA_NAME)打开输入设备。

/hardware/akm/AK8975_FS/libsensors/SensorBase.cpp

SensorBase::SensorBase(
        const char* dev_name,
        const char* data_name)
    : dev_name(dev_name), data_name(data_name),
      dev_fd(-1), data_fd(-1)
{
    if (data_name) {
        data_fd = openInput(data_name);
    }
}

  openInput函数在/dev/input目录下查找设备名称。Linux内核提供了一个Input子系统,Input子系统会在/dev/input/路径下创建我们硬件输入设备的节点,一般情况下在我们的手机中这些节点是以eventXX来命名的,如event0,event1等等,可以利用EVIOCGNAME获取此事件结点名称。open(devname, O_RDONLY)打开了设备节点,strcpy(input_name, filename)将设备名拷贝到input_name中。
/hardware/akm/AK8975_FS/libsensors/SensorBase.cpp

int SensorBase::openInput(const char* inputName) {
    int fd = -1;
    const char *dirname = "/dev/input";
    char devname[PATH_MAX];
    char *filename;
    DIR *dir;
    struct dirent *de;
    dir = opendir(dirname);
    if(dir == NULL)
        return -1;
    strcpy(devname, dirname);
    filename = devname + strlen(devname);
    *filename++ = '/';
    while((de = readdir(dir))) {
        if(de->d_name[0] == '.' &&
                (de->d_name[1] == '\0' ||
                        (de->d_name[1] == '.' && de->d_name[2] == '\0')))
            continue;
        strcpy(filename, de->d_name);
        fd = open(devname, O_RDONLY);
        if (fd>=0) {
            char name[80];
            if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
                name[0] = '\0';
            }
            if (!strcmp(name, inputName)) {
                strcpy(input_name, filename);
                break;
            } else {
                close(fd);
                fd = -1;
            }
        }
    }
    closedir(dir);
    ALOGE_IF(fd<0, "couldn't find '%s' input device", inputName);
    return fd;
}

  这样,SensorDevice的构造函数便介绍完毕。
  回到SensorService的onFirstRef函数,SensorService继承自Thread,函数末尾调用run进入threadLoop方法。

/frameworks/native/services/sensorservice/SensorService.cpp

...
run("SensorService", PRIORITY_URGENT_DISPLAY);
...

  threadLoop方法中调用了SensorDevice::poll方法,mSensorEventBuffer是一个struct sensors_event_t数组。每个传感器的数据都由struct sensors_event_t表示。

/frameworks/native/services/sensorservice/SensorService.cpp

...
do {
        ssize_t count = device.poll(mSensorEventBuffer, numEventMax);
        if (count < 0) {
            ALOGE("sensor poll failed (%s)", strerror(-count));
            break;
        }
...

/hardware/libhardware/include/hardware/sensors.h

typedef struct sensors_event_t {
    /* must be sizeof(struct sensors_event_t) */
    int32_t version;

    /* sensor identifier */
    int32_t sensor;

    /* sensor type */
    int32_t type;

    /* reserved */
    int32_t reserved0;

    /* time is in nanosecond */
    int64_t timestamp;

    union {
        union {
            float           data[16];

            /* acceleration values are in meter per second per second (m/s^2) */
            sensors_vec_t   acceleration;

            /* magnetic vector values are in micro-Tesla (uT) */
            sensors_vec_t   magnetic;

            /* orientation values are in degrees */
            sensors_vec_t   orientation;

            /* gyroscope values are in rad/s */
            sensors_vec_t   gyro;

            /* temperature is in degrees centigrade (Celsius) */
            float           temperature;

            /* distance in centimeters */
            float           distance;

            /* light in SI lux units */
            float           light;

            /* pressure in hectopascal (hPa) */
            float           pressure;

            /* relative humidity in percent */
            float           relative_humidity;

            /* uncalibrated gyroscope values are in rad/s */
            uncalibrated_event_t uncalibrated_gyro;

            /* uncalibrated magnetometer values are in micro-Teslas */
            uncalibrated_event_t uncalibrated_magnetic;

            /* heart rate data containing value in bpm and status */
            heart_rate_event_t heart_rate;

            /* this is a special event. see SENSOR_TYPE_META_DATA above.
             * sensors_meta_data_event_t events are all reported with a type of
             * SENSOR_TYPE_META_DATA. The handle is ignored and must be zero.
             */
            meta_data_event_t meta_data;
        };

        union {
            uint64_t        data[8];

            /* step-counter */
            uint64_t        step_counter;
        } u64;
    };

    /* Reserved flags for internal use. Set to zero. */
    uint32_t flags;

    uint32_t reserved1[3];
} sensors_event_t;

  SensorDevice::poll函数最终会调到sensors_poll_context_t::pollEvents函数。

/frameworks/native/services/sensorservice/SensorDevice.cpp

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

  如果前面监听的Sensor描述符(AdxlSensor和KionixSensor)发生了POLLIN事件或者有未处理的事件,则调用readEvents去处理这些事件。readEvents返回值nb为读得的事件数量,count为传回上层的事件容量,data记录了sensors_event_t结构体数组的当前保存位置。每次读出事件后,都会对这三个变量作处理。
  如果还有剩余容量(count>0),则会抓住最后机会使用poll争取获得事件,nbEvents记录了每次进入pollEvents读到的事件总数量。若nbEvents大于0,poll的时间参数为0,表示立即返回;若nbEvents等于0,poll的时间参数为-1,表示一直阻塞到读取到事件。若此时有线程从管道唤醒poll,则会对唤醒事件作处理(实质就是使 mPollFds[wake]的revents恢复默认值)。若poll成功读取到事件且还有剩余容量,则再次进入pollEvents的主循环。
  第一次进入pollEvents函数时,由于还没有poll,mPollFds中的所有Sensor的fd都不会有变化,所以会阻塞在poll调用中,直到Sensor发生了事件或者有线程从管道将其唤醒。之后再次进入主循环调用readEvents读取Sensor事件(如果Sensor发生POLLIN事件的话),count没有满的情况下,然后再次进入poll函数,这样一直循环下去,直到poll没有事件返回且没有事件容量才会退出循环。

/hardware/akm/AK8975_FS/libsensors/Sensors.cpp

int sensors_poll_context_t::pollEvents(sensors_event_t* data, int count)
{
    int nbEvents = 0;
    int n = 0;

    do {
        // see if we have some leftover from the last poll()
        for (int i=0 ; count && i<numSensorDrivers ; i++) {
            SensorBase* const sensor(mSensors[i]);
            if ((mPollFds[i].revents & POLLIN) || (sensor->hasPendingEvents())) {
                int nb = sensor->readEvents(data, count);
                if (nb < count) {
                    // no more data for this sensor
                    mPollFds[i].revents = 0;
                }
                if ((0 != nb) && (acc == i)) {
                    ((AkmSensor*)(mSensors[akm]))->setAccel(&data[nb-1]);
                }
                count -= nb;
                nbEvents += nb;
                data += nb;
            }
        }

        if (count) {
            // we still have some room, so try to see if we can get
            // some events immediately or just wait if we don't have
            // anything to return
            n = poll(mPollFds, numFds, nbEvents ? 0 : -1);
            if (n<0) {
                ALOGE("poll() failed (%s)", strerror(errno));
                return -errno;
            }
            if (mPollFds[wake].revents & POLLIN) {
                char msg;
                int result = read(mPollFds[wake].fd, &msg, 1);
                ALOGE_IF(result<0, "error reading from wake pipe (%s)", strerror(errno));
                ALOGE_IF(msg != WAKE_MESSAGE, "unknown message on wake queue (0x%02x)", int(msg));
                mPollFds[wake].revents = 0;
            }
        }
        // if we have events and space, go read them
    } while (n && count);

    return nbEvents;
}

  readEvents中如果有未处理事件,则将sensors_event_t类型的未处理事件指针保存在第一个参数中。mInputReader类型为class InputEventCircularReader,是用来填充struct input_event输入事件的环形缓冲区。data_fd为openInput的返回值,即打开的输入设备的fd。AdxlSensor的构造函数将4传给InputEventCircularReader构造函数参数,mBuffer初始化为8个input_event大小的内存,以暂存读取超出环形缓冲区的部分。mBufferEnd指向环形缓冲的末尾,mHead记录了下次填充input_event的位置,mCurr记录了最后一个填充的input_event的位置,mFreeSpace记录了空闲的input_event大小的内存块数量。fill函数从输入设备中读取input_event事件到环形缓冲区中,当读取的大小超过缓冲区大小时,会将超出部分覆盖到缓冲区起始部分。
  while循环里读取mCurr记录的input_event的类型来执行操作,循环的条件是环形缓冲区还有数据可以读且需要读取事件的余量count大于0。AdxlSensor是一个加速度传感器,读取的事件类型为EV_ABS,可以用来判断手机屏幕的方向。x轴,y轴是以屏幕左下角为原点向右和向上的方向,z轴是垂直于屏幕指向屏幕外面的方向。在一个时刻,只有一个轴读取到加速度值。使用ADXL_UNIT_CONVERSION宏将内核层读到的重力加速度值转化为标准单位重力加速度值。在三轴上计算得到的数据用以初始化一个mPendingEvent。读取事件类型为EV_SYN时(EV_SYN是用于事件间的分割标志。事件可能按时间或空间进行分割,就像在多点触摸协议中的例子),设定mPendingEvent的时间戳为输入事件发生的时间,将mPendingEvent指针保存在data参数中。这样,readEvents函数将底层传上来的input_event填充到入参data中。SensorService便保存了来自底层的input_event包装而成的sensors_event_t事件。readEvents的返回值就是保存到data参数中的
input_event数量。
  值得注意的是,readEvents的入参data是对sensors_poll_context_t::pollEvents的入参data指针值的拷贝,readEvents中能改变data指向的数组的内容,但不能改变指针的指向的位置。所以,当readEvents函数返回了读取的事件数时,sensors_poll_context_t::pollEvents的入参data表示的数组内容已经改变,指向的位置和调用readEvents前的位置相同。

/hardware/akm/AK8975_FS/libsensors/AdxlSensor.cpp

int AdxlSensor::readEvents(sensors_event_t* data, int count)
{
    if (count < 1)
        return -EINVAL;

    if (mHasPendingEvent) {
        mHasPendingEvent = false;
        mPendingEvent.timestamp = getTimestamp();
        *data = mPendingEvent;
        return mEnabled ? 1 : 0;
    }

    ssize_t n = mInputReader.fill(data_fd);
    if (n < 0)
        return n;

    int numEventReceived = 0;
    input_event const* event;

    while (count && mInputReader.readEvent(&event)) {
        int type = event->type;
        if (type == EV_ABS) {
            float value = event->value;
            if (event->code == EVENT_TYPE_ACCEL_X) {
                mPendingEvent.acceleration.x = ADXL_UNIT_CONVERSION(value);
            } else if (event->code == EVENT_TYPE_ACCEL_Y) {
                mPendingEvent.acceleration.y = ADXL_UNIT_CONVERSION(value);
            } else if (event->code == EVENT_TYPE_ACCEL_Z) {
                mPendingEvent.acceleration.z = ADXL_UNIT_CONVERSION(value);
            }
        } else if (type == EV_SYN) {
            mPendingEvent.timestamp = timevalToNano(event->time);
            if (mEnabled) {
                *data++ = mPendingEvent;
                count--;
                numEventReceived++;
            }
        } else {
            ALOGE("AdxlSensor: unknown event (type=%d, code=%d)",
                    type, event->code);
        }
        mInputReader.next();
    }

    return numEventReceived;
}

/hardware/akm/AK8975_FS/libsensors/InputEventReader.h

class InputEventCircularReader
{
    struct input_event* const mBuffer;
    struct input_event* const mBufferEnd;
    struct input_event* mHead;
    struct input_event* mCurr;
    ssize_t mFreeSpace;

public:
    InputEventCircularReader(size_t numEvents);
    ~InputEventCircularReader();
    ssize_t fill(int fd);
    ssize_t readEvent(input_event const** events);
    void next();
};

/hardware/akm/AK8975_FS/libsensors/InputEventReader.h

InputEventCircularReader::InputEventCircularReader(size_t numEvents)
    : mBuffer(new input_event[numEvents * 2]),
      mBufferEnd(mBuffer + numEvents),
      mHead(mBuffer),
      mCurr(mBuffer),
      mFreeSpace(numEvents)
{
}

/hardware/akm/AK8975_FS/libsensors/InputEventReader.cpp

ssize_t InputEventCircularReader::fill(int fd)
{
    size_t numEventsRead = 0;
    if (mFreeSpace) {
        const ssize_t nread = read(fd, mHead, mFreeSpace * sizeof(input_event));
        if (nread<0 || nread % sizeof(input_event)) {
            // we got a partial event!!
            return nread<0 ? -errno : -EINVAL;
        }

        numEventsRead = nread / sizeof(input_event);
        if (numEventsRead) {
            mHead += numEventsRead;
            mFreeSpace -= numEventsRead;
            if (mHead > mBufferEnd) {
                size_t s = mHead - mBufferEnd;
                memcpy(mBuffer, mBufferEnd, s * sizeof(input_event));
                mHead = mBuffer + s;
            }
        }
    }

    return numEventsRead;
}

/bionic/libc/kernel/uapi/linux

struct input_event {
  //按键时间
  struct timeval time;
  //类型
  __u16 type;
  //模拟成的按键
  __u16 code;
  //按下还是释放
  __s32 value;
};

  至此,Android Sensor的HAL层代码大致分析完毕。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Invoker123/article/details/77814665

智能推荐

hbuliderX语法插件助手下载失败_下载语法助手插件失败-程序员宅基地

文章浏览阅读8.7k次。建议全部卸载,去官网找windows App开发版编译失败:HBuilderX 安装目录不能包括 ( 等特殊字符)----这个问题是跟安装目录有关系_下载语法助手插件失败

QT自定义Widget实现鼠标拖动窗口移动位置及鼠标拖拽窗口边缘窗口大小改变_qt 拖动改位置-程序员宅基地

文章浏览阅读5.3k次,点赞12次,收藏38次。QT自定义Widget实现鼠标拖动窗口移动位置及鼠标拖拽窗口边缘窗口大小改变通过setWindowFlags(Qt::FramelessWindowHint);可以隐藏掉Qt自带的窗口标题,这句话写的简单,可是窗口引起的改变可不少:最直观的,标题栏没了间接的,没了标题栏,也没有办法拖拽标题栏移动窗口位置了隐含的,鼠标移动到窗口边缘时,鼠标形态不再改变,无法实现鼠标拖拽窗口边缘改变窗口大小So,想使用自定义的窗体也是需要付出代价的。如果我既想自定义窗体,也想要让自定义的窗体,兼具鼠标拖动窗口移动_qt 拖动改位置

绝密 | 机器学习老手不会轻易告诉你的12件事儿-程序员宅基地

文章浏览阅读2.7k次,点赞2次,收藏13次。编译 | AI科技大本营 参与 | 彭硕 刘畅 编辑 | 明明机器学习是人工智能的核心,而机器学习的算法是其最重要的武器。机器学习算法可以从例子中归纳出执行重要任务的重要方法,这种方法不仅可行还可节约成本,随着可用的数据越来越多,我们就可以利用其解决更多的问题,因此,机器学习在计算机科学和其他领域中都得到了广泛的运用。尽管如此,开发出成功的机器学习应用程序还需要大量...

hiberante dynameic-update dynamic-insert 解决每次update所有字段的问题-程序员宅基地

文章浏览阅读708次。hibernate 动态生成sql的系统开销很小,当表_dynamic-insert

优化_一般多少epoch后调小学习率-程序员宅基地

文章浏览阅读349次。。_一般多少epoch后调小学习率

addEventListener和attachEvent以及事件句柄绑定的区别_句柄式事件和addeventlinster的区别-程序员宅基地

文章浏览阅读1.7k次。这几天对js的dom事件绑定回顾了一下首先说一下addEventListener和attachEvent的区别1.语法不同2.适用的范围不同,addEventListener适用于遵循dom标准的浏览器内使用如FF,而attachEvent则是在ie中使用的3.参数不一样4.绑定多个相同事件的执行顺序不一样addEventListener语法target.addEven_句柄式事件和addeventlinster的区别

随便推点

JAVA截长屏图代码,java实现截屏功能的代码-程序员宅基地

文章浏览阅读700次。抓取思路是首先抓到屏幕的整个图象,将图象显示在一个JFrame中,再将JFrame全屏显示,这样就模拟出了一个桌面,Java也就可以获得鼠标的作用区域从而实现桌面中的小范围截屏。import javax.swing.*;import java.awt.*;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;i..._java 截长图

Anaconda python 版本对应关系_anaconda与python版本对应关系-程序员宅基地

文章浏览阅读2k次。【转】原文:_沥川往事https://blog.csdn.net/yuejisuo1948/article/details/81043823首先解释一下上表。 anaconda在每次发布新版本的时候都会给python3和python2都发布一个包,版本号是一样的。表格中,python版本号下方的离它最近的anaconda包就是包含它的版本。举个例子,假设你想安装python2.7.14,在..._anaconda与python版本对应关系

toolchain安装教程支持_网上现成toolchain安装操作-程序员宅基地

文章浏览阅读1.1k次。1.ARM-ELF-TOOLSARM-ELF-TOOLS所提供的是 uClinux系统下的交叉编译工具。下载地址:到http://www.uclinux.org/pub/uClinux/arm-elf-tools/下载arm-elf-tools交叉编译工具安装程序。例如:下载之后的文件名为arm-elf-tools-20030314.sh(日期可能不同)是脚本文件。具体操作过程:(1) 首先看其权..._linux source toolchain 下载

sysbench 压测 mysql_sysbench 压测 MySQL 性能及优化-程序员宅基地

文章浏览阅读163次。sysbench 安装流程下载wget https://github.com/akopytov/sysbench/archive/master.zipunzip 安装yum install unzip解压unzip master.zip安装相关依赖yum -y install make automake libtool pkgconfig libaio-devel vim-commonyum -..._sysbench压测后mysql内存规律性高

需求分析中适应性怎么写_需求文档,怎么写才不会被打?-程序员宅基地

文章浏览阅读1k次。说起需求文档,作为产品经理的必备技能之一,恐怕没有一个产品经理不知道的吧。虽说需求文档是产品经理必备技能之一,但是要写一份开发看了不想打人的需求文档还是需要花点功夫的。什么是需求文档需求文档,就是传说中的PRD文档,全称ProductRequirement Document。需求文档的对产品的说明文档,用于完整的描述产品背景、需求和目标。需求文档的作用有很多人认为写需求文档纯属浪费时间,需求澄清时..._适应性需求

yslow chrome_YSlow / Chrome黑客-程序员宅基地

文章浏览阅读285次。yslow chromeIf you haven't seen it yet, YSlow for Chrome hit the streets couple of weeks ago. (And Google's own PageSpeed did too yesterday. (And there's now DynaTrace for Firefox. (And WebPageTest fo..._yslow chrome

推荐文章

热门文章

相关标签