Android Sensor 介绍

Posted 爱吃香蕉的猴子0000

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Sensor 介绍相关的知识,希望对你有一定的参考价值。

android Sensor 介绍

hi,大家好,我是爱吃香蕉的猴子,今天记录一下 Sensor的学习;
推荐文章感谢大神

目录
  1. Sensor的介绍
  2. Android 上层Sensor的使用
  3. Sensor的基础架构
  4. 客户端和服务端通信

一、Sensor介绍

  • Sensor的类型
    在这里插入图片描述
  • 加速度传感器: 测试设备重力情况,相对于外部参照物;
    在这里插入图片描述
  • 磁感应传感器:定位设备的方位,可以测量出当前设备与东西南北四个方向上的夹角;
    在这里插入图片描述
  • 陀螺仪:测量设备自身的旋转运动。对设备自身运动更擅长。但不能确定设备的方向。
    在这里插入图片描述

Android 上层Sensor的使用

   //实例化传感器的管理器
    sensorManager = (SensorManager) getSystemService(this.SENSOR_SERVICE);  
    //获取所有的管理器
    sensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
    
    sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    String name = sensor.getName();//名称
    ...
    onStart() {
    //在onStart中注册传感器的监听事件
    sensorManager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_FASTEST);
    
    //传感器监听对象
    SensorEventListener listener = new SensorEventListener() {

二、Sensor的基础架构

  • Sensor框架分为三个层次:客户端、服务端、HAL层,服务端负责从HAL读取数据,并将数据写到管道中,客户端通过管道读取服务端数据;
    在这里插入图片描述

补充两条code
在这里插入图片描述
在这里插入图片描述
基础图做解析

  • 客户端
    • SensorManager.cpp
      • 负责和服务端SensorService.cpp的通信
      • SensorEventQueue.cpp 消息队列
      • 接口
        • getSensorList()
        • getDefaultSensor()
  • 服务端
    • SensorService.cpp
      • 服务端数据处理中心
      • SensorEventConnection 从BnSensorEventConnection继承来,实现接口ISensorEventConnection的一些方法,ISensorEventConnection在SensorEventQueue会保存一个指针,指向调用服务接口创建的SensorEventConnection对象
      • SensorService创建完之后,将会调用SensorService::onFirstRef()方法,在该方法中完成初始化工作。
      • 首先获取SensorDevice实例,在其构造函数中,完成了对Sensor模块HAL的初始化:
    • Bittube.cpp
      • 在这个类中创建管道,用于服务端与客户端读写数据
    • SensorDevice
      • 负责与HAL读取数据
        --------------------------------------------------------- 短暂分割线 ------------------------------------
        客户端的具体实现
    • Apk的监听
SensorManager  mSensorManager =
 (SensorManager)getSystemService(SENSOR_SERVICE);
 Sensor   mAccelerometer =
 mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
 
    protected void onResume() {
           super.onResume();
          mSensorManager. registerListenerImpl (this, mAccelerometer,
     SensorManager.SENSOR_DELAY_NORMAL);
     }
     protected void onPause() {
           super.onPause();
         mSensorManager.unregisterListener(this);
     }
 
public interface SensorEventListener {
    public void onSensorChanged(SensorEvent event);
    public void onAccuracyChanged(Sensor sensor, int accuracy);   
}
1Activity实现了SensorEventListener接口。
2、在onCreate方法中,获取SystemSensorManager,并获取到加速传感器的Sensor3、在onResume方法中调用SystemSensorManager,registerListenerImpl注册监听器;
4、当Sensor数据有改变的时候将会回调onSensorChanged方法。
  • 初始化SystemSensorManager
public SystemSensorManager(Context context,Looper mainLooper) {
        mMainLooper = mainLooper;       
              mContext = context;
            
        synchronized(sListeners) {
            if (!sSensorModuleInitialized) {
                sSensorModuleInitialized = true;
 
                nativeClassInit();
 
                // 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) {
                        //Log.d(TAG, "found sensor: " + sensor.getName() +
                        //        ", handle=" + sensor.getHandle());
                        fullList.add(sensor);
                        sHandleToSensor.append(sensor.getHandle(), sensor);
                    }
                } while (i>0);
 
                sPool = new SensorEventPool( sFullSensorsList.size()*2 );
                sSensorThread = new SensorThread();
            }
        }
    }
系统开机启动的时候,会创建SystemSensorManager的实例,在其构造函数中,主要做了四件事情:
1、初始化JNI:调用JNI函数nativeClassInit()进行初始化
2、初始化Sensor列表:调用JNI函数sensors_module_init,对Sensor模块进行初始化。创建了nativeSensorManager的实例。
3、获取Sensor列表:调用JNI函数sensors_module_get_next_sensor()获取Sensor,并存在sHandleToSensor列表中
4、构造SensorThread类:构造线程的类函数,并没有启动线程,当有应用注册的时候才会启动线程
  • 启动SensorThread线程读取消息队列中的数据
protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
            int delay, Handler handler) {
    
        synchronized (sListeners) {
            ListenerDelegate l = null;
            for (ListenerDelegate i : sListeners) {
                if (i.getListener() == listener) {
                    l = i;
                }
            }
            …….
            // if we don't find it, add it to the list
            if (l == null) {
                l = new ListenerDelegate(listener, sensor, handler);
                sListeners.add(l);
                  ……
                    if (sSensorThread.startLocked()) {
                        if (!enableSensorLocked(sensor, delay)) {
                          …….
                        }
                 ……
            } else if (!l.hasSensor(sensor)) {
                l.addSensor(sensor);
                if (!enableSensorLocked(sensor, delay)) {
                    ……
                }
            }
        }
        return result;
    }
  当有应用程序调用registerListenerImpl()方法注册监听的时候,会调用SensorThread.startLoacked()启动线程。
  线程只会启动一次,并调用enableSensorLocked()接口对指定的sensor使能,并设置采样时间。
  SensorThreadRunnable实现了Runnable接口,在SensorThread类中被启动
  boolean startLocked() {
            try {
                if (mThread == null) {
                    SensorThreadRunnable runnable = new SensorThreadRunnable();
                    Thread thread = new Thread(runnable, SensorThread.class.getName());
                    thread.start();
                    synchronized (runnable) {  //队列创建成功,线程同步
                        while (mSensorsReady == false) {
                            runnable.wait();
                        }
                    }
                  
        }
private class SensorThreadRunnable implements Runnable {
            SensorThreadRunnable() {
            }
            private boolean open() {
                sQueue = sensors_create_queue();
                return true;
            }
            public void run() {
                …….
                if (!open()) {
                    return;
                }
                synchronized (this) {
                    mSensorsReady = true;
                    this.notify();
                }
                while (true) {
                    final int sensor = sensors_data_poll(sQueue, values, status, timestamp);
                    …….
            }
        }
    }
 在open函数中调用JNI函数sensors_create_queue()来创建消息队列,然后调用SensorManager. createEventQueue()创建。
 在startLocked函数中启动新的线程后,做了一个while的等待while (mSensorsReady == false),只有当mSensorsReady等于true的时候,才会执行enableSensorLocked()函数对sensor使能。而mSensorsReady变量,是在open()调用创建消息队列成功之后才会true,所以认为,三个功能调用顺序是如下:
1、调用open函数创建消息队列
2、调用enableSensorLocked()函数对sensor使能
3、调用sensors_data_poll从消息队列中读取数据,而且是在while (true)循环里一直读取

服务端的具体实现

  • 启动SensorService服务
  • 在SystemServer进程中的main函数中,通过JNI调用,调用到com_android_server_SystemServer.cpp的android_server_SystemServer_init1()方法,该方法又调用system_init.cpp中的system_init():
  • 创建了SensorService的实例:
    • SensorService创建完之后,将会调用SensorService::onFirstRef()方法,在该方法中完成初始化工作。
    • 首先获取SensorDevice实例,在其构造函数中,完成了对Sensor模块HAL的初始化:
SensorDevice::SensorDevice()
    :  mSensorDevice(0),
       mSensorModule(0)
{
    status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID,
            (hw_module_t const**)&mSensorModule);
 
    if (mSensorModule) {
        err = sensors_open(&mSensorModule->common, &mSensorDevice);
 
        ALOGE_IF(err, "couldn't open device for module %s (%s)",
                SENSORS_HARDWARE_MODULE_ID, strerror(-err));
 
        if (mSensorDevice) {
            sensor_t const* list;
            ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);
            mActivationCount.setCapacity(count);
            Info model;
            for (size_t i=0 ; i<size_t(count) ; i++) {
                mActivationCount.add(list[i].handle, model);
                mSensorDevice->activate(mSensorDevice, list[i].handle, 0);
            }
        }
    }
}
这里主要做了三个工作:
调用HAL层的hw_get_modele()方法,加载Sensor模块so文件
调用sensor.h的sensors_open方法打开设备
调用sensors_poll_device_t->activate()对Sensor模块使能
再看看SensorService::onFirstRef()方法:
void SensorService::onFirstRef()
{
    SensorDevice& dev(SensorDevice::getInstance());
 
    if (dev.initCheck() == NO_ERROR) {
        sensor_t const* list;
        ssize_t count = dev.getSensorList(&list);
        if (count > 0) {
            ……
            for (ssize_t i=0 ; i<count ; i++) {
                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)
            const SensorFusion& fusion(SensorFusion::getInstance());
 
            if (hasGyro) {
               ……
            }
            ……
            run("SensorService", PRIORITY_URGENT_DISPLAY);
            mInitCheck = NO_ERROR;
        }
    }
}
在这个方法中,主要做了4件事情:
创建SensorDevice实例
获取Sensor列表
调用SensorDevice.getSensorList(),获取Sensor模块所有传感器列表
为每个传感器注册监听器
registerSensor( new HardwareSensor(list[i]) );

void SensorService::registerSensor(SensorInterface* s)
{
    sensors_event_t event;
    memset(&event, 0, sizeof(event));
 
    const Sensor sensor(s->getSensor());
    // 添加到Sensor列表,给客户端使用
    mSensorList.add(sensor);
    // add to our handle->SensorInterface mapping
    mSensorMap.add(sensor.getHandle(), s);
    // create an entry in the mLastEventSeen array
    mLastEventSeen.add(sensor.getHandle(), event);
}
HardwareSensor实现了SensorInterface接口。
启动线程读取数据
调用run方法启动新线程,将调用SensorService::threadLoop()方法。
  • 新的线程中读取HAL层数据:
    • SensorService实现了Thread类,当在onFirstRef中调用run方法后,将在新的线程中调用SensorService::threadLoop()方法。
bool SensorService::threadLoop()
{
    ……
    do {
        count = device.poll(buffer, numEventMax);
 
        recordLastValue(buffer, count);
        ……
 
        // send our events to clients...
        const SortedVector< wp<SensorEventConnection> > activeConnections(
                getActiveConnections());
        size_t numConnections = activeConnections.size();
        for (size_t i=0 ; i<numConnections ; i++) {
            sp<SensorEventConnection> connection(
                    activeConnections[i].promote());
            if (connection != 0) {
                connection->sendEvents(buffer, count, scratch);
            }
        }
    } while (count >= 0 || Thread::exitPending());
    return false;
}while循环中一直读取HAL层数据,再调用SensorEventConnection->sendEvents将数据写到管道中。

三、客户端和服务端通信
在这里插入图片描述

  • 1、数据传输
    • 概括: 服务端和客户端做了哪里事情??
      • ① 客户端服务端线程
        • 服务端:一个是服务端的一个线程,这个线程负责源源不断的从HAL读取数据。
        • 客户端:另一个是客户端的一个线程,客户端线程负责从消息队列中读数据。
      • ② 创建消息队列
      • 客户端可以创建多个消息队列,一个消息队列对应有一个与服务器通信的连接接口;
      • ③ 创建连接接口
      • 服务端与客户端沟通的桥梁,服务端读取到HAL层数据后,会扫面有多少个与客户端连接的接口,然后往每个接口的管道中写数据;
      • ④ 创建管道
      • 每一个连接接口都有对应的一个管道;
  • 因为在实际使用中,消息队列只会创建一个,也就是说客户端与服务端之间的通信只有一个连接接口,只有一个管道传数据,但是那么数据的形式是怎么从HAL层传到JAVA层的呢? 步入数据传递的正题
  • 其实数据是以一个结构体sensors_event_t的形式从HAL层传到JNI层。看看HAL的sensors_event_t结构体:
typedef struct sensors_event_t {
    int32_t version;
    int32_t sensor;            //标识符
    int32_t type;             //传感器类型
    int32_t reserved0;
    int64_t timestamp;        //时间戳
    union {
        float           data[16];
        sensors_vec_t   acceleration;   //加速度
        sensors_vec_t   magnetic;      //磁矢量
        sensors_vec_t   orientation;     //方向
        sensors_vec_t   gyro;          //陀螺仪
        float           temperature;     //温度
        float           distance;        //距离
        float           light;           //光照
        float           pressure;         //压力
        float           relative_humidity;  //相对湿度
    };
    uint32_t        reserved1[4];
} sensors_event_t;

在JNI层有一个ASensorEvent结构体与sensors_event_t向对应,frameworks/native/include/android/sensor.h:

typedef struct ASensorEvent {
    int32_t version;
    int32_t sensor;
    int32_t type;
    int32_t reserved0;
    int64_t timestamp;
    union {
        float           data[16];
        ASensorVector   vector;
        ASensorVector   acceleration;
        ASensorVector   magnetic;
        float           temperature;
        float           distance;
        float           light;
        float           pressure;
    };
    int32_t reserved1[4];
} ASensorEvent;

  • 2、通信流程
    在这里插入图片描述
  • 经过前面的介绍,现在知道了客户端实现的方式及服务端的实现,但是没有具体讲到它们是如何进行通信的,现在看看客户端与服务端之间的通信。主要涉及的是进程间通信,有IBind和管道通信。客户端通过IBind通信获取到服务端的远程调用,然后通过管道进行sensor数据的传输。
  • ----------------------------------------------------------------短暂分割线------------------------------------------------------
    服务端
  • native层实现了sensor服务的核心实现,Sensor服务的主要流程的实现在sensorservice类中,下面重点分析下这个类的流程。
class SensorService :
        public BinderService<SensorService>,
        public BnSensorServer,
        protected Thread

看看sensorService继承的类:
    继承BinderService<SensorService>这个模板类添加到系统服务,用于Ibinder进程间通信。

template<typename SERVICE>
class BinderService
{
public:
    static status_t publish() {
        sp<IServiceManager> sm(defaultServiceManager());
        return sm->addService(String16(SERVICE::getServiceName()), new SERVICE());
    }
 
    static void publishAndJoinThreadPool() {
        sp<ProcessState> proc(ProcessState::Android9.0源码学习-Sensor Framework

Android课程---Android Studio使用小技巧:提取方法代码片段

哪些设备支持 Android Sensor Batching?

获取Android设备的方向,Sensor和SensorManager实现手机旋转角度

Android Sensor详解Sensor ADSP Sensor1 api使用

Android_传感器光学