refs: https://developer.android.google.cn/guide/topics/sensors/
1. 传感器分类
Android平台支持三个大类的传感器
- Motion sensors(运动传感器)
这些传感器测量加速力,并沿三个轴的旋转力。此类别包括加速度计,重力感应器, 陀螺仪和旋转矢量传感器。 - Environmental sensors (环境传感器)
这些传感器测量各种环境参数,例如环境空气温度和压力,照明和湿度。此类别包括气压计,光度计,和温度计。 - Position sensors (位置传感器)
这些传感器测量设备的物理位置。这个类别包括方向传感器和磁力计。
目前 Android 平台支持的传感器type如下:
Sensor | Type | Description | Common Uses |
---|---|---|---|
TYPE_ACCELEROMETER |
Hardware | Measures the acceleration force in m/s2 that is applied to a device on all three physical axes (x, y, and z), including the force of gravity. | Motion detection (shake, tilt, etc.). |
TYPE_AMBIENT_TEMPERATURE |
Hardware | Measures the ambient room temperature in degrees Celsius (°C). See note below. | Monitoring air temperatures. |
TYPE_GRAVITY |
Software or Hardware | Measures the force of gravity in m/s2 that is applied to a device on all three physical axes (x, y, z). | Motion detection (shake, tilt, etc.). |
TYPE_GYROSCOPE |
Hardware | Measures a device's rate of rotation in rad/s around each of the three physical axes (x, y, and z). | Rotation detection (spin, turn, etc.). |
TYPE_LIGHT |
Hardware | Measures the ambient light level (illumination) in lx. | Controlling screen brightness. |
TYPE_LINEAR_ACCELERATION |
Software or Hardware | Measures the acceleration force in m/s2 that is applied to a device on all three physical axes (x, y, and z), excluding the force of gravity. | Monitoring acceleration along a single axis. |
TYPE_MAGNETIC_FIELD |
Hardware | Measures the ambient geomagnetic field for all three physical axes (x, y, z) in μT. | Creating a compass. |
TYPE_ORIENTATION |
Software | Measures degrees of rotation that a device makes around all three physical axes (x, y, z). As of API level 3 you can obtain the inclination matrix and rotation matrix for a device by using the gravity sensor and the geomagnetic field sensor in conjunction with the getRotationMatrix() method. |
Determining device position. |
TYPE_PRESSURE |
Hardware | Measures the ambient air pressure in hPa or mbar. | Monitoring air pressure changes. |
TYPE_PROXIMITY |
Hardware | Measures the proximity of an object in cm relative to the view screen of a device. This sensor is typically used to determine whether a handset is being held up to a person's ear. | Phone position during a call. |
TYPE_RELATIVE_HUMIDITY |
Hardware | Measures the relative ambient humidity in percent (%). | Monitoring dewpoint, absolute, and relative humidity. |
TYPE_ROTATION_VECTOR |
Software or Hardware | Measures the orientation of a device by providing the three elements of the device's rotation vector. | Motion detection and rotation detection. |
TYPE_TEMPERATURE |
Hardware | Measures the temperature of the device in degrees Celsius (°C). This sensor implementation varies across devices and this sensor was replaced with the TYPE_AMBIENT_TEMPERATURE sensor in API Level 14 |
Monitoring temperatures. |
2. 常规使用流程
2.1 常用api
SensorManager:可以通过这个类去创建一个传感器服务的实例,这个类提供的各种方法可以访问传感器列表、注册或解除注册传感器事件监听、获取方位信息等。
Sensor:用于创建一个特定的传感器实例,这个类提供的方法可以让你决定一个传感器的功能。
SensorEvent:系统会通过这个类创建一个传感器事件对象,提供了一个传感器的事件信息,包含一下内容,原生的传感器数据、触发传感器的事件类型、精确的数据以及事件发生的时间。
SensorEventListener:可以通过这个接口创建两个回调用法来接收传感器的事件通知,比如当传感器的值发生变化时。
2.2 使用方式
第一步:获取SensorManager对象
第二步:获取Sensor对象
第三步:注册Sensor对象
第四步:重写onAccuracyChanged,onSensorChanged这两个方法
第五步:注销Sensor对象
public class SensorActivity extends Activity implements SensorEventListener {
private SensorManager mSensorManager;
private Sensor mSensor;
@Override
public final void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//第一步:通过getSystemService获得SensorManager实例对象
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
//第二步:通过SensorManager实例对象获得想要的传感器对象:参数决定获取哪个传感器
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
}
//第四步:必须重写的两个方法:onAccuracyChanged,onSensorChanged
/**
* 传感器精度发生改变的回调接口
*/
@Override
public final void onAccuracyChanged(Sensor sensor, int accuracy) {
//TODO 在传感器精度发生改变时做些操作,accuracy为当前传感器精度
}
/**
* 传感器事件值改变时的回调接口:执行此方法的频率与注册传感器时的频率有关
*/
@Override
public final void onSensorChanged(SensorEvent event) {
// 大部分传感器会返回三个轴方向x,y,x的event值,值的意义因传感器而异
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
//TODO 利用获得的三个float传感器值做些操作
}
/**
* 第三步:在获得焦点时注册传感器并让本类实现SensorEventListener接口
*/
@Override
protected void onResume() {
super.onResume();
/*
*第一个参数:SensorEventListener接口的实例对象
*第二个参数:需要注册的传感器实例
*第三个参数:传感器获取传感器事件event值频率:
* SensorManager.SENSOR_DELAY_FASTEST = 0:对应0微秒的更新间隔,最快,1微秒 = 1 % 1000000秒
* SensorManager.SENSOR_DELAY_GAME = 1:对应20000微秒的更新间隔,游戏中常用
* SensorManager.SENSOR_DELAY_UI = 2:对应60000微秒的更新间隔
* SensorManager.SENSOR_DELAY_NORMAL = 3:对应200000微秒的更新间隔
* 键入自定义的int值x时:对应x微秒的更新间隔
*
*/
mSensorManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_NORMAL);
}
/**
* 第五步:在失去焦点时注销传感器
*/
@Override
protected void onPause() {
super.onPause();
mSensorManager.unregisterListener(this);
}
}
注意,设备不一定支持你需要的sensor,使用前可以先判断下可用性
private SensorManager mSensorManager;
...
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
if (mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null){
// Success! There's a magnetometer.
} else {
// Failure! No magnetometer.
}
//或者
List<Sensor> deviceSensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
3. 常用Sensor的解释
Accelerometer 加速度传感器
加速度传感器又叫G-sensor,返回x、y、z三轴的加速度数值。
该数值包含地心引力的影响,单位是m/s^2。
将手机平放在桌面上,x轴默认为0,y轴默认0,z轴默认9.81。 将手机朝下放在桌面上,z轴为-9.81。 将手机向左倾斜,x轴为正值。 将手机向右倾斜,x轴为负值。 将手机向上倾斜,y轴为负值。 将手机向下倾斜,y轴为正值。
Magnetometer 磁力传感器
磁力传感器简称为M-sensor,返回x、y、z三轴的环境磁场数据。
该数值的单位是微特斯拉(micro-Tesla),用uT表示。 单位也可以是高斯(Gauss),1Tesla=10000Gauss。 硬件上一般没有独立的磁力传感器,磁力数据由电子罗盘传感器提供(E-compass)。
电子罗盘传感器同时提供下文的方向传感器数据。
Orientation 方向传感器
方向传感器简称为O-sensor,返回三轴的角度数据,方向数据的单位是角度。
为了得到精确的角度数据,E-compass(电子罗盘传感器)需要获取G-sensor(加速度传感器)的数据, 经过计算生产O-sensor数据,否则只能获取水平方向的角度。
方向传感器提供三个数据,分别为azimuth、pitch和roll。
azimuth:方位,返回水平时磁北极和Y轴的夹角,范围为0°至360°。 0°=北,90°=东,180°=南,270°=西。
pitch:x轴和水平面的夹角,范围为-180°至180°。 当z轴向y轴转动时,角度为正值。
roll:y轴和水平面的夹角,由于历史原因,范围为-90°至90°。 当x轴向z轴移动时,角度为正值。
电子罗盘在获取正确的数据前需要进行校准,通常可用8字校准法。 8字校准法要求用户使用需要校准的设备在空中做8字晃动, 原则上尽量多的让设备法线方向指向空间的所有8个象限。
Gyroscope 陀螺仪传感器
陀螺仪传感器叫做Gyro-sensor,返回x、y、z三轴的角速度数据。
角速度的单位是radians/second。
根据Nexus S手机实测: 水平逆时针旋转,Z轴为正。 水平逆时针旋转,z轴为负。 向左旋转,y轴为负。 向右旋转,y轴为正。 向上旋转,x轴为负。 向下旋转,x轴为正。
Ambient Light Sensor (环境)光线感应传感器
光线感应传感器检测实时的光线强度,光强单位是lux(勒克司度),其物理意义是照射到单位面积上的光通量。
光线感应传感器主要用于Android系统的LCD自动亮度功能。
可以根据采样到的光强数值实时调整LCD的亮度。
Barometer Sensor (气)压力传感器
压力传感器返回当前的压强,单位是百帕斯卡hectopascal(hPa)。
Temperature Sensor 温度传感器
温度传感器返回当前的温度。
Proximity Sensor (近)距离传感器
又称接近传感器,检测物体与手机的距离,单位是cm(厘米)。
一些接近传感器只能返回远和近两个状态, 因此,接近传感器将最大距离返回远状态,小于最大距离返回近状态。 接近传感器可用于接听电话时自动关闭LCD屏幕以节省电量。
一些芯片集成了接近传感器和光线传感器两者功能。
Gravity 重力传感器
重力传感器简称GV-sensor,输出重力数据。
在地球上,重力数值为9.8,单位是m/s^2。 坐标系统与加速度传感器相同。 当设备复位时,重力传感器的输出与加速度传感器相同。
Linear Acceleration 线性加速度传感器
线性加速度传感器简称LA-sensor。
线性加速度传感器是加速度传感器减去重力影响获取的数据。 单位是m/s^2,坐标系统与加速度传感器相同。
加速度传感器、重力传感器和线性加速度传感器的计算公式如下: 加速度 = 重力 + 线性加速度
Rotation Vector 旋转矢量传感器
旋转矢量传感器简称RV-sensor。
旋转矢量代表设备的方向,是一个将坐标轴和角度混合计算得到的数据。
RV-sensor输出三个数据: xsin(theta/2) ysin(theta/2) z*sin(theta/2) sin(theta/2)是RV的数量级。
RV的方向与轴旋转的方向相同。 RV的三个数值,与cos(theta/2)组成一个四元组。 RV的数据没有单位,使用的坐标系与加速度相同。
举例:
sensors_event_t.data[0] = x*sin(theta/2)
sensors_event_t.data[1] = ysin(theta/2)
sensors_event_t.data[2] = z*sin(theta/2)
sensors_event_t.data[3] = cos(theta/2)
其他传感器
Step Detector 步数探测器
Step Counter 计步器
Significant Motion Detector 运动检测器
Game Rotation Vector 游戏旋转矢量
Geomagnetic Rotation Vector 地磁旋转矢量
Basic Gestures 基本手势
Motion Accel 运动加速度
4. 坐标系统
手机的自然坐标系
当一个设备被放在其默认的方向上时,X轴是水平指向右的,Y轴是垂直向上的,Z轴是指向屏幕正面之外的,即屏幕背面是Z的负值。
img当设备运动或者旋转的时候,这些坐标轴是不会改变的,即它们是跟随手机的。
即是说,手机坐标系是跟随设备的自然方向的(但是请记住自然方向不一定是竖直,比如平板它的自然方向就很有可能是横向)。
使用这个坐标系的传感器:
即是说它们的度数显示了在手机的这三个轴上的数字大小。
屏幕旋转
常常要考虑屏幕的旋转,即屏幕画面相对于自然方向的旋转。
于是就需要使用 getRotation()方法来获取屏幕的旋转值。
这个方法是Display类中的,跟传感器不相关。
这个方法的返回值只对应0,90,180,270四种旋转情况,它说明屏幕显示区域的旋转情况。
世界坐标系
有一些传感器和方法使用相对于世界的坐标系,因为它们返回的数据反映设备相对于地球及真实环境的位置信息。
请见getOrientation() 方法,getRotationMatrix() 方法,Orientation Sensor, 和 Rotation Vector Sensor。
getRotationMatrix()
getRotationMatrix()方法说明中,定义的世界坐标系如下:
imgX轴平行于地面,指向东方。
Y轴平行于地面,指向北极方向。
Z轴垂直于地面,指向天空。
getOrientation()
getOrientation() 方法中所用的坐标系与上面的不同:
imgX轴平行于地面,指向西方;
Y轴平行于地面,指向地磁场北极。
Z轴垂直于地面,指向地心。
getOrientation方法的返回值表示:
values[0]: azimuth, rotation around the Z axis.
values[1]: pitch, rotation around the X axis.
values[2]: roll, rotation around the Y axis.
并且这三个角度值都是以弧度做单位,逆时针方向为正。
方向传感器的返回值说明
方向传感器是利用加速度计和地磁场传感器得到自己的数据。
方向传感器比较特殊,因为它的数值是相对于绝对方向的。它得到的是手机设备的绝对姿态值。
一个方向传感器得到的三维数据如下:
(参见http://developer.android.com/guide/topics/sensors/sensors_position.html#sensors-pos-orient)
方向传感器返回的都是角度值,以度数为单位。
注意下面说的x、y、z轴均是手机自身的坐标轴。
第一个角度:Azimuth (degrees of rotation around the z axis).
表示手机自身的y轴与地磁场北极方向的角度,即手机顶部朝向与正北方向的角度。
(This is the angle between magnetic north and the device's y axis. )
当手机绕着自身的z轴旋转时,该角度值将发生改变。
例如该角度值为0时,表示手机顶部指向正北;该角度为90度时,代表手机顶部指向正东;该角度为180度时,代表手机顶部指向正南;该角度为270度时,代表手机顶部指向正西。
第二个角度:Pitch (degrees of rotation around the x axis).
表示手机顶部或尾部翘起的角度。
当手机绕着自身的x轴旋转,该角度会发生变化,值的范围是-180到180度。
当z轴正向朝着y轴正向旋转时,该角度是正值;当z轴正向朝着y轴负向旋转时,该角度是负值。
假设将手机屏幕朝上水平放在桌子上,如果桌子是完全水平的,该角度应该是0。
假如从手机顶部抬起,直到将手机沿x轴旋转180度(屏幕向下水平放在桌面上),这个过程中,该角度值会从0变化到-180。
如果从手机底部开始抬起,直到将手机沿x轴旋转180度(屏幕向下水平放在桌面上),该角度的值会从0变化到180。
第三个角度:Roll (degrees of rotation around the y axis).
表示手机左侧或右侧翘起的角度。
当手机绕着自身x轴旋转时,该角度值将会发生变化,取值范围是-90到90度。
当z轴正向朝着x轴正向旋转时,该角度是负值;
当z轴正向朝着x轴负向旋转时,该角度是正值。\
(这里跟官方文档的说法有点不太一致,即第三个角度的正负号正好相反,我不知道是文档写错了,还是它用了别的什么坐标系)。
因为通过真机测试,结果如下:
将手机屏幕朝上水平放在桌子上,如果桌子是完全水平的,该角度应该是0。
假如将手机左侧逐渐抬起,直到将手机沿Y轴旋转90度(手机与桌面垂直),在这个旋转过程中,该角度会从0变化到-90。
如果从手机的右侧开始抬起,直到将手机沿Y轴旋转90度(手机与桌面垂直),该角度的值会从0变化到90度。
其他说明:
由于需要计算,所以方向传感器的准确度和精度都会受到影响。
官方文档上说,只有当第三个roll的角度值为0的时候得到的值比较可靠。
specifically, this sensor is only reliable when the roll component is 0。
所以从Android 2.2 (API level 8)开始,不建议使用方向传感器。
建议使用 getRotationMatrix()
和getOrientation()
结合来计算方向值。
也可以利用 remapCoordinateSystem()
方法来进行一些方向值向其他坐标系的转换。
5. 运动传感器 Motion Sensors
Android平台提供了一些监控设备运动的传感器。
运动传感器中有两个永远是基于硬件的,即加速度计和陀螺仪(accelerometer and gyroscope)。
运动传感器中有三个是既可以基于硬件又可以基于软件的,即重力感应器、线性加速度计、旋转向量传感器。
运动传感器用来监测设备的运动,比如倾斜,震动,旋转或摇摆(tilt, shake, rotation, or swing)。
运动传感器的返回值
所有的运动传感器都返回一个多维的向量值,保存在SensorEvent的values数组中。
参见链接:https://developer.android.google.cn/guide/topics/sensors/sensors_motion
image.png加速度计Accelerometer
加速度传感器测量作用于设备的加速度Ad:
Ad = -∑Fs / mass
公式中是施加于设备的外力之和和设备质量的比值。
但是,重力加速度会影响这个公式:
Ad = -g -∑F / mass
我的理解是:Ad是设备的实际加速度(我们想知道的值),而加速度的读数是一个受到了重力影响的读数。即Ad+9.81;
比如,把设备静止地平放在桌面上,这时,Ad是零;加速度计的读数大小是重力加速度的数值g = 9.81 m/s2。这个常量值的大小可以用STANDARD_GRAVITY来表示。
而当设备自由落体时,它以9.81 m/s2的加速度向地面运动,Ad为-9.81 m/s2,这时加速度计的读数应该是0。
坐标系的设置
当把设备平放在桌面上,以它的自然方向放置:
如果你从设备左边推它,它往右移,这时它的X加速度值是正的;
如果你从设备下方推它,它将朝着远离你的方向移动,这时它的Y加速度值是正的;
如果你把设备以A m/s2的加速度推向天空,Z轴的加速度值应当等于A + 9.81,(which corresponds to the acceleration of the device (+A m/s2) minus the force of gravity (-9.81 m/s2))。
重力传感器Gravity Sensor
重力传感器测量的是重力值在三个方向上的大小。
重力传感器和加速度传感器的单位一样m/s2,并且它们使用的坐标系也一样。
当设备静止时,重力传感器的输出和加速度传感器的输出是完全一致的。
陀螺仪Gyroscope
陀螺仪测量的是设备绕三个轴向的旋转速度,单位是rad/s。
所使用的坐标系统仍然和加速度计的一样。
旋转的值在逆时针方向为正,即,如果一个观察者从某个轴的正向某点向原点看,如果观察到的旋转是逆时针的,则是一个正值的旋转。这是一个关于旋转方向的标准的数学定义,注意,这个和方向传感器所用的定义不同。
陀螺仪的输出需要对时间积分来计算。有一个例子见:http://developer.android.com/guide/topics/sensors/sensors_motion.html
标准的陀螺仪提供原始的旋转数据,对噪声和漂移没有过滤和校正。
实际运用时,陀螺仪的噪声和漂移会引入错误,所以需要被补偿。通常可以通过其他传感器(重力传感器或加速度计)来检测噪声和漂移。
线性加速度计Linear Accelerometer
线性加速度计提供了沿着每个轴的加速度值,并且是排除了重力的值。
即:linear acceleration = acceleration - acceleration due to gravity
它所使用的单位和坐标系都和加速度计相同。
线性加速度计有一个偏移值(offset),你需要移除这个偏移值,比较简单的方法是在你的应用一开始设置一个标定步骤:让用户把设备放在桌子上,然后读出三个轴的offset值,之后,在从线性加速度计中读数的时候减去这个offset值,就可以得到实际的线性加速度值。
旋转向量传感器Rotation Vector Sensor
旋转向量用一个角度和轴向的组合来表达设备的方向信息。比如,设备绕着某一个轴向旋转了一个角度 θ。
旋转向量的三个元素的值如下:
x*sin(θ/2)
y*sin(θ/2)
z*sin(θ/2)
rotation vector的大小是sin(θ/2),方向是它的旋转轴向。
旋转向量没有单位。
X轴指向东,Y轴指向北,Z轴与地面垂直,指向天空。
6. 位置传感器Position Sensors
Android平台提供了两种决定设备位置的传感器:
地磁场传感器和方向传感器(the geomagnetic field sensor and the orientation sensor)。
还有一种传感器用于检测设备正面和其他物体的距离,叫做接近传感器(proximity sensor)。
地磁场传感器和接近传感器是基于硬件的。
方向传感器是基于软件的,它的数据是根据加速度计和地磁场传感器导出的。
但是方向传感器自从Android 2.2 (API Level 8)开始就被废弃了。
位置传感器也是返回一个多维向量,放在 SensorEvent
中的values数组中。
返回值见表:
img方向传感器Orientation Sensor
方向传感器是根据地磁场传感器和加速度计推导出输出数据的。
使用这两个硬件传感器,方向传感器为下面三个方向提供了数据:
1. Azimuth:绕Z轴旋转的度数。这是设备的y轴和地磁场北极的夹角。比如,设备的y轴指向东,这个度数就为90。
2. Pitch:绕X轴旋转的度数。当设备的z轴朝着y轴正向旋转时,这个值是正值,反之,当设备的z轴朝着y轴的负向旋转时,这个值为负值。它的取值范围是-180到180。
3. Roll:绕Y轴旋转的度数。当设备的z轴朝着x轴正向旋转时,这个值是正值,反之,当设备的z轴朝着x轴的负向旋转时,这个值为负值。它的取值范围是-90到90。
注意这个定义是非常特殊的,因为它在顺时针旋转的时候是正值,而数学上总是逆时针为正值。
因为方向传感器需要大量的处理运算,所以它的准确度和精度都有所下降。后来,自Android 2.2 (API level 8),方向传感器被废弃。自Android 4.4W (API level 20),方向传感器类型被废弃。
官方建议使用下面的方法:
利用getRotationMatrix()结合getOrientation()方法可以计算方向值。
https://developer.android.google.cn/guide/topics/sensors/sensors_position#sensors-pos-orient
还可以利用remapCoordinateSystem()把方向值转换到你的应用的参考坐标系。
地磁场传感器Geomagnetic Field Sensor
地磁场传感器监测地球地磁场变化。
传感器提供三个坐标上的原始的磁场强度值(in μT)。
一般情况下,你不需要直接使用这个传感器,你可以使用旋转向量传感器来决定原始的旋转运动;你也可以使用加速度计和地磁场传感器并结合getRotationMatrix()方法来获得旋转矩阵和倾斜矩阵。
你可以结合 getOrientation()
和 getInclination()
方法来使用这些矩阵,从而得到方位和地磁场偏移数据。
接近传感器Proximity Sensor
接近传感器可以让你得到设备离另一个物体的距离。
接近传感器通常用于检测设备正面和用户头部的距离,比如用户正在打电话。
大多数Proximity Sensor返回绝对的距离数值,以cm为单位。但是也有一些只返回近或者远。
7. Android Sensor Framework 概览
7.1 Overview
Android Sensor Framework 的整体架构如图所示:
图片 1Android Sensor Framework 可以分为 3 大部分,各个部分的主要功能如下:
SDK
这一部分主要功能是为 Application 提供 Java API 接口,以便 Application 可以开启所需的 Sensor 并获取数据。
Framework
这一部分主要有 Sensor Service 构成,主要实现了 Sensor 数据流和控制流。
Libraries
这一部分是 Sensor 的硬件抽象层(HAL),它实现了 Sensor 的具体操作和数据获取功能。同时,它还进行虚拟 Sensor,电子罗盘等相关的算法处理过程。此模块通常以一个动态链接库的形式提供。
7.2 Android Sensor Framework 类图
图片 27.3 Android Sensor SDK
上图中的 Client 部分内容即为 Android Sensor SDK 的主要构成。主要类的主要功能如下:
SensorManager
该类主要封装了 Sensor 相关的 API ,提供给 Application 使用。
文件路径:frameworks/base/core/java/android/hardware/SensorManager.java
SystemSensorManager
该类主要实现 SensorManager 控制和数据获取的逻辑。
文件路径:frameworks/base/core/java/android/hardware/SystemSensorManager.java
android_hardware_SensorManager.cpp
该文件负责 jave 层和 native 层通信的 JNI 实现,上层的 Java 代码通过 JNI 调用 Native 层提供的服务。
文件路径:frameworks/base/core/jni/android_hardware_SensorManager.cpp
SensorManager.cpp
Sensor 在 Native 层的客户端,负责与服务端 SensorService.cpp 的通信
文件路径:frameworks/native/libs/gui/SensorManager.cpp
7.4 Android Sensor Native Framework
上图中的 Server 部分内容即为 Android Sensor Native Framwork 的主要构成。主要类的主要功能如下:
SensorService.cpp
SensorService 是 Android Sensor Framework 最核心的模块,它实现了主要的 Sensor控制流和数据流逻辑,完成 Sensor 参数配置,数据分发,Client 请求处理等功能。
文件路径:frameworks/native/services/sensorservice/SensorService.cpp
BinderService
BinderService 是 Android Service 框架的主要类,它提供了 Service 的生命周期管理、进程间通信、请求响应处理等功能。Android 中的绝大部分 Service 都会继承此类。
文件路径:frameworks/native/include/binder/BinderService.h
BnSensorServer
该类提供类 Sensor 信息获取以及 SensorEventConnection 创建的功能。
文件路径:frameworks/native/include/gui/ISensorServer.h
SensorEventConnection
SensorEventConnection 是 Sensor 数据的传输通道,当 Client 开始监听某一个 Sensor 是,一个对应的 SensorEventConnection 将会被创建,Server 端在接收到 Sensor 数据后,通过写入到 SensorEventConnection 传递给 Client 端。
文件路径:frameworks/native/libs/gui/ISensorEventConnection.cpp
Bittube
该类为单向字节管道,提供进程间单向数据通信功能。SensorEventConnection 是基于 Bittube 实现的。
文件路径:frameworks/native/libs/gui/BitTube.cpp
SensorDevice
该类负责管理和维护系统中的所有 Sensor,封装了 Sensor 的使能、配置、数据读取等功能。
文件路径:frameworks/native/services/sensorservice/SensorDevice.cpp
7.5 Android Sensor HAL
Android 定义了一系列 Sensor HAL 接口,实际的 Sensor HAL 库需要实现这些接口,主要的接口如下:
7.5.1 SensorList
SensorList 定义了 HAL 层提供的 Sensor,提供 Sensor 类型、供应商、功耗等信息。同时,HAL 层需要实现获取 SensorList 的回调接口。
7.5.2 sensors_module_t
HAL 层需要定义一个 sensors_module_t,供系统在启动时加载 Sensor HAL 动态库。sensors_module_t 向上层注册获取 SensorList 和获取 Sensor 控制接口的相关回调函数。
7.5.3 Sensor 控制和数据获取接口
HAL 层还需要提供实际控制和获取 Sensor 数据的接口,SensorService 中对 Sensor 的控制和数据的获取最终会调用到这些接口。
7.6 Android Sensor Framework的初始化流程
7.6.1 Android Sensor Service 初始化
图片 3 图片 3Kernel 在启动完成后,会执行 init 程序,该程序接着解析 init.rc 文件,启动 zygote,最终会执行 Zyoteinit.java 中的 main 函数。
在 Zygoteinit 的main 函数执行过程中,会调用 startSystemServer 接口,该接口最终会调用 native 层的 nativeforkSystemServer 接口,进而启动 SystemServer ,调用其 main 函数。
在 SystemServer 的 main 函数中,会调用对应的 nativeInit 接口。在 nativeInit 中,会创建第一个 SensorService 实例。当 SensorService 第一个实例创建时,其 onFirstRef 接口将会被调用。
图片 4 图片 4在 SensorService 的 onFirstRef 接口中,会创建 SensorDevice 的实例。在 SensorDevice 的构造函数中,会调用 hw_get_module 接口加载 Sensor HAL 的动态库,接着调用 Sensor HAL 提供的 open 接口,执行 Sensor HAL 的初始化。 接着 SensorService 通过 SensorDevice,调用 Sensor HAL 提供的 get_sensors_list 接口,获取所支持的 Sensor 信息。 而后,SensorService 会创建一个 Looper 和 SensorEventAckReceiver。其中 Looper 用于 enable sensor 后,进行数据的接收;而 SensorEventAckReceiver 则用于在 dispatch wake up sensor event 给上层后,接收上层返回的确认 ACK。 至此,SensorService 初始化完毕。
7.6.2 Android Sensor HAL 加载
在 SensorService 创建 SensorDevice 时,会调用 hw_get_module 接口加载 SensorHAL 的动态库文件。 在64位的系统中,hw_get_module 接口会在 /vendor/lib64/hw 和 /system/lib64/hw 目录下搜索 SensorHAL 动态库文件,前者的优先级高。 hw_get_module 会获取依次获取 “ro.hardware.sensors”,”ro.hardware”,”ro.product.board”,”ro.board.platform”,”ro.arch” property 的值作为 subname,并以 sensors.subname.so 作为 SensorHAL 动态库的文件名,在上述两个目录中搜索文件是否存在,如果都没有搜索到,那么最后会用 sensors.default.so 作为文件名,进行搜索。 当搜索到 SensorHAL 的动态库文件后,就会调用 load 接口进行加载操作。 具体的流程可以查看参考链接中的源代码:
7.6.3 Android Sensor Manager 初始化
图片 5APP 在获取 Sensor 数据前,需要获取一个 SensorManager 对象。而在其构造函数中,会先调用 nativeClassInit 和 nativeGetNextSensor 获取系统支持的所有 Sensor 的参数(注,nativeClassInit 只会调用一次),包括名称、类型等参数。后续的相关接口,会用到这些参数。
7.7 Android Sensor Framework的数据流程分析
图片 6当上层调用 registerListener 接口时,相应的 sensor 就会被 enable。SensorService 在调用 HAL 提供的 enable 接口前,会先调用 batch 接口,对 sensor 的采样率、数据上报频率等进行配置。另外,如果 sensor 已经被 enable 了,那么 SensorService 就只调用 batch 和 flush 接口。 SensorService 在 onFirstRef 时创建了一个 Looper,该 Looper 的执行线程会调用 poll 接口,并阻塞在 sensor 的数据管道,当 sensor 有数据返回时,SensorService 会通过 SensorEventQueue 发送到上层,并最终分发到各个 listener。
网友评论