SensorActivity.java
在应用程序中使用传感器需要用到 hardware 包中的 SensorManager 、 SensorListener 等相关的类,具体的实现代码如下:
public class SensorActivity extends Activity {
private static final String TAG = "SensorActivity" ;
SensorManager mySM ;
SensorListener mySL = new SensorListener (){
public void onAccuracyChanged( int sensor, int accuracy) {
}
public void onSensorChanged( int sensor, float [] values) {
switch (sensor) {
case SensorManager. SENSOR_ACCELEROMETER :
Log.i ( TAG , "Accelerometer: "
+ values[0] + ", "
+ values[1] + ", "
+ values[2]);
break ;
}
}
};
public void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout. main );
mySM =(SensorManager)getSystemService( SENSOR_SERVICE );
}
protected void onPause() {
mySM .unregisterListener( mySL );
super .onPause();
}
protected void onResume() {
mySM .registerListener( mySL ,SensorManager. SENSOR_ACCELEROMETER ,
SensorManager. SENSOR_DELAY_UI );
super .onResume();
}
}
这段代码特别简单,利用了大家熟悉的观察者模式对传感器数据进行监听处理,接下来,我们就分析这段代码背后的机制,看看 Android 为我们做了什么,才把貌似复杂的传感器处理简化到了这样几行代码就可以实现的程度。
SensorManager.java
对应用程序来说,最重要的就是把 SensorListener 注册到 SensorManager 上,从而才能以观察者身份接收到数据的变化,因此,我们把目光落在 SensorManager 的构造函数、 RegisterListener 函数和通知机制相关的代码上。
先来看构造函数的代码:
public SensorManager(Looper mainLooper) {
mSensorService = ISensorService.Stub.asInterface(
ServiceManager.getService(Context.SENSOR_SERVICE));
……
// initialize the sensor list
sensors_module_init();
final ArrayList<Sensor> fullList = sFullSensorsList;
int i = 0;
do {
Sensor sensor = new Sensor();
i = sensors_module_get_next_sensor(sensor, i);
if (i>=0) {
sensor.setLegacyType(getLegacySensorType(sensor.getType()));
fullList.add(sensor);
sHandleToSensor.append(sensor.getHandle(), sensor);
}
} while (i>0);
……
sSensorThread = new SensorThread();
}
在这段代码中我们关注三件事,一是利用 ISensorService 接口获取了对 SensorService 的引用;二是利用 sensors_module_init() 等函数完成了传感器列表的初始化;三是创建了一个 SensorThread 线程对象。
在此处,并没有启动 SensorThread 线程,也没有看到明显的操作传感器的动作,接下来,再分析一下 registerListener() 函数的代码:
public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate,
Handler handler) {
……
l = new ListenerDelegate(listener, sensor, handler);
sListeners.add(l);
if (!sListeners.isEmpty()) {
result = sSensorThread.startLocked (mSensorService);
if (result) {
result = mSensorService.enableSensor (l, name, handle, delay);
}
}
……
}
在这段代码中值得注意的是 SensorThread 线程被启动,通过 SensorService 的 EnableSensor 方法传感器将被打开进入工作状态。
再来看一下 SensorThread 的代码,在它的构造函数中调用了 sensors_data_init() 函数,在 startLocked() 函数中启动了线程,在线程 run() 函数中调用了 sensors_data_open() 函数,然后
while (true) {
// wait for an event
final int sensor = sensors_data_poll(values, status, timestamp);
final Sensor sensorObject = sHandleToSensor.get(sensor);
if (sensorObject != null) {
// report the sensor event to all listeners that
// care about it.
final int size = sListeners.size();
for (int i=0 ; i<size ; i++) {
ListenerDelegate listener = sListeners.get(i);
if (listener.hasSensor(sensorObject)) {
// this is asynchronous (okay to call
// with sListeners lock held).
listener.onSensorChangedLocked(sensorObject,
values, timestamp, accuracy);
}
}
}
}
即通过 sensors_data_poll() 函数等待硬件传感器的事件,调用 listener.onSensorChangedLocked() 函数,在该函数中调用了 SensorListener 中的 onSensorChanged() ,即调到了应用程序的观察者接口。
至此, SensorManager 中的主要逻辑已经理清了,还有两个部分,一是 SensorService 的逻辑还没有涉及;二是 sensors_data_init() 相关的一组函数做了什么还没涉及。先来看一下 SensorService 的相关部分。
SensorService.java
SensorService 代码中可以看到,主要做的就是对传感器的控制,包括初始化、开、关、激活、设置延迟参数、睡眠几个动作,用的函数是一组类似 _sensors_control_init() 的函数,比如前文提到的 enableSensor() 的代码是:
if (_sensors_control_activate(sensor, true) == false) {
Slog.w(TAG, "could not enable sensor " + sensor);
return false;
}
在 JAVA 的代码里面,对于前文提到的两组函数 sensor_data_XXX() 和 _sensor_control_XXX() 都是采用 native 的方式进行的 JNI 调用,接下来就透过 JNI ,来看相关的 CPP 代码。
Sensors.h
在看 CPP 代码前,先来看一下 Sensors.h 文件,这个文件将被 CPP 包含,从文件里的信息来看,这个是 HAL (硬件抽象层)的接口文件,里面提供了 device 的结构体封装及一些设备驱动应用提供的操作函数,注意这些函数将被传感器的驱动程序实现,在此不并心驱动的实现,只要知道驱动能提供这些函数供上层程序调用就可以了,这也就是 HAL 的作用,对不同的设备向上层提供统一的调用接口。
SensorManager.cpp
这个文件提供了对传感器数据部分的操作,实现了前文提到的一组 sensor_data_XXX() 函数,如果对驱动有点熟悉的话,可以看到
static jint
sensors_module_init(JNIEnv *env, jclass clazz)
{
int err = 0;
sensors_module_t const* module;
err = hw_get_module(SENSORS_HARDWARE_MODULE_ID, (const hw_module_t **)&module);
if (err == 0)
sSensorModule = (sensors_module_t*)module;
return err;
}
这个函数通过 hw_get_module 加载了驱动程序。
static jint
sensors_data_poll(JNIEnv *env, jclass clazz,
jfloatArray values, jintArray status, jlongArray timestamp)
{
sensors_data_t data;
int res = sSensorDevice->poll(sSensorDevice, &data);
if (res >= 0) {
jint accuracy = data.vector.status;
env->SetFloatArrayRegion(values, 0, 3, data.vector.v);
env->SetIntArrayRegion(status, 0, 1, &accuracy);
env->SetLongArrayRegion(timestamp, 0, 1, &data.time);
}
return res;
}
这个函数通过 sSensorDevice->poll() 函数等待设备的数据到来,并将数据通过 JNI 规则传递到上层的数组中去。
SensorService.cpp
这里的代码与 SensorManager.cpp 类似,比如:
static jboolean
android_activate(JNIEnv *env, jclass clazz, jint sensor, jboolean activate)
{
int active = sSensorDevice->activate(sSensorDevice, sensor, activate);
return (active<0) ? false : true;
}
调用了 sSensorDevice->activate() 函数使能特定的传感器。其他函数就不一一列举了。
Sensors.c
最后,就是驱动程序了,利用硬件手册,遵循驱动程序的框架,将 sensors.h 中的结构体的函数指针赋值即可。不是本文的关注点,就不再详细解析了。
总结
1. 通过上述对源码的分析过程,可以对应到 Android 架构图的各个层次,是一次上下贯通的过程,参照架构图可以看到:
SensorActivity.java 对应的是 Application 层,是应用程序。
SensorManager.java , SensorListener.java 对应的是 Frameworks 层,是 Android 提供的应用程序开发接口,应用程序框架。与应用程序的调用是通过类实例化或类继承进行的。
SensorManager.cpp , SensorService.cpp 对应的是 Libraries 层,是 Android 提供的底层库,与 Frameworks 的调用是通过 JNI 实现的跨语言调用。
Sensors.h 是 HAL 层,即硬件抽象层,这里提供了 Android 独立于具体硬件的抽象接口。
Sensors.c 是 Linux Kernel 层,是具体的硬件设备驱动程序。
2. 通过上述分析,可以进一步了解 Android 系统的 Binder 接口机制。这里使用了简化的 IBinder 接口,可能是原设计人员考虑到了这部分相对独立且简单,所以没有使用此前关于 IPC 机制学习中用到的 Proxy 模式,而只是用 ISensorService.Stub 接口直接使用了内核服务,但与前文了解到的 IPC 机制不冲突。
——欢迎转载,转载请注明出处,谢谢——