Android Sensor系統剖析(4.0)(下)

Author:[email protected]

    由於現在電腦上只有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.

 

本文乃原創,轉載請註明出處,謝謝。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章