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的負值。
當設備運動或者旋轉的時候,這些坐標軸是不會改變的,即它們是跟隨手機的。
即是說,手機坐標系是跟隨設備的自然方向的(但是請記住自然方向不一定是豎直,比如平板它的自然方向就很有可能是橫向)。
使用這個坐標系的傳感器:
即是說它們的度數顯示了在手機的這三個軸上的數字大小。
屏幕旋轉
常常要考慮屏幕的旋轉,即屏幕畫面相對于自然方向的旋轉。
于是就需要使用 getRotation()方法來獲取屏幕的旋轉值。
這個方法是Display類中的,跟傳感器不相關。
這個方法的返回值只對應0,90,180,270四種旋轉情況,它說明屏幕顯示區域的旋轉情況。
世界坐標系
有一些傳感器和方法使用相對于世界的坐標系,因為它們返回的數據反映設備相對于地球及真實環境的位置信息。
請見getOrientation() 方法,getRotationMatrix() 方法,Orientation Sensor, 和 Rotation Vector Sensor。
getRotationMatrix()
getRotationMatrix()方法說明中,定義的世界坐標系如下:
?X軸平行于地面,指向東方。
Y軸平行于地面,指向北極方向。
Z軸垂直于地面,指向天空。
getOrientation()
getOrientation() 方法中所用的坐標系與上面的不同:
?X軸平行于地面,指向西方;
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
加速度計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數組中。
返回值見表:
方向傳感器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 的整體架構如圖所示:
Android Sensor Framework 可以分為 3 大部分,各個部分的主要功能如下:
SDK
這一部分主要功能是為 Application 提供 Java API 接口,以便 Application 可以開啟所需的 Sensor 并獲取數據。
Framework
這一部分主要有 Sensor Service 構成,主要實現了 Sensor 數據流和控制流。
Libraries
這一部分是 Sensor 的硬件抽象層(HAL),它實現了 Sensor 的具體操作和數據獲取功能。同時,它還進行虛擬 Sensor,電子羅盤等相關的算法處理過程。此模塊通常以一個動態鏈接庫的形式提供。
7.2 Android Sensor Framework 類圖
7.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 初始化
圖片 3Kernel 在啟動完成后,會執行 init 程序,該程序接著解析 init.rc 文件,啟動 zygote,最終會執行 Zyoteinit.java 中的 main 函數。
在 Zygoteinit 的main 函數執行過程中,會調用 startSystemServer 接口,該接口最終會調用 native 層的 nativeforkSystemServer 接口,進而啟動 SystemServer ,調用其 main 函數。
在 SystemServer 的 main 函數中,會調用對應的 nativeInit 接口。在 nativeInit 中,會創建第一個 SensorService 實例。當 SensorService 第一個實例創建時,其 onFirstRef 接口將會被調用。
圖片 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 初始化
APP 在獲取 Sensor 數據前,需要獲取一個 SensorManager 對象。而在其構造函數中,會先調用 nativeClassInit 和 nativeGetNextSensor 獲取系統支持的所有 Sensor 的參數(注,nativeClassInit 只會調用一次),包括名稱、類型等參數。后續的相關接口,會用到這些參數。
7.7 Android Sensor Framework的數據流程分析
當上層調用 registerListener 接口時,相應的 sensor 就會被 enable。SensorService 在調用 HAL 提供的 enable 接口前,會先調用 batch 接口,對 sensor 的采樣率、數據上報頻率等進行配置。另外,如果 sensor 已經被 enable 了,那么 SensorService 就只調用 batch 和 flush 接口。 SensorService 在 onFirstRef 時創建了一個 Looper,該 Looper 的執行線程會調用 poll 接口,并阻塞在 sensor 的數據管道,當 sensor 有數據返回時,SensorService 會通過 SensorEventQueue 發送到上層,并最終分發到各個 listener。