Author:Harish_hu@qq.comjava
因爲如今電腦上只有4.0的代碼,考慮到代碼差異也不大,因此下部分,就基於4.0來分析。android
3:SensorManagerc++
上一部分說過,開機後,system server啓動時,就會初始化sensor service,也就是說,開機後她一直都在後臺運行着,客戶端部分,直接connect就好了。至於怎麼connect,這一切都被封裝到SensorManager裏了。app
3.1 SensorManager的建立async
獲取SensorManager的對象實例代碼:ide
mSensorManager =(SensorManager)getSystemService(SENSOR_SERVICE);函數
調用Activity的成員函數來獲取SensorManager實例,咱們從Activity派生關係能夠追溯到,這個函數的最終在ContextImpl實現:oop
//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對象的建立:fetch
//ContextImpl.java static{ ... registerService(SENSOR_SERVICE, newServiceFetcher() { public ObjectcreateService(ContextImpl ctx) { return newSensorManager(ctx.mMainThread.getHandler().getLooper()); }}); ... }
3.2 初始化並鏈接sensor servicethis
初始化過程確定是在構造函數中進行,那如何鏈接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.
本文乃原創,轉載請註明出處,謝謝。