一、概述

sensor(传感器)作为手机中一个非常重要且目前来说不可或缺的一种组件,功能强大,但是使用却很简单。Android 传感器属于虚拟设备,可提供来自以下各种物理传感器的数据:加速度计、陀螺仪、磁力计、气压计、湿度传感器、压力传感器、光传感器、近程传感器和心率传感器。因为对于日常生活来说有一部分sensor是使用频率是很高的,所以必然也伴随着手机功耗的增加如果每次都是CPU进行处理的化,而且CPU一旦休眠还伴随着sensor会停止工作,为了优化手机使用Google和MTK分别开发了CHRE 和SCP 进行sensor控制。

首先介绍以下SCP:

SCP 是用来处理sensor和audio相关功能和其他客制化需求的一个协处理理器,MTK SCP选择freeRTOS作为操作系统,CHRE是处理传感器相关操作的专门任务,它的架构如下
SCP
然后是CHRE:
CHRE

在SCP下,MTK传感器集线器功能是在google CHRE ar上开发的,chre(Context Hub Runtime Environment)是一种事件驱动的体系结构,也可以被视为操作系统。

黄色部分是事件队列,CHRE只有一个while循环来处理事件队列中的头事件。如果以前的调用尚未完成,CHRE将无法调用队列中的一个任务。因此,没有优先级概念,当前事件队列处理只能

被中断中断。默认情况下,CHRE在事件队列中最多支持512个事件。CHRE的目的是实现实时性和轻量级,因此事件队列中调用的所有任务都必须快速运行。CHRE中的驱动程序实现称为nano hub app。

整个sensor体系中包括:应用层、framework层、jni、hal层、kernel层、SCP/CHRE。

二、应用层调用

sensor在应用层调用非常简单,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

public class SensorActivity extends Activity implements SensorEventListener {

private final SensorManager mSensorManager;

private final Sensor mAccelerometer;


public SensorActivity() {

mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);

mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

}


protected void onResume() {

super.onResume();

mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);

}


protected void onPause() {

super.onPause();

mSensorManager.unregisterListener(this);

}


public void onAccuracyChanged(Sensor sensor, int accuracy) {

}


public void onSensorChanged(SensorEvent event) {

}

}

只需要获取到sensormanager然后注册监听就可以,sensor的信息就会通过回调接口上报上来

  • getSystemService 获取系统服务的标准接口,参数是表示要获取的服务类型
  • Sensormanger.getDefaultSensor 获取想要使用的sensor 实例 ,参数表示要获取的sensor 类型
  • SensorManager.registerListener 注册sensor的信息回调,参数分别是上下文,sensor,上报延时

三、framework层

经过上层的getSystemService获取了服务,功能就来到了framework层,这里对应framework/base/core/java/android/hardware/SensorManager.java,但是实际上这只是一个代理抽象类,真正获取的是SystemSensorManager:framework/base/core/java/android/hardware/SystemSensorManager.java。(从SystemServiceRegistry.java中可以看出,这是一个专门为上层注册接口的类)。

SystemSensorManager 在最上层控制着所有的sensor ,他的实现仅仅靠自己是不够的,它还链接了一个jni库,注册了很多native方法。android_hardware_SensorManager :framework/base/core/jni/android_hardware_SensorManager.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135

static const JNINativeMethod gSystemSensorManagerMethods[] = {

{"nativeClassInit",

"()V",

(void*)nativeClassInit },

{"nativeCreate",

"(Ljava/lang/String;)J",

(void*)nativeCreate },


{"nativeGetSensorAtIndex",

"(JLandroid/hardware/Sensor;I)Z",

(void*)nativeGetSensorAtIndex },


{"nativeGetDynamicSensors",

"(JLjava/util/List;)V",

(void*)nativeGetDynamicSensors },


{"nativeIsDataInjectionEnabled",

"(J)Z",

(void*)nativeIsDataInjectionEnabled },


{"nativeCreateDirectChannel",

"(JJIILandroid/hardware/HardwareBuffer;)I",

(void*)nativeCreateDirectChannel },


{"nativeDestroyDirectChannel",

"(JI)V",

(void*)nativeDestroyDirectChannel },


{"nativeConfigDirectChannel",

"(JIII)I",

(void*)nativeConfigDirectChannel },


{"nativeSetOperationParameter",

"(JII[F[I)I",

(void*)nativeSetOperationParameter },

};


static const JNINativeMethod gBaseEventQueueMethods[] = {

{"nativeInitBaseEventQueue",

"(JLjava/lang/ref/WeakReference;Landroid/os/MessageQueue;Ljava/lang/String;ILjava/lang/"

"String;Ljava/lang/String;)J",

(void *)nativeInitSensorEventQueue},


{"nativeEnableSensor", "(JIII)I", (void *)nativeEnableSensor},


{"nativeDisableSensor", "(JI)I", (void *)nativeDisableSensor},


{"nativeDestroySensorEventQueue", "(J)V", (void *)nativeDestroySensorEventQueue},


{"nativeFlushSensor", "(J)I", (void *)nativeFlushSensor},


{"nativeInjectSensorData", "(JI[FIJ)I", (void *)nativeInjectSensorData},

};


} //unnamed namespace


int register_android_hardware_SensorManager(JNIEnv *env)

{

RegisterMethodsOrDie(env, "android/hardware/SystemSensorManager",

gSystemSensorManagerMethods, NELEM(gSystemSensorManagerMethods));


RegisterMethodsOrDie(env, "android/hardware/SystemSensorManager$BaseEventQueue",

gBaseEventQueueMethods, NELEM(gBaseEventQueueMethods));


gBaseEventQueueClassInfo.clazz = FindClassOrDie(env,

"android/hardware/SystemSensorManager$BaseEventQueue");


gBaseEventQueueClassInfo.dispatchSensorEvent = GetMethodIDOrDie(env,

gBaseEventQueueClassInfo.clazz, "dispatchSensorEvent", "(I[FIJ)V");


gBaseEventQueueClassInfo.dispatchFlushCompleteEvent = GetMethodIDOrDie(env,

gBaseEventQueueClassInfo.clazz, "dispatchFlushCompleteEvent", "(I)V");


gBaseEventQueueClassInfo.dispatchAdditionalInfoEvent = GetMethodIDOrDie(env,

gBaseEventQueueClassInfo.clazz, "dispatchAdditionalInfoEvent", "(III[F[I)V");


return 0;

}

上面代码是android_hardware_SensorManager用来绑定java类和相关方法的。然后又将方法实现转移到SensorManager.cpp:framework/native/libs/sensor/SensorManager.cpp

SystemSensorManager创建时 会创建native SensorManager的实例并持有,然后获取sensorlist。SystemSensorManager中封装了很多方法,如:启用、禁用、刷新、添加监听等等。

SensorManager 也不是自己去做事情,它通过BitTube和SensorService 链接,将指令传到sensorservice。android_hardware_SensorManager 有一个内部类专门监听了BitTube通道文件描述符,会将sensor上报的信息通过这里上报到上层。

然后所有的事情都会转移到frameworks/native/services/sensorservice/ 这个包中,这里面会对所有sensor信息进行整理过滤,这里的所有信息都是从hal层获取,这里有个很关键的类SensorDevice,这个类链接了hal层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

SensorDevice::SensorDevice()

: mHidlTransportErrors(20),
mRestartWaiter(new HidlServiceRegistrationWaiter()),
mEventQueueFlag(nullptr),
mWakeLockQueueFlag(nullptr),
mReconnecting(false) {
if (!connectHidlService()) {
return;
}

initializeSensorList();

mIsDirectReportSupported =
(checkReturnAndGetStatus(mSensors->unregisterDirectChannel(-1)) != INVALID_OPERATION);
}
...
bool SensorDevice::connectHidlService() {
HalConnectionStatus status = connectHidlServiceV2_1(); // 链接hal 2.1
if (status == HalConnectionStatus::DOES_NOT_EXIST) {
status = connectHidlServiceV2_0(); // 链接 hal 2.0
}

if (status == HalConnectionStatus::DOES_NOT_EXIST) {
status = connectHidlServiceV1_0(); // 链接 hal 1.0
}
return (status == HalConnectionStatus::CONNECTED);
}
SensorDevice::HalConnectionStatus SensorDevice::connectHidlServiceV1_0() {
// SensorDevice will wait for HAL service to start if HAL is declared in device manifest.
size_t retry = 10;
HalConnectionStatus connectionStatus = HalConnectionStatus::UNKNOWN;

while (retry-- > 0) {
sp<V1_0::ISensors> sensors = V1_0::ISensors::getService();
if (sensors == nullptr) {
// no sensor hidl service found
connectionStatus = HalConnectionStatus::DOES_NOT_EXIST;
break;
}

mSensors = new ISensorsWrapperV1_0(sensors);
mRestartWaiter->reset();
// Poke ISensor service. If it has lingering connection from previous generation of
// system server, it will kill itself. There is no intention to handle the poll result,
// which will be done since the size is 0.
if(mSensors->poll(0, [](auto, const auto &, const auto &) {}).isOk()) {
// ok to continue
connectionStatus = HalConnectionStatus::CONNECTED;
break;
}

// hidl service is restarting, pointer is invalid.
mSensors = nullptr;
connectionStatus = HalConnectionStatus::FAILED_TO_CONNECT;
ALOGI("%s unsuccessful, remaining retry %zu.", __FUNCTION__, retry);
mRestartWaiter->wait();
}

return connectionStatus;
}

SensorDevice::HalConnectionStatus SensorDevice::connectHidlServiceV2_0() {
HalConnectionStatus connectionStatus = HalConnectionStatus::UNKNOWN;
sp<V2_0::ISensors> sensors = V2_0::ISensors::getService();

if (sensors == nullptr) {
connectionStatus = HalConnectionStatus::DOES_NOT_EXIST;
} else {
mSensors = new ISensorsWrapperV2_0(sensors);
connectionStatus = initializeHidlServiceV2_X();
}

return connectionStatus;
}

SensorDevice::HalConnectionStatus SensorDevice::connectHidlServiceV2_1() {
HalConnectionStatus connectionStatus = HalConnectionStatus::UNKNOWN;
sp<V2_1::ISensors> sensors = V2_1::ISensors::getService();

if (sensors == nullptr) {
connectionStatus = HalConnectionStatus::DOES_NOT_EXIST;
} else {
mSensors = new ISensorsWrapperV2_1(sensors);
connectionStatus = initializeHidlServiceV2_X();
}

return connectionStatus;
}
...

ISensors::getService()是hal层service 的获取方式,对应的是hardware/interfaces/sensors/…/ISensors.hal ,ISensors.hal编译之后会生成ISensors.h,服务端只要实现这个头文件的方法即可

四、hal层

hal层代码接口位于:hardware/interfaces/sensors/

文件夹下定义了多个版本的hal层结构,1.0、2.0、2.1还有公共接口,一般使用最新的2.1或者2.0,文件结构如下
在这里插入图片描述

.hal 文件是接口文件,在编译过程中会被编译成.h,需要使用的就导入.h文件,然后ISensors::getService()获取service服务实例即可,multihal里面是关于多hal的实现,vts里面是vs测试相关,hal层和framework层通信使用的是HIDL,和AIDL类似,底层使用的都是binder机制实现跨进程通信。

  • ISensorsCallback.hal 里面定义的动态sensor的回调接口
  • ISensors.hal 里面定义的是服务的主要功能接口
  • types.hal 里面定义的是一些要用到的结构类型

4.1 hal的实现

真正实现hal转接口的代码是在:vendor/mediatek/proprietary/hardware/sensor 这个文件夹中也会有多个版本的代码根据android.mk 进行选择,由宏控制,选择相应的版本,当前选择最新2.0进行讨论

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

LOCAL_PATH := $(call my-dir)

ifdef MTK_GENERIC_HAL

## layer decoupling 2.0 chips will go to this branch

## DO NOT USE platform macro in this branch

include $(call all-named-subdir-makefiles, hidl 2.0)

else

ifeq ($(strip $(MTK_SENSOR_ARCHITECTURE)),1.0)

include $(call all-named-subdir-makefiles,hidl sensors-1.0)

else ifeq ($(MTK_SENSORS_1_0),yes)

include $(call all-named-subdir-makefiles,hidl sensors-1.0)

else

include $(call all-named-subdir-makefiles,hidl $(strip $(MTK_SENSOR_ARCHITECTURE)))

endif

endif

与framework层通信的代码在hidl文件夹下有多个文件夹:
在这里插入图片描述

1.0/2.0 表示版本号,配置hal哪个版本就哪个

multihal:多hal,需要单独配置由/vendor/etc/sensors/hals.conf这个文件控制

Sensors.h 中可以看出Sensors 继承了ISensors并实现了这些方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

Sensors::Sensors()
: mInitCheck(NO_INIT),
mSensorModule(nullptr),
mSensorDevice(nullptr),
mEventQueueFlag(nullptr),
mOutstandingWakeUpEvents(0),
mReadWakeLockQueueRun(false),
mAutoReleaseWakeLockTime(0),
mHasWakeLock(false),
mRunThreadEnable(false),
mEventQueueInitialized(false) {
status_t err = OK;
if (UseMultiHal()) {
mSensorModule = ::get_multi_hal_module_info();
} else {
err = hw_get_module(
SENSORS_HARDWARE_MODULE_ID,
(hw_module_t const **)&mSensorModule); //获取SENSORS_HARDWARE_MODULE_ID的模块
}
if (mSensorModule == NULL) {
err = UNKNOWN_ERROR;
}

if (err != OK) {
LOG(ERROR) << "Couldn't load "
<< SENSORS_HARDWARE_MODULE_ID
<< " module ("
<< strerror(-err)
<< ")";

mInitCheck = err;
return;
}

err = sensors_open_1(&mSensorModule->common, &mSensorDevice); // 加载模块中的sensors_module_methods,并赋值给mSensorDevice

if (err != OK) {
LOG(ERROR) << "Couldn't open device for module "
<< SENSORS_HARDWARE_MODULE_ID
<< " ("
<< strerror(-err)
<< ")";

mInitCheck = err;
return;
...
}

从Sensors.cpp代码可以看出,Sensors初始化时会先判断是否使用了多hal,如果使用则会加载多hal模块,如果使用则通过hw_get_module加载id为SENSORS_HARDWARE_MODULE_ID的模块,并把它赋值给了mSensorModule。发现这个模块代码就放在sensor目录下面对应的那些不同版本的文件夹下,直接到vendor/mediatek/proprietary/hardware/sensor/2.0/hal 这个目录下放的都是2.0 hal 的代码,其中sensors.cpp 中的正式id为SENSORS_HARDWARE_MODULE_ID的模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...
static struct hw_module_methods_t sensors_module_methods = {
.open = open_sensors
};

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 = "MTK SENSORS Module",
.author = "Mediatek",
.methods = &sensors_module_methods,
},

所以可以从此看出,从framework层过来的指令给了mSensorModule和mSensorDevice 进行处理,间接的传递给了这个模块处理,然后此模块又分出很多个类进行分别处理不同的指令,部分指令又会汇集到一个类去和另一个层通信它就是HfManager,这个类在2.0/core/文件夹下,

进到HfManager 我们发现,这个类里面还有一个内部类HfLooper,但是无论哪个类,他们的方法最后会通过一个节点他就是dev/hf_manager,hal层则是通过这个节点来到了kernel层kernel-4.14/d/misc/mediatek/sensor/2.0/core/hf_manager.h

五、kernel 层

kernel层代码位于kernel文件夹下,至于kernel版本会在device下定义,我们先看kernel-4.14。sensor在kernel中的代码位于:

1
2
3
kernel-4.14/drivers/misc/mediatek/sensor
kernel-4.14/drivers/misc/mediatek/sensors-1.0
kernel-4.14/drivers/staging/nanohub

5.1 kernel-4.14/drivers/misc/mediatek/

首先这个文件夹下会包含很多驱动,其中有两个包sensor和sensors-1.0,这两个下面的内容其实是类似的,根据宏CONFIG_MTK_SENSOR_ARCHITECTURE会确定我们要的代码sensor中。

Android.mk

1
2
3
4
5
6
7
...
88 ifeq ($(subst ",,$(CONFIG_MTK_SENSOR_ARCHITECTURE)),1.0)
89 obj-y += sensors-1.0/
90 else
91 obj-y += sensor/
92 endif
...

sensor 文件夹下有一个我们要的类hf_manager.c,打开这个文件不然发现,它创建了节点dev/hf_manager,这刚好就和hal层的HfManager.cpp 链接上了,hal层的指令通过这个节点来到了kernel,这是一个普通的文件节点,里面有一些读写、指令操作。这里面有个核心结构体hf_core,后面很多操作都和这个结构体有关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
struct hf_core {

struct mutex manager_lock;

struct list_head manager_list; //外面注册的manager

struct sensor_state state[SENSOR_TYPE_SENSOR_MAX];



spinlock_t client_lock;

struct list_head client_list;



struct mutex device_lock;

struct list_head device_list;



struct kthread_worker kworker;

首先我们看下hf_manager 被打开时做了什么事情:创造了一个hf_client,这个hf_client记录了当前进程和线程的id,还创建了一个FIFO,用于数据交换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static int hf_manager_open(struct inode *inode, struct file *filp)

{

struct hf_client *client = hf_client_create();



if (!client)

return -ENOMEM;



filp->private_data = client;

nonseekable_open(inode, filp);

return 0;

}

然后,大概浏览一下代码不难发现,指令好像后面都被hf_device这个结构体承担了,这个结构体来自与hf_manager,hf_manager 每次使用之前都会调用hf_manager_find_manager方法来查找,那我么看看这个方法做了什么:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
static struct hf_manager *hf_manager_find_manager(struct hf_core *core,

uint8_t sensor_type)

{

int i = 0;

struct hf_manager *manager = NULL;

struct hf_device *device = NULL;



list_for_each_entry(manager, &core->manager_list, list) {

device = READ_ONCE(manager->hf_dev);

if (!device || !device->support_list)

continue;

for (i = 0; i < device->support_size; ++i) {

if (sensor_type == device->support_list[i].sensor_type)

return manager;

}

}

pr_err("Failed to find manager, %u unregistered\n", sensor_type);

return NULL;

}

发现它只是从一个list中去查找,根据sensor_type进行匹配,这个core→manager_list 又是由hf_manager_create方法进行注册,而这个方法是向外提供的,然后搜索一下不难发现:./2.0/sensorhub/transceiver.c./2.0/mtk_nanohub/mtk_nanohub.c使用到了它,也就是说这两个类分别注册了自己的hf_device,并且进行了相关的数据处理,这两个类所处的文件夹可以猜测一个是跟sensorhub相关,另一个则和CHRE相关。

5.2 sensor hub

sensor hub是个什么东西呢,故名思意,它是一个传感器集线器,也就是说某些传感器的数据要经过这个地方进行中转,transceiver.c它会和SCP通过IPI通信,将这边的指令还有DRAM地址发送到SCP端,然后把SCP 端的信息回传,先是读取DRAM内存获取信息,然后通过manager→report方法会传到hf_fifo,然后hf_fifo上的数据会被hal层读走。

ap侧sensor hub 通过kernel-4.14/drivers/misc/mediatek/sensor/2.0/sensorhub/ipi_comm.c和SCP侧建立链接:IPI_IN_SENSOR_NOTIFY接收ID,IPI_OUT_SENSOR_NOTIFY接收ID,IPI_IN_SENSOR_CTRL指令ID

sensor hub 所链接的SCP 侧在:vendor/mediatek/proprietary/tinysys/scp/middleware/sensorhub/comm/ipi_comm.c

5.3 nano hub

nano hub 是CHRE框架中的集线器,和sensor hub类似,nano hub 也是通过mtk_nonohub.c注册了hf_device ,和SCP通过IPI通信,将DRAM地址发送到SCP端,通过IPI把指令发过去,但是通过DRAM把信息读回来,然后通过manager→report 传递到hal层

ap侧nano hub 通过kernel-4.14/drivers/misc/mediatek/sensor/2.0/mtk_nanohub/nanohub/nanohub-mtk.c 和SCP建立链接 通过ID IPI_CHRE

nanohub 所链接的SCP侧在:vendor/mediatek/proprietary/hardware/contexthub/firmware/links/plat/src/hostIntfIPI.c

然后CHRE会调用bool SensorQueueEnqueue(struct SimpleQueue* sq, const void *data, int length, bool possiblyDiscardable)将数据传递到scp/middleware/contexthub/contexthub_fw.c,然后contexthub_fw.c 将数据写入DRAM,供AP侧读取

还有一部分指令会通过IPI_SENSOR直接传递到scp/middleware/contexthub/contexthub_fw.c

vendor/mediatek/proprierary/hardware/contexthub/firmware 下面有一些sensor,会将数据传递给hostIntf,然后传递给contexthub.c

vendor/mediatek/proprierary/tinysys/scp/middleware/sensorhub 下面也有一些sensor会传递信息

这两个地方有什么区别,目前暂未搞清楚,但是可以肯定的是sensor核心代码就在这两个地方了,CHRE 和 SCP侧,整个框架信息传递如下图:
在这里插入图片描述