mt8167s溫溼度傳感器框架分析——framework到vendor層

mt8167s溫溼度傳感器框架分析——framework到vendor層

關鍵字:mt8167s、Android 9.0、AHT10

前言

​ 本來如果只是給傳感器寫個驅動並提供能讀取溫溼度數據的節點,是一件比較輕鬆的事情,但是最近上層應用的同事要求我們按照安卓標準的流程來,這樣他們就能通過註冊一個服務直接讀取傳感器事件數據了。這樣做的好處就是第三方的應用也能正常讀取溫溼度的數據並展示。

正文

​ 網上分析安卓9.0 sensor相關的資料不多,下面找到了一位大神對安卓9.0整個sensor框架總結的流程圖:

img

​ 雖然流程比較粗糙,但是也有助於我們跟蹤代碼。這裏重點說一下,sensor架構中的HAL層分爲兩部分:

(1)安卓官方實現部分

hardware/libhardware/modules/sensors

(2)芯片產商實現部分(MTK平臺)

vendor/mediatek/proprietary/hardware/sensor

​ 一般來講,在適配一款新的sensor,改動只會涉及vendor層到kernel層,再往上都是安卓標準的,但是爲了瞭解整個流程怎麼走的,參考這位大神的博客,在這裏我也稍微介紹一下framework層的部分。

代碼路徑:frameworks\base\services\java\com\android\server\SystemServer.java

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。

代碼路徑: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) {
        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方法。

代碼路勁:frameworks\native\services\sensorservice\SensorService.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層的中間樞紐:

代碼路徑:frameworks\native\services\sensorservice\SensorDevice.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的數據:

代碼路徑:frameworks\native\services\sensorservice\SensorService.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函數,這裏我給出這個調用的流程:

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層:

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的定義如下:

struct pollfd mPollFds[numFds];

其中,

struct pollfd {
	int fd;        /* 文件描述符 */
	short events; /* 等待的事件 */
	short revents; /* 實際發生了的事件 */
};

所以mPollFds就是用來監聽代表每個sensor是否有數據上報的文件描述符

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

​ 如果想自定義一種sensor就需要給這個枚舉類型增加值。

(2)
mSensors的定義如下:

SensorBase* mSensors[numFds];

SensorBase是一個基類,所有的sensor類都繼承於它,比如我這次實現的溼度傳感器:

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的構造函數中會對上面兩點講到的數組進行初始化:

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爲例:

代碼路徑:vendor\mediatek\proprietary\hardware\sensor\sensors-1.0\Humidity.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這個類來操作:

代碼路徑:vendor\mediatek\proprietary\hardware\sensor\sensors-1.0\SensorEventReader.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來存儲接收的數據

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()函數來獲取數據。

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()去處理數據:

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

​ mPendingEvent.relative_humidity就是最終上報給上層應用的值了。

結語

​ 至此,framework層到vendor層的流程就分析完了,後面我們會分析kernel層的sensor框架。

參考鏈接

https://blog.csdn.net/goodnight1994/article/details/97503586

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