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.
本文乃原創,轉載請註明出處,謝謝。