zoukankan      html  css  js  c++  java
  • [置顶] Android Sensor系统剖析(4.0)(下)

    Author:Harish_hu@qq.com

        由于现在电脑上只有4.0的代码,考虑到代码差别也不大,所以下部分,就基于4.0来分析。

     3:SensorManager

        上一部分说过,开机后,system server启动时,就会初始化sensor service,也就是说,开机后她一直都在后台运行着,客户端部分,直接connect就行了。至于怎么connect,这一切都被封装到SensorManager里了。

    3.1 SensorManager的创建

    获取SensorManager的对象实例代码:

    mSensorManager =(SensorManager)getSystemService(SENSOR_SERVICE);

    调用Activity的成员函数来获取SensorManager实例,我们从Activity派生关系可以追溯到,这个函数的最终在ContextImpl实现:

     

    //ContextImpl.java
    @Override
    public ObjectgetSystemService(String name) {
    ServiceFetcherfetcher = SYSTEM_SERVICE_MAP.get(name);
    return fetcher ==null ? null : fetcher.getService(this);
    }

    这个函数从SYSTEM_SERVICE_MAP中获取了name对应的特定对象实例,所以从SYSTEM_SERVICE_MAP的初始化,就可以看到SensorManager对象的创建:

     

    //ContextImpl.java
    static{     ...
            registerService(SENSOR_SERVICE, newServiceFetcher() {
                    public ObjectcreateService(ContextImpl ctx) {
                        return newSensorManager(ctx.mMainThread.getHandler().getLooper());
                    }}); ...
    }

    3.2 初始化并连接sensor service

    初始化过程肯定是在构造函数中进行,那如何连接sensor service呢?上一部分说过,sensor service是基于c++代码编写的native binder,客户端要与其连接并交互,当然也是使用c++更方便(我只是说比较方便,当然你如果硬要用java与其建立连接并交互数据,也是可以的).

        如果一种做法可以让你更方便,我想大多数人的选择都是一样的,就是使用C++代码访问服务,然后java代码通过jni调用c++代码,这也是android系统的通用做法;接下去,我们看下SensorManager的jni函数映射:

     

    在android jni中c++类文件的命名规则一般都是java类的package路径+类名,还有一点需要注意的是,这里jni映射函数名都是一样的,这只是这个类的设计者这么命名而已,实际上c++类中的对应函数命名是没有限制的,关于jni的详细描述,大家可查看相关资料,这里就不再赘述.

    在了解了jni函数映射后,后续在java代码中如果调用了native函数,我们将直接跳转到c++代码.

    SensorManager被实例化,地球人都知道构造函数先走,所以接下去看SensorManager构造函数:

     

     public SensorManager(Looper mainLooper) {
            mMainLooper = mainLooper;
            synchronized(sListeners) {
                if (!sSensorModuleInitialized) {
                    sSensorModuleInitialized =true;
                    nativeClassInit();
                    sWindowManager =IWindowManager.Stub.asInterface(
                           ServiceManager.getService("window"));
                    if (sWindowManager != null) {
                        // if it's null we'rerunning in the system process
                        // which won't get therotated values
                        try {
                            sRotation =sWindowManager.watchRotation(
                                    newIRotationWatcher.Stub() {
                                        public voidonRotationChanged(int rotation) {
                                           SensorManager.this.onRotationChanged(rotation);
                                        }
                                    }
                            );
                        } catch (RemoteException e){
                        }
                    }
     
                    // initialize the sensor list
                    sensors_module_init();
                    final ArrayList<Sensor>fullList = sFullSensorsList;
                    int i = 0;
                    do {
                        Sensor sensor = newSensor();
                        i =sensors_module_get_next_sensor(sensor, i);
     
                        if (i>=0) {
                            //Log.d(TAG,"found sensor: " + sensor.getName() +
                            //        ", handle=" + sensor.getHandle());
                           sensor.setLegacyType(getLegacySensorType(sensor.getType()));
                            fullList.add(sensor);
                           sHandleToSensor.append(sensor.getHandle(), sensor);
                        }
                    } while (i>0);
     
                    sPool = new SensorEventPool(sFullSensorsList.size()*2 );
                    sSensorThread = newSensorThread();
                }
            }
        }

    先调用nativeClassInit来初始化JNI相关java类信息,对应C++代码: 

     

    static void
    nativeClassInit(JNIEnv *_env, jclass _this)
    {
        jclass sensorClass =_env->FindClass("android/hardware/Sensor");
        SensorOffsets& sensorOffsets =gSensorOffsets;
        sensorOffsets.name        = _env->GetFieldID(sensorClass,"mName",      "Ljava/lang/String;");
        sensorOffsets.vendor      = _env->GetFieldID(sensorClass,"mVendor",   "Ljava/lang/String;");
        sensorOffsets.version     = _env->GetFieldID(sensorClass,"mVersion",   "I");
        sensorOffsets.handle      = _env->GetFieldID(sensorClass, "mHandle",    "I");
        sensorOffsets.type        = _env->GetFieldID(sensorClass,"mType",      "I");
        sensorOffsets.range       = _env->GetFieldID(sensorClass,"mMaxRange",  "F");
        sensorOffsets.resolution  = _env->GetFieldID(sensorClass,"mResolution","F");
        sensorOffsets.power       = _env->GetFieldID(sensorClass,"mPower",     "F");
        sensorOffsets.minDelay    = _env->GetFieldID(sensorClass,"mMinDelay",  "I");
    }

    从代码上看出,这个函数主要是保存java类Sensor的各个filed的id值,方便后续在c++代码中利用Jni环境向jave层传递数据,这个在后续poll sensor值的时候会用到。接着调用jni函数sensors_module_init,c++代码如下:

     

    static jint
    sensors_module_init(JNIEnv*env, jclass clazz)
    {
        SensorManager::getInstance();
        return 0;
    }

    函数很简单,就调用SensorManager::getInstance实例化SensorManager对象实例。注意这里是jnic++层的实现,SensorManager对象是C++层的对象实例,不要跟上面java层的搞浑了。getInstance,可以明显看出来,这是一个单例对象,继续看c++ SensorManager的构造函数:

     

    SensorManager::SensorManager()
        : mSensorList(0)
    {
        // okay we're not locked here, but it's notneeded during construction
        assertStateLocked();
    }

    构造函数就调了assertStateLocked,继续看这个函数:

     

    status_tSensorManager::assertStateLocked() const {
        if (mSensorServer == NULL) {
            // try for one second
            const String16name("sensorservice");
            for (int i=0 ; i<4 ; i++) {
                status_t err = getService(name,&mSensorServer);
                if (err == NAME_NOT_FOUND) {
                    usleep(250000);
                    continue;
                }
                if (err != NO_ERROR) {
                    return err;
                }
                break;
            }
     
            class DeathObserver : publicIBinder::DeathRecipient {
                SensorManager& mSensorManger;
                virtual void binderDied(constwp<IBinder>& who) {
                    LOGW("sensorservice died[%p]", who.unsafe_get());
                    mSensorManger.sensorManagerDied();
                }
            public:
                DeathObserver(SensorManager&mgr) : mSensorManger(mgr) { }
            };
     
            mDeathObserver = newDeathObserver(*const_cast<SensorManager *>(this));
            mSensorServer->asBinder()->linkToDeath(mDeathObserver);
     
            mSensors =mSensorServer->getSensorList();
            size_t count = mSensors.size();
            mSensorList = (Sensorconst**)malloc(count * sizeof(Sensor*));
            for (size_t i=0 ; i<count ; i++) {
                mSensorList[i] = mSensors.array() +i;
            }
        }
     
        return NO_ERROR;
    }

    这个函数通过getService拿到sensorservice的proxy binder,这样就建立了与sensorservice的数据连接,然后调用getsensorlist从sensorservice获取sensor list并保存。

    ok,到这里,java层的jni函数sensors_module_init()就走完了,我们已经与sensor service建立连接,并已经取得了sensor list,但是这些数据目前是存于c++层的,我们要通过jni将数据拿到java层,所以在java层SensorManager构造函数调用sensors_module_init()后,调用sensors_module_get_next_sensor获取sensor数据并保存。

    下面是jni函数sensors_module_get_next_sensor的c++实现:

     

    //android_hardware_SensorManager.cpp
    static jint
    sensors_module_get_next_sensor(JNIEnv*env, jobject clazz, jobject sensor, jint next)
    {
        SensorManager&mgr(SensorManager::getInstance());
     
        Sensor const* const* sensorList;
        size_t count =mgr.getSensorList(&sensorList);
        if (size_t(next) >= count)
            return -1;
       
        Sensor const* const list =sensorList[next];
        const SensorOffsets&sensorOffsets(gSensorOffsets);
        jstring name =env->NewStringUTF(list->getName().string());
        jstring vendor =env->NewStringUTF(list->getVendor().string());
        env->SetObjectField(sensor,sensorOffsets.name,      name);
        env->SetObjectField(sensor,sensorOffsets.vendor,    vendor);
        env->SetIntField(sensor,sensorOffsets.version,      1);
        env->SetIntField(sensor,sensorOffsets.handle,       list->getHandle());
        env->SetIntField(sensor,sensorOffsets.type,        list->getType());
        env->SetFloatField(sensor,sensorOffsets.range,     list->getMaxValue());
        env->SetFloatField(sensor,sensorOffsets.resolution, list->getResolution());
        env->SetFloatField(sensor,sensorOffsets.power,     list->getPowerUsage());
        env->SetIntField(sensor,sensorOffsets.minDelay,    list->getMinDelay());
       
        next++;
        return size_t(next) < count ? next : 0;
    }

    在这个函数将对应的c++层保存的sensor数据传给jobjectsensor。

    java层SensorManager构造函数最后创建SensorEventPool和sSensorThread, 这两个对象干嘛用的?看名字就知道啦,一个是事件池,sensor 事件很频繁,如果对每一个事件都创建一个新对象,开销太大,弄一个事件池肯定是最好的选择;另外一个是sensor 线程,负责读取sensor 数据.

    3.3 sensor数据读取

        继续来看下应用层获取sensor数据的代码:

     

    public classSensorActivity extends Activity, implements SensorEventListener { 
         private final SensorManagermSensorManager; 
         private final Sensor mAccelerometer; 
         public SensorActivity() { 
             //获取对应服务 
             mSensorManager =(SensorManager)getSystemService(SENSOR_SERVICE); 
             //获取指定sensor对象 
             mAccelerometer =mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); 
         } 
         protected void onResume() { 
             super.onResume(); 
             //注册listener用于数据回调 
             mSensorManager.registerListener(this,mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL); 
         } 
         protected void onPause() { 
             super.onPause(); 
            mSensorManager.unregisterListener(this); 
         } 
         public void onAccuracyChanged(Sensorsensor, int accuracy) { 
         } 
         public void onSensorChanged(SensorEventevent) { 
         } 
     } 

    现在看这代码就很清楚了

    1:(SensorManager)getSystemService(SENSOR_SERVICE)获取SensorManager对象,做了我们上面所介绍的初始化工作

    2:mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),获取指定sensor对象,根据初始化获取的Sensor List。

    3:mSensorManager.registerListener(this,mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);注册listener获取sensor数据

    还记得上一部分说的sensor client与sensor service建立active connection来传递数据吗?service端创建connection是由client端也就是由应用端发起的; 上面1,2都是初始化工作,那真正发起的代码,肯定就是registerlistener了,下面根据代码详细分析:

     

        public booleanregisterListener(SensorEventListener listener, Sensor sensor, int rate) {
            return registerListener(listener,sensor, rate, null);
        }

    直接调用重载函数

     

    public booleanregisterListener(SensorEventListener listener, Sensor sensor, int rate,
                Handler handler) {
            if (listener == null || sensor == null){
                return false;
            }
            boolean result = true;
            int delay = -1;
            switch (rate) {
                case SENSOR_DELAY_FASTEST:
                    delay = 0;
                    break;
                case SENSOR_DELAY_GAME:
                    delay = 20000;
                    break;
                case SENSOR_DELAY_UI:
                    delay = 66667;
                    break;
                case SENSOR_DELAY_NORMAL:
                    delay = 200000;
                    break;
                default:
                    delay = rate;
                    break;
            }
     
            synchronized (sListeners) {
                // look for this listener in our list
                ListenerDelegate l = null;
                for (ListenerDelegate i :sListeners) {
                    if (i.getListener() ==listener) {
                        l = i;
                        break;
                    }
               }
     
                // if we don't find it, add it tothe list
                if (l == null) {
                    l = newListenerDelegate(listener, sensor, handler);
                    sListeners.add(l);
                    // if the list is not empty,start our main thread
                    if (!sListeners.isEmpty()) {
                        if(sSensorThread.startLocked()) {
                            if(!enableSensorLocked(sensor, delay)) {
                                // oops. there was an error
                               sListeners.remove(l);
                                result = false;
                            }
                        } else {
                            // there was an error,remove the listener
                            sListeners.remove(l);
                            result = false;
                        }
                    } else {
                        // weird, we couldn't addthe listener
                        result = false;
                    }
                } else {
                    l.addSensor(sensor);
                    if (!enableSensorLocked(sensor,delay)) {
                        // oops. there was an error
                        l.removeSensor(sensor);
                        result = false;
                    }
                }
            }
     
            return result;
    }

    这个函数使用出现了两个新的变量,分别是sListeners和sSensorThread,对应的类型分别是ListenerDelegate和SensorThread,ListenerDelegate主要是对SensorEventListener做封装,从而使一个listener可以对应多个sensor,SensorThread则负责从sensor service读取sensor数据;该函数先判断lstener对应的ListenerDelegate是否已经创建,如果未创建,新建并将其添加入sListeners,然后查看Sensor Thread是否已经启动,如果没有启动,调用sSensorThread.startLocked()启动线程,接下去调用enableSensorLocked到service端enable对应的sensor.

    先来看startlocked:

     

     boolean startLocked() {
                try {
                    if (mThread == null) {
                        mSensorsReady = false;
                        SensorThreadRunnablerunnable = new SensorThreadRunnable();
                        Thread thread = newThread(runnable, SensorThread.class.getName());
                        thread.start();
                        synchronized (runnable) {
                            while (mSensorsReady ==false) {
                                runnable.wait();
                            }
                        }
                        mThread = thread;
                    }
                } catch (InterruptedException e) {
                }
                return mThread == null ? false :true;
            }

    如果线程未创建,创建SensorThreadRunnable,然后初始化线程并启动,线程启动后SensorThreadRunnable.run会被执行:

     

    private class SensorThreadRunnable implementsRunnable {
                SensorThreadRunnable() {
                }
     
                private boolean open() {
                    // NOTE: this cannotsynchronize on sListeners, since
                    // it's held in the main threadat least until we
                    // return from here.
                    sQueue = sensors_create_queue();
                    return true;
                }
     
                public void run() {
                    //Log.d(TAG, "enteringmain sensor thread");
                    final float[] values = newfloat[3];
                    final int[] status = newint[1];
                    final long timestamp[] = newlong[1];
                   Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
     
                    if (!open()) {
                        return;
                    }
     
                    synchronized (this) {
                        // we've open the driver,we're ready to open the sensors
                        mSensorsReady = true;
                        this.notify();
                    }
     
                    while (true) {
                        // wait for an event
                        final int sensor =sensors_data_poll(sQueue, values, status, timestamp);
     
                        int accuracy = status[0];
                        synchronized (sListeners) {
                            if (sensor == -1 ||sListeners.isEmpty()) {
                                // we lost theconnection to the event stream. this happens
                                // when the lastlistener is removed or if there is an error
                                if (sensor == -1&& !sListeners.isEmpty()) {
                                    // log awarning in case of abnormal termination
                                    Log.e(TAG,"_sensors_data_poll() failed, we bail out: sensors=" + sensor);
                                }
                                // we have no morelisteners or polling failed, terminate the thread
                               sensors_destroy_queue(sQueue);
                                sQueue = 0;
                                mThread = null;
                                break;
                            }
                            final SensorsensorObject = sHandleToSensor.get(sensor);
                            if (sensorObject !=null) {
                                // report thesensor 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 isasynchronous (okay to call
                                        // withsListeners lock held).
                                       listener.onSensorChangedLocked(sensorObject,
                                               values, timestamp, accuracy);
                                    }
                                }
                            }
                        }
                    }
                    //Log.d(TAG, "exiting mainsensor thread");
                }
            }
        }

    run执行时,先调用open,open函数很简单,就调用sensors_create_queue()来创建数据队列,显然这个队列是用于sensor数据传输的,sensors_create_queue()是jni函数,接下去看其对应c++部分代码:

     

    staticjint
    sensors_create_queue(JNIEnv*env, jclass clazz)
    {
        SensorManager&mgr(SensorManager::getInstance());
        sp<SensorEventQueue>queue(mgr.createEventQueue());
        queue->incStrong(clazz);
        returnreinterpret_cast<int>(queue.get());
    }

    调用SensorManager.createEventQueue来创建队列:

     

    sp<SensorEventQueue>SensorManager::createEventQueue()
    {
        sp<SensorEventQueue> queue;
        Mutex::Autolock _l(mLock);
        while(assertStateLocked() == NO_ERROR) {
            sp<ISensorEventConnection>connection =
                   mSensorServer->createSensorEventConnection();
            if (connection == NULL) {
                // SensorService just died.
                LOGE("createEventQueue:connection is NULL. SensorService died.");
                continue;
            }
            queue = newSensorEventQueue(connection);
            break;
        }
        return queue;
    }


    调用mSensorServer->createSensorEventConnection()与server端建立连接,接着将获取的connection对象创建SensorEventQueue对象并返回。

    sensors_create_queue函数接着调用queue.get()获取队列的指针,并返回给java层

    回过头来继续看java调用sensors_create_queue的open函数:

     

     private boolean open() {
     // NOTE: this cannot synchronize onsListeners, since
     // it's held in the main thread at least untilwe
     // return from here.
    //将返回的SensorEventQueue指针保存到sQueue里
     sQueue = sensors_create_queue();
     return true;
     }


    将c++创建的SensorEventQueue对象地址保存到java层的一个变量里,这在android里面是很常见也很好用的方法

    在open结束后,SensorThreadRunnable.run接下去调用sensors_data_poll来抓去sensor数据

    staticnative int sensors_data_poll(int queue, float[] values, int[] status, long[]timestamp);

    这个函数的第一个参数就是之前保存的c++层SensorEventQueue对象指针,看对应c++实现:

     

    staticjint
    sensors_data_poll(JNIEnv*env, jclass clazz, jint nativeQueue,
            jfloatArray values, jintArray status,jlongArray timestamp)
    {
       //强制类型转换
        sp<SensorEventQueue> queue(reinterpret_cast<SensorEventQueue*>(nativeQueue));
        if (queue == 0) return -1;
        status_t res;
    ASensorEventevent;
    //从队列中读取数据
        res = queue->read(&event, 1);
        if (res == -EAGAIN) {
            res = queue->waitForEvent();
            if (res != NO_ERROR)
                return -1;
            res = queue->read(&event, 1);
        }
        if (res < 0)
            return -1;
        jint accuracy = event.vector.status;
        env->SetFloatArrayRegion(values, 0, 3,event.vector.v);
        env->SetIntArrayRegion(status, 0, 1,&accuracy);
        env->SetLongArrayRegion(timestamp, 0, 1,&event.timestamp);
        return event.sensor;
    }


    先将java层传过来的对象地址强制类型转换成SensorEventQueue,然后调用 queue->read(&event, 1)读取sensor数据

     

    ssize_tSensorEventQueue::read(ASensorEvent* events, size_t numEvents)
    {
        ssize_t size =mSensorChannel->read(events, numEvents*sizeof(events[0]));
        LOGE_IF(size<0 && size!=-EAGAIN,
                "SensorChannel::read error(%s)", strerror(-size));
        if (size >= 0) {
            if (size % sizeof(events[0])) {
                // partial read!!! should neverhappen.
                LOGE("SensorEventQueue partialread (event-size=%u, read=%d)",
                        sizeof(events[0]),int(size));
                return -EINVAL;
            }
            // returns number of events read
            size /= sizeof(events[0]);
        }
    returnsize;
    }


    关于数据的具体传输,上一部分已经详细介绍,这里就不再描述

    Jni部分sensors_data_poll在获取到sensor数据并返回到java层,SensorThreadRunnable.run在得到sensor数据后,通过下面代码将数据通过listener回调

     

    finalint 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).
       istener.onSensorChangedLocked(sensorObject,values,timestamp, accuracy);
    }
    }

    就这样,通过registerlistener注册的listener就可以获取到想要的sensor数据,这样就可以了吗?还不行,上面只是说数据流是这么走的,SensorEventQueue::read现在读不到数据的,因为在sensor service那边,sensor还是inactive的,所以registerListener 在sSensorThread.startLocked()成功后,再调用enableSensorLocked来active指定sensor:

     

          private booleanenableSensorLocked(Sensor sensor, int delay) {
            boolean result = false;
            for (ListenerDelegate i : sListeners) {
                if (i.hasSensor(sensor)) {
                    String name = sensor.getName();
                    int handle =sensor.getHandle();
                    result = sensors_enable_sensor(sQueue,name, handle, delay);
                    break;
                }
            }
            return result;
        }


    sensors_enable_sensor,又一个jni函数,直接看对应c++函数:

     

    staticjboolean
    sensors_enable_sensor(JNIEnv*env, jclass clazz,
            jint nativeQueue, jstring name, jintsensor, jint delay)
    {
        sp<SensorEventQueue>queue(reinterpret_cast<SensorEventQueue *>(nativeQueue));
        if (queue == 0) return JNI_FALSE;
        status_t res;
        if(delay >= 0) {
            res = queue->enableSensor(sensor,delay);
        } else {
            res = queue->disableSensor(sensor);
        }
        return res == NO_ERROR ? true : false;
    }


    继续看queue->enableSensor

     

      status_tSensorEventQueue::enableSensor(int32_t handle, int32_t us) const {
        status_t err =mSensorEventConnection->enableDisable(handle, true);
        if (err == NO_ERROR) {
           mSensorEventConnection->setEventRate(handle, us2ns(us));
        }
        return err;
    }

    调用mSensorEventConnection->enableDisable(handle,true)将对应的sensor激活。

     Ok,激活后,SensorThreadRunnable.run中sensors_data_poll就可以拿到数据,并回调给注册的listener.

     

    本文乃原创,转载请注明出处,谢谢。

     

  • 相关阅读:
    CSS margin的一些让你模糊的点
    VUE中CSS样式穿透
    如何给img标签里的请求添加自定义header?
    iframe的父子页面进行简单的相互传值
    Docker部署网站之后映射域名
    机器学习笔记(九)---- 集成学习(ensemble learning)【华为云技术分享】
    鲲鹏性能优化十板斧之前言 | 鲲鹏处理器NUMA简介与性能调优五步法
    【我的物联网成长记8】超速入门AT指令集【华为云技术分享】
    【直播分享】实现LOL小地图英雄头像分析案例【华为云分享】
    MongoDB一次节点宕机引发的思考(源码剖析)【华为云分享】
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3202963.html
Copyright © 2011-2022 走看看