1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.hardware; 18 19 import android.Manifest; 20 import android.content.Context; 21 import android.content.pm.PackageManager; 22 import android.os.Handler; 23 import android.os.Looper; 24 import android.os.MessageQueue; 25 import android.util.Log; 26 import android.util.SparseArray; 27 import android.util.SparseBooleanArray; 28 import android.util.SparseIntArray; 29 import dalvik.system.CloseGuard; 30 31 import java.lang.ref.WeakReference; 32 import java.util.ArrayList; 33 import java.util.HashMap; 34 import java.util.List; 35 36 /** 37 * Sensor manager implementation that communicates with the built-in 38 * system sensors. 39 * 40 * @hide 41 */ 42 public class SystemSensorManager extends SensorManager { nativeClassInit()43 private static native void nativeClassInit(); nativeCreate(String opPackageName)44 private static native long nativeCreate(String opPackageName); nativeGetSensorAtIndex(long nativeInstance, Sensor sensor, int index)45 private static native boolean nativeGetSensorAtIndex(long nativeInstance, 46 Sensor sensor, int index); nativeIsDataInjectionEnabled(long nativeInstance)47 private static native boolean nativeIsDataInjectionEnabled(long nativeInstance); 48 49 private static boolean sSensorModuleInitialized = false; 50 private static InjectEventQueue mInjectEventQueue = null; 51 52 private final Object mLock = new Object(); 53 54 private final ArrayList<Sensor> mFullSensorsList = new ArrayList<>(); 55 private final SparseArray<Sensor> mHandleToSensor = new SparseArray<>(); 56 57 // Listener list 58 private final HashMap<SensorEventListener, SensorEventQueue> mSensorListeners = 59 new HashMap<SensorEventListener, SensorEventQueue>(); 60 private final HashMap<TriggerEventListener, TriggerEventQueue> mTriggerListeners = 61 new HashMap<TriggerEventListener, TriggerEventQueue>(); 62 63 // Looper associated with the context in which this instance was created. 64 private final Looper mMainLooper; 65 private final int mTargetSdkLevel; 66 private final Context mContext; 67 private final long mNativeInstance; 68 69 /** {@hide} */ SystemSensorManager(Context context, Looper mainLooper)70 public SystemSensorManager(Context context, Looper mainLooper) { 71 mMainLooper = mainLooper; 72 mTargetSdkLevel = context.getApplicationInfo().targetSdkVersion; 73 mContext = context; 74 mNativeInstance = nativeCreate(context.getOpPackageName()); 75 76 synchronized(mLock) { 77 if (!sSensorModuleInitialized) { 78 sSensorModuleInitialized = true; 79 nativeClassInit(); 80 } 81 } 82 83 // initialize the sensor list 84 for (int index = 0;;++index) { 85 Sensor sensor = new Sensor(); 86 if (!nativeGetSensorAtIndex(mNativeInstance, sensor, index)) break; 87 mFullSensorsList.add(sensor); 88 mHandleToSensor.append(sensor.getHandle(), sensor); 89 } 90 } 91 92 93 /** @hide */ 94 @Override getFullSensorList()95 protected List<Sensor> getFullSensorList() { 96 return mFullSensorsList; 97 } 98 99 100 /** @hide */ 101 @Override registerListenerImpl(SensorEventListener listener, Sensor sensor, int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags)102 protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor, 103 int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags) { 104 if (listener == null || sensor == null) { 105 Log.e(TAG, "sensor or listener is null"); 106 return false; 107 } 108 // Trigger Sensors should use the requestTriggerSensor call. 109 if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) { 110 Log.e(TAG, "Trigger Sensors should use the requestTriggerSensor."); 111 return false; 112 } 113 if (maxBatchReportLatencyUs < 0 || delayUs < 0) { 114 Log.e(TAG, "maxBatchReportLatencyUs and delayUs should be non-negative"); 115 return false; 116 } 117 118 // Invariants to preserve: 119 // - one Looper per SensorEventListener 120 // - one Looper per SensorEventQueue 121 // We map SensorEventListener to a SensorEventQueue, which holds the looper 122 synchronized (mSensorListeners) { 123 SensorEventQueue queue = mSensorListeners.get(listener); 124 if (queue == null) { 125 Looper looper = (handler != null) ? handler.getLooper() : mMainLooper; 126 final String fullClassName = listener.getClass().getEnclosingClass() != null ? 127 listener.getClass().getEnclosingClass().getName() : 128 listener.getClass().getName(); 129 queue = new SensorEventQueue(listener, looper, this, fullClassName); 130 if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs)) { 131 queue.dispose(); 132 return false; 133 } 134 mSensorListeners.put(listener, queue); 135 return true; 136 } else { 137 return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs); 138 } 139 } 140 } 141 142 /** @hide */ 143 @Override unregisterListenerImpl(SensorEventListener listener, Sensor sensor)144 protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) { 145 // Trigger Sensors should use the cancelTriggerSensor call. 146 if (sensor != null && sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) { 147 return; 148 } 149 150 synchronized (mSensorListeners) { 151 SensorEventQueue queue = mSensorListeners.get(listener); 152 if (queue != null) { 153 boolean result; 154 if (sensor == null) { 155 result = queue.removeAllSensors(); 156 } else { 157 result = queue.removeSensor(sensor, true); 158 } 159 if (result && !queue.hasSensors()) { 160 mSensorListeners.remove(listener); 161 queue.dispose(); 162 } 163 } 164 } 165 } 166 167 /** @hide */ 168 @Override requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor)169 protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) { 170 if (sensor == null) throw new IllegalArgumentException("sensor cannot be null"); 171 172 if (listener == null) throw new IllegalArgumentException("listener cannot be null"); 173 174 if (sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) return false; 175 176 synchronized (mTriggerListeners) { 177 TriggerEventQueue queue = mTriggerListeners.get(listener); 178 if (queue == null) { 179 final String fullClassName = listener.getClass().getEnclosingClass() != null ? 180 listener.getClass().getEnclosingClass().getName() : 181 listener.getClass().getName(); 182 queue = new TriggerEventQueue(listener, mMainLooper, this, fullClassName); 183 if (!queue.addSensor(sensor, 0, 0)) { 184 queue.dispose(); 185 return false; 186 } 187 mTriggerListeners.put(listener, queue); 188 return true; 189 } else { 190 return queue.addSensor(sensor, 0, 0); 191 } 192 } 193 } 194 195 /** @hide */ 196 @Override cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor, boolean disable)197 protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor, 198 boolean disable) { 199 if (sensor != null && sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) { 200 return false; 201 } 202 synchronized (mTriggerListeners) { 203 TriggerEventQueue queue = mTriggerListeners.get(listener); 204 if (queue != null) { 205 boolean result; 206 if (sensor == null) { 207 result = queue.removeAllSensors(); 208 } else { 209 result = queue.removeSensor(sensor, disable); 210 } 211 if (result && !queue.hasSensors()) { 212 mTriggerListeners.remove(listener); 213 queue.dispose(); 214 } 215 return result; 216 } 217 return false; 218 } 219 } 220 flushImpl(SensorEventListener listener)221 protected boolean flushImpl(SensorEventListener listener) { 222 if (listener == null) throw new IllegalArgumentException("listener cannot be null"); 223 224 synchronized (mSensorListeners) { 225 SensorEventQueue queue = mSensorListeners.get(listener); 226 if (queue == null) { 227 return false; 228 } else { 229 return (queue.flush() == 0); 230 } 231 } 232 } 233 initDataInjectionImpl(boolean enable)234 protected boolean initDataInjectionImpl(boolean enable) { 235 synchronized (mLock) { 236 if (enable) { 237 boolean isDataInjectionModeEnabled = nativeIsDataInjectionEnabled(mNativeInstance); 238 // The HAL does not support injection OR SensorService hasn't been set in DI mode. 239 if (!isDataInjectionModeEnabled) { 240 Log.e(TAG, "Data Injection mode not enabled"); 241 return false; 242 } 243 // Initialize a client for data_injection. 244 if (mInjectEventQueue == null) { 245 mInjectEventQueue = new InjectEventQueue(mMainLooper, this, 246 mContext.getPackageName()); 247 } 248 } else { 249 // If data injection is being disabled clean up the native resources. 250 if (mInjectEventQueue != null) { 251 mInjectEventQueue.dispose(); 252 mInjectEventQueue = null; 253 } 254 } 255 return true; 256 } 257 } 258 injectSensorDataImpl(Sensor sensor, float[] values, int accuracy, long timestamp)259 protected boolean injectSensorDataImpl(Sensor sensor, float[] values, int accuracy, 260 long timestamp) { 261 synchronized (mLock) { 262 if (mInjectEventQueue == null) { 263 Log.e(TAG, "Data injection mode not activated before calling injectSensorData"); 264 return false; 265 } 266 int ret = mInjectEventQueue.injectSensorData(sensor.getHandle(), values, accuracy, 267 timestamp); 268 // If there are any errors in data injection clean up the native resources. 269 if (ret != 0) { 270 mInjectEventQueue.dispose(); 271 mInjectEventQueue = null; 272 } 273 return ret == 0; 274 } 275 } 276 277 /* 278 * BaseEventQueue is the communication channel with the sensor service, 279 * SensorEventQueue, TriggerEventQueue are subclases and there is one-to-one mapping between 280 * the queues and the listeners. InjectEventQueue is also a sub-class which is a special case 281 * where data is being injected into the sensor HAL through the sensor service. It is not 282 * associated with any listener and there is one InjectEventQueue associated with a 283 * SensorManager instance. 284 */ 285 private static abstract class BaseEventQueue { nativeInitBaseEventQueue(long nativeManager, WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ, float[] scratch, String packageName, int mode, String opPackageName)286 private static native long nativeInitBaseEventQueue(long nativeManager, 287 WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ, float[] scratch, 288 String packageName, int mode, String opPackageName); nativeEnableSensor(long eventQ, int handle, int rateUs, int maxBatchReportLatencyUs)289 private static native int nativeEnableSensor(long eventQ, int handle, int rateUs, 290 int maxBatchReportLatencyUs); nativeDisableSensor(long eventQ, int handle)291 private static native int nativeDisableSensor(long eventQ, int handle); nativeDestroySensorEventQueue(long eventQ)292 private static native void nativeDestroySensorEventQueue(long eventQ); nativeFlushSensor(long eventQ)293 private static native int nativeFlushSensor(long eventQ); nativeInjectSensorData(long eventQ, int handle, float[] values,int accuracy, long timestamp)294 private static native int nativeInjectSensorData(long eventQ, int handle, 295 float[] values,int accuracy, long timestamp); 296 297 private long nSensorEventQueue; 298 private final SparseBooleanArray mActiveSensors = new SparseBooleanArray(); 299 protected final SparseIntArray mSensorAccuracies = new SparseIntArray(); 300 protected final SparseBooleanArray mFirstEvent = new SparseBooleanArray(); 301 private final CloseGuard mCloseGuard = CloseGuard.get(); 302 private final float[] mScratch = new float[16]; 303 protected final SystemSensorManager mManager; 304 305 protected static final int OPERATING_MODE_NORMAL = 0; 306 protected static final int OPERATING_MODE_DATA_INJECTION = 1; 307 BaseEventQueue(Looper looper, SystemSensorManager manager, int mode, String packageName)308 BaseEventQueue(Looper looper, SystemSensorManager manager, int mode, String packageName) { 309 if (packageName == null) packageName = ""; 310 nSensorEventQueue = nativeInitBaseEventQueue(manager.mNativeInstance, 311 new WeakReference<>(this), looper.getQueue(), mScratch, 312 packageName, mode, manager.mContext.getOpPackageName()); 313 mCloseGuard.open("dispose"); 314 mManager = manager; 315 } 316 dispose()317 public void dispose() { 318 dispose(false); 319 } 320 addSensor( Sensor sensor, int delayUs, int maxBatchReportLatencyUs)321 public boolean addSensor( 322 Sensor sensor, int delayUs, int maxBatchReportLatencyUs) { 323 // Check if already present. 324 int handle = sensor.getHandle(); 325 if (mActiveSensors.get(handle)) return false; 326 327 // Get ready to receive events before calling enable. 328 mActiveSensors.put(handle, true); 329 addSensorEvent(sensor); 330 if (enableSensor(sensor, delayUs, maxBatchReportLatencyUs) != 0) { 331 // Try continuous mode if batching fails. 332 if (maxBatchReportLatencyUs == 0 || 333 maxBatchReportLatencyUs > 0 && enableSensor(sensor, delayUs, 0) != 0) { 334 removeSensor(sensor, false); 335 return false; 336 } 337 } 338 return true; 339 } 340 removeAllSensors()341 public boolean removeAllSensors() { 342 for (int i=0 ; i<mActiveSensors.size(); i++) { 343 if (mActiveSensors.valueAt(i) == true) { 344 int handle = mActiveSensors.keyAt(i); 345 Sensor sensor = mManager.mHandleToSensor.get(handle); 346 if (sensor != null) { 347 disableSensor(sensor); 348 mActiveSensors.put(handle, false); 349 removeSensorEvent(sensor); 350 } else { 351 // it should never happen -- just ignore. 352 } 353 } 354 } 355 return true; 356 } 357 removeSensor(Sensor sensor, boolean disable)358 public boolean removeSensor(Sensor sensor, boolean disable) { 359 final int handle = sensor.getHandle(); 360 if (mActiveSensors.get(handle)) { 361 if (disable) disableSensor(sensor); 362 mActiveSensors.put(sensor.getHandle(), false); 363 removeSensorEvent(sensor); 364 return true; 365 } 366 return false; 367 } 368 flush()369 public int flush() { 370 if (nSensorEventQueue == 0) throw new NullPointerException(); 371 return nativeFlushSensor(nSensorEventQueue); 372 } 373 hasSensors()374 public boolean hasSensors() { 375 // no more sensors are set 376 return mActiveSensors.indexOfValue(true) >= 0; 377 } 378 379 @Override finalize()380 protected void finalize() throws Throwable { 381 try { 382 dispose(true); 383 } finally { 384 super.finalize(); 385 } 386 } 387 dispose(boolean finalized)388 private void dispose(boolean finalized) { 389 if (mCloseGuard != null) { 390 if (finalized) { 391 mCloseGuard.warnIfOpen(); 392 } 393 mCloseGuard.close(); 394 } 395 if (nSensorEventQueue != 0) { 396 nativeDestroySensorEventQueue(nSensorEventQueue); 397 nSensorEventQueue = 0; 398 } 399 } 400 enableSensor( Sensor sensor, int rateUs, int maxBatchReportLatencyUs)401 private int enableSensor( 402 Sensor sensor, int rateUs, int maxBatchReportLatencyUs) { 403 if (nSensorEventQueue == 0) throw new NullPointerException(); 404 if (sensor == null) throw new NullPointerException(); 405 return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), rateUs, 406 maxBatchReportLatencyUs); 407 } 408 injectSensorDataBase(int handle, float[] values, int accuracy, long timestamp)409 protected int injectSensorDataBase(int handle, float[] values, int accuracy, 410 long timestamp) { 411 return nativeInjectSensorData(nSensorEventQueue, handle, values, accuracy, timestamp); 412 } 413 disableSensor(Sensor sensor)414 private int disableSensor(Sensor sensor) { 415 if (nSensorEventQueue == 0) throw new NullPointerException(); 416 if (sensor == null) throw new NullPointerException(); 417 return nativeDisableSensor(nSensorEventQueue, sensor.getHandle()); 418 } dispatchSensorEvent(int handle, float[] values, int accuracy, long timestamp)419 protected abstract void dispatchSensorEvent(int handle, float[] values, int accuracy, 420 long timestamp); dispatchFlushCompleteEvent(int handle)421 protected abstract void dispatchFlushCompleteEvent(int handle); 422 addSensorEvent(Sensor sensor)423 protected abstract void addSensorEvent(Sensor sensor); removeSensorEvent(Sensor sensor)424 protected abstract void removeSensorEvent(Sensor sensor); 425 } 426 427 static final class SensorEventQueue extends BaseEventQueue { 428 private final SensorEventListener mListener; 429 private final SparseArray<SensorEvent> mSensorsEvents = new SparseArray<SensorEvent>(); 430 SensorEventQueue(SensorEventListener listener, Looper looper, SystemSensorManager manager, String packageName)431 public SensorEventQueue(SensorEventListener listener, Looper looper, 432 SystemSensorManager manager, String packageName) { 433 super(looper, manager, OPERATING_MODE_NORMAL, packageName); 434 mListener = listener; 435 } 436 437 @Override addSensorEvent(Sensor sensor)438 public void addSensorEvent(Sensor sensor) { 439 SensorEvent t = new SensorEvent(Sensor.getMaxLengthValuesArray(sensor, 440 mManager.mTargetSdkLevel)); 441 synchronized (mSensorsEvents) { 442 mSensorsEvents.put(sensor.getHandle(), t); 443 } 444 } 445 446 @Override removeSensorEvent(Sensor sensor)447 public void removeSensorEvent(Sensor sensor) { 448 synchronized (mSensorsEvents) { 449 mSensorsEvents.delete(sensor.getHandle()); 450 } 451 } 452 453 // Called from native code. 454 @SuppressWarnings("unused") 455 @Override dispatchSensorEvent(int handle, float[] values, int inAccuracy, long timestamp)456 protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy, 457 long timestamp) { 458 final Sensor sensor = mManager.mHandleToSensor.get(handle); 459 SensorEvent t = null; 460 synchronized (mSensorsEvents) { 461 t = mSensorsEvents.get(handle); 462 } 463 464 if (t == null) { 465 // This may happen if the client has unregistered and there are pending events in 466 // the queue waiting to be delivered. Ignore. 467 return; 468 } 469 // Copy from the values array. 470 System.arraycopy(values, 0, t.values, 0, t.values.length); 471 t.timestamp = timestamp; 472 t.accuracy = inAccuracy; 473 t.sensor = sensor; 474 475 // call onAccuracyChanged() only if the value changes 476 final int accuracy = mSensorAccuracies.get(handle); 477 if ((t.accuracy >= 0) && (accuracy != t.accuracy)) { 478 mSensorAccuracies.put(handle, t.accuracy); 479 mListener.onAccuracyChanged(t.sensor, t.accuracy); 480 } 481 mListener.onSensorChanged(t); 482 } 483 484 @SuppressWarnings("unused") dispatchFlushCompleteEvent(int handle)485 protected void dispatchFlushCompleteEvent(int handle) { 486 if (mListener instanceof SensorEventListener2) { 487 final Sensor sensor = mManager.mHandleToSensor.get(handle); 488 ((SensorEventListener2)mListener).onFlushCompleted(sensor); 489 } 490 return; 491 } 492 } 493 494 static final class TriggerEventQueue extends BaseEventQueue { 495 private final TriggerEventListener mListener; 496 private final SparseArray<TriggerEvent> mTriggerEvents = new SparseArray<TriggerEvent>(); 497 TriggerEventQueue(TriggerEventListener listener, Looper looper, SystemSensorManager manager, String packageName)498 public TriggerEventQueue(TriggerEventListener listener, Looper looper, 499 SystemSensorManager manager, String packageName) { 500 super(looper, manager, OPERATING_MODE_NORMAL, packageName); 501 mListener = listener; 502 } 503 504 @Override addSensorEvent(Sensor sensor)505 public void addSensorEvent(Sensor sensor) { 506 TriggerEvent t = new TriggerEvent(Sensor.getMaxLengthValuesArray(sensor, 507 mManager.mTargetSdkLevel)); 508 synchronized (mTriggerEvents) { 509 mTriggerEvents.put(sensor.getHandle(), t); 510 } 511 } 512 513 @Override removeSensorEvent(Sensor sensor)514 public void removeSensorEvent(Sensor sensor) { 515 synchronized (mTriggerEvents) { 516 mTriggerEvents.delete(sensor.getHandle()); 517 } 518 } 519 520 // Called from native code. 521 @SuppressWarnings("unused") 522 @Override dispatchSensorEvent(int handle, float[] values, int accuracy, long timestamp)523 protected void dispatchSensorEvent(int handle, float[] values, int accuracy, 524 long timestamp) { 525 final Sensor sensor = mManager.mHandleToSensor.get(handle); 526 TriggerEvent t = null; 527 synchronized (mTriggerEvents) { 528 t = mTriggerEvents.get(handle); 529 } 530 if (t == null) { 531 Log.e(TAG, "Error: Trigger Event is null for Sensor: " + sensor); 532 return; 533 } 534 535 // Copy from the values array. 536 System.arraycopy(values, 0, t.values, 0, t.values.length); 537 t.timestamp = timestamp; 538 t.sensor = sensor; 539 540 // A trigger sensor is auto disabled. So just clean up and don't call native 541 // disable. 542 mManager.cancelTriggerSensorImpl(mListener, sensor, false); 543 544 mListener.onTrigger(t); 545 } 546 547 @SuppressWarnings("unused") dispatchFlushCompleteEvent(int handle)548 protected void dispatchFlushCompleteEvent(int handle) { 549 } 550 } 551 552 final class InjectEventQueue extends BaseEventQueue { InjectEventQueue(Looper looper, SystemSensorManager manager, String packageName)553 public InjectEventQueue(Looper looper, SystemSensorManager manager, String packageName) { 554 super(looper, manager, OPERATING_MODE_DATA_INJECTION, packageName); 555 } 556 injectSensorData(int handle, float[] values,int accuracy, long timestamp)557 int injectSensorData(int handle, float[] values,int accuracy, long timestamp) { 558 return injectSensorDataBase(handle, values, accuracy, timestamp); 559 } 560 561 @SuppressWarnings("unused") dispatchSensorEvent(int handle, float[] values, int accuracy, long timestamp)562 protected void dispatchSensorEvent(int handle, float[] values, int accuracy, 563 long timestamp) { 564 } 565 566 @SuppressWarnings("unused") dispatchFlushCompleteEvent(int handle)567 protected void dispatchFlushCompleteEvent(int handle) { 568 569 } 570 571 @SuppressWarnings("unused") addSensorEvent(Sensor sensor)572 protected void addSensorEvent(Sensor sensor) { 573 574 } 575 576 @SuppressWarnings("unused") removeSensorEvent(Sensor sensor)577 protected void removeSensorEvent(Sensor sensor) { 578 579 } 580 } 581 } 582