MTK Android P Sensor架构(一)

需求场景:

本来如果只是给传感器写个驱动并提供能读取温湿度数据的节点,是一件比较轻松的事情,但是最近上层应用的同事要求我们按照安卓标准的流程来,这样他们就能通过注册一个服务直接读取传感器事件数据了。这样做的好处就是第三方的应用也能正常读取温湿度的数据并展示。

正文:

网上分析安卓9.0 sensor相关的资料不多,下面找到了一位大神对安卓9.0整个sensor框架总结的流程图:

虽然流程比较粗糙,但是也有助于我们跟踪代码。这里重点说一下,sensor架构中的HAL层分为两部分:

  • 安卓官方实现部分:
cpp 复制代码
hardware/libhardware/modules/sensors
  • 芯片产商实现部分(MTK平台):
cpp 复制代码
vendor/mediatek/proprietary/hardware/sensor

一般来讲,在适配一款新的sensor,改动只会涉及vendor层到kernel层,再往上都是安卓标准的,但是为了了解整个流程怎么走的,参考这位大神的博客,在这里我也稍微介绍一下framework层的部分。

cpp 复制代码
代码路径:

frameworks\base\services\java\com\android\server\SystemServer.java
cpp 复制代码
private void startBootstrapServices() {
 ...
 mSensorServiceStart = SystemServerInitThreadPool.get().submit(() -> {
            TimingsTraceLog traceLog = new TimingsTraceLog(
                    SYSTEM_SERVER_TIMING_ASYNC_TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
            traceLog.traceBegin(START_SENSOR_SERVICE);
            startSensorService(); /* 调用JNI接口 */
            traceLog.traceEnd();
        }, START_SENSOR_SERVICE);
 ...
}

system_server启动之后会通过JNI接口启动sensorService。

cpp 复制代码
代码路径:

frameworks\base\services\core\jni\com_android_server_SystemServer.cpp
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) {
        SensorService::instantiate();
    }
 
}
 
/*
 * JNI registration.
   */
   static const JNINativeMethod gMethods[] = {
   /* name, signature, funcPtr */
   { "startSensorService", "()V", (void*) android_server_SystemServer_startSensorService },
   { "startHidlServices", "()V", (void*) android_server_SystemServer_startHidlServices },
   };
 

从上面可以发现,最后调用到

android_server_SystemServer_startSensorService

函数,里面会判断属性

system_init.startsensorservice

是否为1,然后才会真正去启动

SensorService

服务。所以这里涉及到第一个改动,设置

system_init.startsensorservice

属性,这里我是直接在

build/make/tools/buildinfo.sh

里面写死为1。

用SensorService::instantiate()方式创建的sensorservice实例后,调用里面的SensorService::onFirstRef方法。

cpp 复制代码
代码路径:

frameworks\native\services\sensorservice\SensorService.cpp
cpp 复制代码
void SensorService::onFirstRef() {
    ALOGD("nuSensorService starting...");
    SensorDevice& dev(SensorDevice::getInstance()); /* 创建并获取SensorDevice实例 */
 ...
 
 if (dev.initCheck() == NO_ERROR) {
     sensor_t const* list;
     ssize_t count = dev.getSensorList(&list); /* 通过SensorDevice,并调用到vendor层去获取sensor的数目 */
     if (count > 0) {
         ssize_t orientationIndex = -1;
         bool hasGyro = false, hasAccel = false, hasMag = false;
         uint32_t virtualSensorsNeeds =
                (1<<SENSOR_TYPE_GRAVITY) |
                (1<<SENSOR_TYPE_LINEAR_ACCELERATION) |
                (1<<SENSOR_TYPE_ROTATION_VECTOR) |
                (1<<SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR) |
                (1<<SENSOR_TYPE_GAME_ROTATION_VECTOR);
 
         for (ssize_t i=0 ; i<count ; i++) {
             bool useThisSensor=true;
 
             switch (list[i].type) {
                 case SENSOR_TYPE_ACCELEROMETER:
                     hasAccel = true;
                     break;
                 case SENSOR_TYPE_MAGNETIC_FIELD:
                     hasMag = true;
                     break;
                 case SENSOR_TYPE_ORIENTATION:
                     orientationIndex = i;
                     break;
                 case SENSOR_TYPE_GYROSCOPE:
                 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
                     hasGyro = true;
                     break;
                 case SENSOR_TYPE_GRAVITY:
                 case SENSOR_TYPE_LINEAR_ACCELERATION:
                 case SENSOR_TYPE_ROTATION_VECTOR:
                 case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR:
                 case SENSOR_TYPE_GAME_ROTATION_VECTOR:
                     if (IGNORE_HARDWARE_FUSION) {
                         useThisSensor = false;
                     } else {
                         virtualSensorsNeeds &= ~(1<<list[i].type);
                     }
                     break;
             }
             if (useThisSensor) {
                 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)
         SensorFusion::getInstance();
 
         if (hasGyro && hasAccel && hasMag) {
             ...
         }
 
         if (hasAccel && hasGyro) {
             ...
         }
 
         if (hasAccel && hasMag) {
             ...
         }
 
         ...
     }
 }
}
 

我这次主要是增加温湿度传感器的功能,上面的流程中没有过多涉及温湿度的,有兴趣的可以参考大神的博客自行分析。不过这里重点关注一下SensorDevice这个类,它是连接上层应用和HAL层的中间枢纽:

cpp 复制代码
代码路径:

frameworks\native\services\sensorservice\SensorDevice.cpp
cpp 复制代码
SensorDevice::SensorDevice()
        : mHidlTransportErrors(20), mRestartWaiter(new HidlServiceRegistrationWaiter()) {
    if (!connectHidlService()) {
        return;
    }
 float minPowerMa = 0.001; // 1 microAmp
 
 checkReturn(mSensors->getSensorsList(
        [&](const auto &list "&") {
            const size_t count = list.size();
 
            mActivationCount.setCapacity(count);
            Info model;
            for (size_t i=0 ; i < count; i++) {
                sensor_t sensor;
                convertToSensor(list[i], &sensor);
                // Sanity check and clamp power if it is 0 (or close)
                if (sensor.power < minPowerMa) {
                    ALOGE("Reported power %f not deemed sane, clamping to %f",
                          sensor.power, minPowerMa);
                    sensor.power = minPowerMa;
                }
                mSensorList.push_back(sensor);
 
                mActivationCount.add(list[i].sensorHandle, model);
 
                checkReturn(mSensors->activate(list[i].sensorHandle, 0 /* enabled */));
            }
        }));
 
 mIsDirectReportSupported =
        (checkReturn(mSensors->unregisterDirectChannel(-1)) != Result::INVALID_OPERATION);
}

在SensorDevice构造函数中,通过调用connectHidlService()和安卓部分的HAL层服务建立连接。连接后,就可以调用已经在HAL层注册的sensor设备了,比如这里就调用getSensorsList()来获取sensor设备列表,并放回sensor的数目。然后就是通过mSensors->activate()来"激活"sensor设备,而每个sensor具体的activate()函数由驱动工程师实现。

激活sensor设备后,就可以开始获取sensor的数据了,在SensorService中会通过poll机制去查询底层sensor的数据:

cpp 复制代码
代码路径:

frameworks\native\services\sensorservice\SensorService.cpp
cpp 复制代码
bool SensorService::threadLoop() {
    ...
 SensorDevice& device(SensorDevice::getInstance());
 
 const int halVersion = device.getHalDeviceVersion();
 do {
     ssize_t count = device.poll(mSensorEventBuffer, numEventMax);
     if (count < 0) {
         ALOGE("sensor poll failed (%s)", strerror(-count));
         break;
     }
 
     ...
 } while (!Thread::exitPending());
 
 ALOGW("Exiting SensorService::threadLoop => aborting...");
 abort();
 return false;
}

整个threadLoop函数里面内容挺多的,但是目前只关注读取数据的poll部分。可以看到device就是SensorDevice的一个实例,前面我们讲到上层都是通过SensorDevice和HAL层连接,这里也不例外,也是调用到了SensorDevice中的poll函数,这里我给出这个调用的流程:

cpp 复制代码
1、frameworks\native\services\sensorservice\SensorDevice.cpp
SensorDevice::poll()
 2、vendor\mediatek\proprietary\hardware\sensor\sensors-1.0\sensors.cpp
 poll__poll()
  3、vendor\mediatek\proprietary\hardware\sensor\sensors-1.0\SensorManager.cpp
  SensorManager::pollEvent()
   4、vendor\mediatek\proprietary\hardware\sensor\sensors-1.0\SensorContext.cpp
   sensors_poll_context_t::pollEvent

上面简陋的流程展示了从framework层一路调用到vendor层:

cpp 复制代码
int sensors_poll_context_t::pollEvent(sensors_event_t* data, int count) {
    int nbEvents = 0;
    int n = 0;
    int averageCount = 0, loop = 0, loopcount = 0;
    int backupcount = count, backuploop = 0;
 do {
    loopcount++;
    computeCountForEachFd(count, &averageCount, &loop);
    backuploop = loop;
    for (int i = 0; count && loop && i < numFds; i++) {
        SensorBase* const sensor(mSensors[i]);
  if (mPollFds[i].revents & POLLIN || sensor->pendingEvent()) {
   int nb = sensor->readEvents(data, averageCount);
            ...
        }
    }
    // try to see if we can get some events immediately or just wait if
    // we don't have anything to return, important to update fd revents
    // which sensor data pending in buffer and aviod one sensor always
    // occupy poll bandwidth.
    n = TEMP_FAILURE_RETRY(poll(mPollFds, numFds, nbEvents ? 0 : -1));
    if (n < 0) {
        ALOGE("poll() failed (%s)", strerror(errno));
        return -errno;
    }
 } while (n && count);
 return nbEvents;
}

这里面我们重点关注三点

(1) mPollFds的定义如下

cpp 复制代码
struct pollfd mPollFds[numFds];

其中,

cpp 复制代码
struct pollfd {
 int fd;        /* 文件描述符 */
 short events; /* 等待的事件 */
 short revents; /* 实际发生了的事件 */
};

所以mPollFds就是用来监听代表每个sensor是否有数据上报的文件描述符

cpp 复制代码
enum {
    accel,
    magnetic,
    gyro,
    light,
    proximity,
    pressure,
    humidity,
 temperature,
    stepcounter,
    pedometer,
    activity,
    situation,
    scpfusion,
    apfusion,
    bio,
    wakeupset,
    numFds,
};
 

如果想自定义一种sensor就需要给这个枚举类型增加值

(2) mSensors的定义如下:

cpp 复制代码
SensorBase* mSensors[numFds];

SensorBase是一个基类,所有的sensor类都继承于它,比如我这次实现的湿度传感器:

cpp 复制代码
class HumiditySensor : public SensorBase {
 private:
     int mEnabled;
     sensors_event_t mPendingEvent;
     SensorEventCircularReader mSensorReader;
     int64_t mEnabledTime;
     char input_sysfs_path[PATH_MAX];
     int input_sysfs_path_len;
     int mDataDiv;
     int64_t m_hmdy_last_ts = 0;
     int64_t m_hmdy_delay = 0;
 
     void processEvent(struct sensor_event const *event);
 
 public:
        HumiditySensor();
     virtual ~HumiditySensor();
     virtual int readEvents(sensors_event_t* data, int count);
     virtual int setDelay(int32_t handle, int64_t ns);
     virtual int enable(int32_t handle, int enabled);
     virtual int batch(int handle, int flags, int64_t samplingPeriodNs, int64_t maxBatchReportLatencyNs);
     virtual int flush(int handle);
     virtual int getFd() {
         return mSensorReader.getReadFd();
     };
};

从类的声明来看,定义了很多函数,比如readEvents、enable和batch等等,这些最终都会和底层驱动联系起来,后面再细说。

(3)在sensors_poll_context_t的构造函数中会对上面两点讲到的数组进行初始化:

cpp 复制代码
sensors_poll_context_t::sensors_poll_context_t()
{
 ...
 mSensors[humidity] = new HumiditySensor(); /* 分配一个Humidity传感器的类 */
    mPollFds[humidity].fd = mSensors[humidity]->getFd(); /* 获取对应sensor的字符描述符 */
    mPollFds[humidity].events = POLLIN; /* 等待POLLIN类型的事件 */
    mPollFds[humidity].revents = 0;
 ...
}

再回到上面的

sensors_poll_context_t::pollEvent()

函数,通过

mPollFds[i].revents

判断到如果发生了POLLIN事件,证明可以获取数据了,就调用对应sensor的readEvents()

函数去获取。接下来我们就进入到sensor设备对应的HAL层里面了,现在以湿度sensor为例:

cpp 复制代码
代码路径:

vendor\mediatek\proprietary\hardware\sensor\sensors-1.0\Humidity.cpp
cpp 复制代码
int HumiditySensor::readEvents(sensors_event_t* data, int count) {
    if (count < 1)
        return -EINVAL;
 
    ssize_t n = mSensorReader.fill();
    if (n < 0)
        return n;
    int numEventReceived = 0;
    struct sensor_event const* event;
    
    while (count && mSensorReader.readEvent(&event)) {
        processEvent(event);
        if (event->flush_action <= FLUSH_ACTION) {
            ...
        }
        mSensorReader.next();
    }
    return numEventReceived;
 
}

我们可以看到读取数据实际又是统一通过

SensorEventCircularReader

这个类来操作:

cpp 复制代码
代码路径:

vendor\mediatek\proprietary\hardware\sensor\sensors-1.0\SensorEventReader.cpp
cpp 复制代码
SensorEventCircularReader::SensorEventCircularReader(size_t numEvents)
    : mBuffer(new struct sensor_event[numEvents * 2]),
      mBufferEnd(mBuffer + numEvents),
      mHead(mBuffer),
      mCurr(mBuffer),
      mFreeSpace(numEvents) {
    mReadFd = -1;
    mWriteFd = -1;
}

构造函数里面分配了Buffer来存储接收的数据

cpp 复制代码
ssize_t SensorEventCircularReader::fill() {
    size_t numEventsRead = 0;
    if (mFreeSpace) {
        const ssize_t nread = TEMP_FAILURE_RETRY(read(mReadFd, mHead, mFreeSpace * sizeof(struct sensor_event)));
        if (nread < 0 || nread % sizeof(struct sensor_event)) {
            return 0;
        }
 
        ...
    }
    
    return numEventsRead;
 
}

fill顾名思义就是往分配的buffer里面填充数据,通过我们熟悉的read()函数来获取数据。

cpp 复制代码
ssize_t SensorEventCircularReader::readEvent(struct sensor_event const** events) {
    *events = mCurr;
    ssize_t available = (mBufferEnd - mBuffer) - mFreeSpace;
    return available ? 1 : 0;
}

readEvent()

只是判断buffer中是否有数据,然后就是调用

mSensorReader.next()

获取下一个buffer。再回到

HumiditySensor::readEvents()

在读取到数据后会调用

processEvent()

去处理数据:

cpp 复制代码
void HumiditySensor::processEvent(struct sensor_event const *event) {
    mPendingEvent.relative_humidity = (float) event->word[0] / mDataDiv;
}
 

mPendingEvent.relative_humidity就是最终上报给上层应用的值了。

至此,framework层到vendor层的流程就分析完了,后面我们会分析kernel层的sensor框架。

相关推荐
renxhui2 小时前
Android 性能优化(四):卡顿优化
android·性能优化
二流小码农2 小时前
鸿蒙开发:UI界面分析利器ArkUI Inspector
android·ios·harmonyos
CYRUS_STUDIO2 小时前
FART 精准脱壳:通过配置文件控制脱壳节奏与范围
android·安全·逆向
小疯仔2 小时前
使用el-input数字校验,输入汉字之后校验取消不掉
android·开发语言·javascript
墨狂之逸才3 小时前
Data Binding Conversion 详解
android
iceBin3 小时前
uniapp打包安卓App热更新,及提示下载安装
android·前端
杨充3 小时前
高性能图片优化方案
android
墨狂之逸才4 小时前
BindingAdapter名称的对应关系、命名规则和参数定义原理
android
hellokai4 小时前
ReactNative介绍及简化版原理实现
android·react native
阿豪元代码5 小时前
Perfetto 上手指南3 —— CPU 信息分析
android