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 static android.content.pm.PackageManager.PERMISSION_GRANTED; 20 21 import android.compat.Compatibility; 22 import android.compat.annotation.ChangeId; 23 import android.compat.annotation.EnabledAfter; 24 import android.compat.annotation.UnsupportedAppUsage; 25 import android.content.BroadcastReceiver; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.IntentFilter; 29 import android.content.pm.ApplicationInfo; 30 import android.os.Build; 31 import android.os.Handler; 32 import android.os.Looper; 33 import android.os.MemoryFile; 34 import android.os.MessageQueue; 35 import android.util.Log; 36 import android.util.SparseArray; 37 import android.util.SparseBooleanArray; 38 import android.util.SparseIntArray; 39 40 import com.android.internal.annotations.GuardedBy; 41 42 import dalvik.system.CloseGuard; 43 44 import java.io.IOException; 45 import java.io.UncheckedIOException; 46 import java.lang.ref.WeakReference; 47 import java.util.ArrayList; 48 import java.util.HashMap; 49 import java.util.List; 50 import java.util.Map; 51 import java.util.Optional; 52 53 /** 54 * Sensor manager implementation that communicates with the built-in 55 * system sensors. 56 * 57 * @hide 58 */ 59 public class SystemSensorManager extends SensorManager { 60 //TODO: disable extra logging before release 61 private static final boolean DEBUG_DYNAMIC_SENSOR = true; 62 private static final int MIN_DIRECT_CHANNEL_BUFFER_SIZE = 104; 63 private static final int MAX_LISTENER_COUNT = 128; 64 private static final int CAPPED_SAMPLING_PERIOD_US = 5000; 65 private static final int CAPPED_SAMPLING_RATE_LEVEL = SensorDirectChannel.RATE_NORMAL; 66 67 private static final String HIGH_SAMPLING_RATE_SENSORS_PERMISSION = 68 "android.permission.HIGH_SAMPLING_RATE_SENSORS"; 69 /** 70 * For apps targeting S and above, a SecurityException is thrown when they do not have 71 * HIGH_SAMPLING_RATE_SENSORS permission, run in debug mode, and request sampling rates that 72 * are faster than 200 Hz. 73 */ 74 @ChangeId 75 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R) 76 static final long CHANGE_ID_SAMPLING_RATE_SENSORS_PERMISSION = 136069189L; 77 nativeClassInit()78 private static native void nativeClassInit(); nativeCreate(String opPackageName)79 private static native long nativeCreate(String opPackageName); nativeGetSensorAtIndex(long nativeInstance, Sensor sensor, int index)80 private static native boolean nativeGetSensorAtIndex(long nativeInstance, 81 Sensor sensor, int index); nativeGetDynamicSensors(long nativeInstance, List<Sensor> list)82 private static native void nativeGetDynamicSensors(long nativeInstance, List<Sensor> list); nativeIsDataInjectionEnabled(long nativeInstance)83 private static native boolean nativeIsDataInjectionEnabled(long nativeInstance); 84 nativeCreateDirectChannel( long nativeInstance, long size, int channelType, int fd, HardwareBuffer buffer)85 private static native int nativeCreateDirectChannel( 86 long nativeInstance, long size, int channelType, int fd, HardwareBuffer buffer); nativeDestroyDirectChannel( long nativeInstance, int channelHandle)87 private static native void nativeDestroyDirectChannel( 88 long nativeInstance, int channelHandle); nativeConfigDirectChannel( long nativeInstance, int channelHandle, int sensorHandle, int rate)89 private static native int nativeConfigDirectChannel( 90 long nativeInstance, int channelHandle, int sensorHandle, int rate); 91 nativeSetOperationParameter( long nativeInstance, int handle, int type, float[] floatValues, int[] intValues)92 private static native int nativeSetOperationParameter( 93 long nativeInstance, int handle, int type, float[] floatValues, int[] intValues); 94 95 private static final Object sLock = new Object(); 96 @GuardedBy("sLock") 97 private static boolean sNativeClassInited = false; 98 @GuardedBy("sLock") 99 private static InjectEventQueue sInjectEventQueue = null; 100 101 private final ArrayList<Sensor> mFullSensorsList = new ArrayList<>(); 102 private List<Sensor> mFullDynamicSensorsList = new ArrayList<>(); 103 private boolean mDynamicSensorListDirty = true; 104 105 private final HashMap<Integer, Sensor> mHandleToSensor = new HashMap<>(); 106 107 // Listener list 108 private final HashMap<SensorEventListener, SensorEventQueue> mSensorListeners = 109 new HashMap<SensorEventListener, SensorEventQueue>(); 110 private final HashMap<TriggerEventListener, TriggerEventQueue> mTriggerListeners = 111 new HashMap<TriggerEventListener, TriggerEventQueue>(); 112 113 // Dynamic Sensor callbacks 114 private HashMap<DynamicSensorCallback, Handler> 115 mDynamicSensorCallbacks = new HashMap<>(); 116 private BroadcastReceiver mDynamicSensorBroadcastReceiver; 117 118 // Looper associated with the context in which this instance was created. 119 private final Looper mMainLooper; 120 private final int mTargetSdkLevel; 121 private final boolean mIsPackageDebuggable; 122 private final Context mContext; 123 private final long mNativeInstance; 124 125 private Optional<Boolean> mHasHighSamplingRateSensorsPermission = Optional.empty(); 126 127 /** {@hide} */ SystemSensorManager(Context context, Looper mainLooper)128 public SystemSensorManager(Context context, Looper mainLooper) { 129 synchronized (sLock) { 130 if (!sNativeClassInited) { 131 sNativeClassInited = true; 132 nativeClassInit(); 133 } 134 } 135 136 mMainLooper = mainLooper; 137 ApplicationInfo appInfo = context.getApplicationInfo(); 138 mTargetSdkLevel = appInfo.targetSdkVersion; 139 mContext = context; 140 mNativeInstance = nativeCreate(context.getOpPackageName()); 141 mIsPackageDebuggable = (0 != (appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE)); 142 143 // initialize the sensor list 144 for (int index = 0;; ++index) { 145 Sensor sensor = new Sensor(); 146 if (!nativeGetSensorAtIndex(mNativeInstance, sensor, index)) break; 147 mFullSensorsList.add(sensor); 148 mHandleToSensor.put(sensor.getHandle(), sensor); 149 } 150 } 151 152 /** @hide */ 153 @Override getFullSensorList()154 protected List<Sensor> getFullSensorList() { 155 return mFullSensorsList; 156 } 157 158 /** @hide */ 159 @Override getFullDynamicSensorList()160 protected List<Sensor> getFullDynamicSensorList() { 161 // only set up broadcast receiver if the application tries to find dynamic sensors or 162 // explicitly register a DynamicSensorCallback 163 setupDynamicSensorBroadcastReceiver(); 164 updateDynamicSensorList(); 165 return mFullDynamicSensorsList; 166 } 167 168 /** @hide */ 169 @Override registerListenerImpl(SensorEventListener listener, Sensor sensor, int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags)170 protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor, 171 int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags) { 172 if (listener == null || sensor == null) { 173 Log.e(TAG, "sensor or listener is null"); 174 return false; 175 } 176 // Trigger Sensors should use the requestTriggerSensor call. 177 if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) { 178 Log.e(TAG, "Trigger Sensors should use the requestTriggerSensor."); 179 return false; 180 } 181 if (maxBatchReportLatencyUs < 0 || delayUs < 0) { 182 Log.e(TAG, "maxBatchReportLatencyUs and delayUs should be non-negative"); 183 return false; 184 } 185 if (mSensorListeners.size() >= MAX_LISTENER_COUNT) { 186 throw new IllegalStateException("register failed, " 187 + "the sensor listeners size has exceeded the maximum limit " 188 + MAX_LISTENER_COUNT); 189 } 190 191 // Invariants to preserve: 192 // - one Looper per SensorEventListener 193 // - one Looper per SensorEventQueue 194 // We map SensorEventListener to a SensorEventQueue, which holds the looper 195 synchronized (mSensorListeners) { 196 SensorEventQueue queue = mSensorListeners.get(listener); 197 if (queue == null) { 198 Looper looper = (handler != null) ? handler.getLooper() : mMainLooper; 199 final String fullClassName = 200 listener.getClass().getEnclosingClass() != null 201 ? listener.getClass().getEnclosingClass().getName() 202 : listener.getClass().getName(); 203 queue = new SensorEventQueue(listener, looper, this, fullClassName); 204 if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs)) { 205 queue.dispose(); 206 return false; 207 } 208 mSensorListeners.put(listener, queue); 209 return true; 210 } else { 211 return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs); 212 } 213 } 214 } 215 216 /** @hide */ 217 @Override unregisterListenerImpl(SensorEventListener listener, Sensor sensor)218 protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) { 219 // Trigger Sensors should use the cancelTriggerSensor call. 220 if (sensor != null && sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) { 221 return; 222 } 223 224 synchronized (mSensorListeners) { 225 SensorEventQueue queue = mSensorListeners.get(listener); 226 if (queue != null) { 227 boolean result; 228 if (sensor == null) { 229 result = queue.removeAllSensors(); 230 } else { 231 result = queue.removeSensor(sensor, true); 232 } 233 if (result && !queue.hasSensors()) { 234 mSensorListeners.remove(listener); 235 queue.dispose(); 236 } 237 } 238 } 239 } 240 241 /** @hide */ 242 @Override requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor)243 protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) { 244 if (sensor == null) throw new IllegalArgumentException("sensor cannot be null"); 245 246 if (listener == null) throw new IllegalArgumentException("listener cannot be null"); 247 248 if (sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) return false; 249 250 if (mTriggerListeners.size() >= MAX_LISTENER_COUNT) { 251 throw new IllegalStateException("request failed, " 252 + "the trigger listeners size has exceeded the maximum limit " 253 + MAX_LISTENER_COUNT); 254 } 255 256 synchronized (mTriggerListeners) { 257 TriggerEventQueue queue = mTriggerListeners.get(listener); 258 if (queue == null) { 259 final String fullClassName = 260 listener.getClass().getEnclosingClass() != null 261 ? listener.getClass().getEnclosingClass().getName() 262 : listener.getClass().getName(); 263 queue = new TriggerEventQueue(listener, mMainLooper, this, fullClassName); 264 if (!queue.addSensor(sensor, 0, 0)) { 265 queue.dispose(); 266 return false; 267 } 268 mTriggerListeners.put(listener, queue); 269 return true; 270 } else { 271 return queue.addSensor(sensor, 0, 0); 272 } 273 } 274 } 275 276 /** @hide */ 277 @Override cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor, boolean disable)278 protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor, 279 boolean disable) { 280 if (sensor != null && sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) { 281 return false; 282 } 283 synchronized (mTriggerListeners) { 284 TriggerEventQueue queue = mTriggerListeners.get(listener); 285 if (queue != null) { 286 boolean result; 287 if (sensor == null) { 288 result = queue.removeAllSensors(); 289 } else { 290 result = queue.removeSensor(sensor, disable); 291 } 292 if (result && !queue.hasSensors()) { 293 mTriggerListeners.remove(listener); 294 queue.dispose(); 295 } 296 return result; 297 } 298 return false; 299 } 300 } 301 flushImpl(SensorEventListener listener)302 protected boolean flushImpl(SensorEventListener listener) { 303 if (listener == null) throw new IllegalArgumentException("listener cannot be null"); 304 305 synchronized (mSensorListeners) { 306 SensorEventQueue queue = mSensorListeners.get(listener); 307 if (queue == null) { 308 return false; 309 } else { 310 return (queue.flush() == 0); 311 } 312 } 313 } 314 initDataInjectionImpl(boolean enable)315 protected boolean initDataInjectionImpl(boolean enable) { 316 synchronized (sLock) { 317 if (enable) { 318 boolean isDataInjectionModeEnabled = nativeIsDataInjectionEnabled(mNativeInstance); 319 // The HAL does not support injection OR SensorService hasn't been set in DI mode. 320 if (!isDataInjectionModeEnabled) { 321 Log.e(TAG, "Data Injection mode not enabled"); 322 return false; 323 } 324 // Initialize a client for data_injection. 325 if (sInjectEventQueue == null) { 326 try { 327 sInjectEventQueue = new InjectEventQueue( 328 mMainLooper, this, mContext.getPackageName()); 329 } catch (RuntimeException e) { 330 Log.e(TAG, "Cannot create InjectEventQueue: " + e); 331 } 332 } 333 return sInjectEventQueue != null; 334 } else { 335 // If data injection is being disabled clean up the native resources. 336 if (sInjectEventQueue != null) { 337 sInjectEventQueue.dispose(); 338 sInjectEventQueue = null; 339 } 340 return true; 341 } 342 } 343 } 344 injectSensorDataImpl(Sensor sensor, float[] values, int accuracy, long timestamp)345 protected boolean injectSensorDataImpl(Sensor sensor, float[] values, int accuracy, 346 long timestamp) { 347 synchronized (sLock) { 348 if (sInjectEventQueue == null) { 349 Log.e(TAG, "Data injection mode not activated before calling injectSensorData"); 350 return false; 351 } 352 int ret = sInjectEventQueue.injectSensorData(sensor.getHandle(), values, accuracy, 353 timestamp); 354 // If there are any errors in data injection clean up the native resources. 355 if (ret != 0) { 356 sInjectEventQueue.dispose(); 357 sInjectEventQueue = null; 358 } 359 return ret == 0; 360 } 361 } 362 cleanupSensorConnection(Sensor sensor)363 private void cleanupSensorConnection(Sensor sensor) { 364 mHandleToSensor.remove(sensor.getHandle()); 365 366 if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) { 367 synchronized (mTriggerListeners) { 368 HashMap<TriggerEventListener, TriggerEventQueue> triggerListeners = 369 new HashMap<TriggerEventListener, TriggerEventQueue>(mTriggerListeners); 370 371 for (TriggerEventListener l : triggerListeners.keySet()) { 372 if (DEBUG_DYNAMIC_SENSOR) { 373 Log.i(TAG, "removed trigger listener" + l.toString() 374 + " due to sensor disconnection"); 375 } 376 cancelTriggerSensorImpl(l, sensor, true); 377 } 378 } 379 } else { 380 synchronized (mSensorListeners) { 381 HashMap<SensorEventListener, SensorEventQueue> sensorListeners = 382 new HashMap<SensorEventListener, SensorEventQueue>(mSensorListeners); 383 384 for (SensorEventListener l: sensorListeners.keySet()) { 385 if (DEBUG_DYNAMIC_SENSOR) { 386 Log.i(TAG, "removed event listener" + l.toString() 387 + " due to sensor disconnection"); 388 } 389 unregisterListenerImpl(l, sensor); 390 } 391 } 392 } 393 } 394 updateDynamicSensorList()395 private void updateDynamicSensorList() { 396 synchronized (mFullDynamicSensorsList) { 397 if (mDynamicSensorListDirty) { 398 List<Sensor> list = new ArrayList<>(); 399 nativeGetDynamicSensors(mNativeInstance, list); 400 401 final List<Sensor> updatedList = new ArrayList<>(); 402 final List<Sensor> addedList = new ArrayList<>(); 403 final List<Sensor> removedList = new ArrayList<>(); 404 405 boolean changed = diffSortedSensorList( 406 mFullDynamicSensorsList, list, updatedList, addedList, removedList); 407 408 if (changed) { 409 if (DEBUG_DYNAMIC_SENSOR) { 410 Log.i(TAG, "DYNS dynamic sensor list cached should be updated"); 411 } 412 mFullDynamicSensorsList = updatedList; 413 414 for (Sensor s: addedList) { 415 mHandleToSensor.put(s.getHandle(), s); 416 } 417 418 Handler mainHandler = new Handler(mContext.getMainLooper()); 419 420 for (Map.Entry<DynamicSensorCallback, Handler> entry : 421 mDynamicSensorCallbacks.entrySet()) { 422 final DynamicSensorCallback callback = entry.getKey(); 423 Handler handler = 424 entry.getValue() == null ? mainHandler : entry.getValue(); 425 426 handler.post(new Runnable() { 427 @Override 428 public void run() { 429 for (Sensor s: addedList) { 430 callback.onDynamicSensorConnected(s); 431 } 432 for (Sensor s: removedList) { 433 callback.onDynamicSensorDisconnected(s); 434 } 435 } 436 }); 437 } 438 439 for (Sensor s: removedList) { 440 cleanupSensorConnection(s); 441 } 442 } 443 444 mDynamicSensorListDirty = false; 445 } 446 } 447 } 448 setupDynamicSensorBroadcastReceiver()449 private void setupDynamicSensorBroadcastReceiver() { 450 if (mDynamicSensorBroadcastReceiver == null) { 451 mDynamicSensorBroadcastReceiver = new BroadcastReceiver() { 452 @Override 453 public void onReceive(Context context, Intent intent) { 454 if (intent.getAction() == Intent.ACTION_DYNAMIC_SENSOR_CHANGED) { 455 if (DEBUG_DYNAMIC_SENSOR) { 456 Log.i(TAG, "DYNS received DYNAMIC_SENSOR_CHANED broadcast"); 457 } 458 // Dynamic sensors probably changed 459 mDynamicSensorListDirty = true; 460 updateDynamicSensorList(); 461 } 462 } 463 }; 464 465 IntentFilter filter = new IntentFilter("dynamic_sensor_change"); 466 filter.addAction(Intent.ACTION_DYNAMIC_SENSOR_CHANGED); 467 mContext.registerReceiver(mDynamicSensorBroadcastReceiver, filter, 468 Context.RECEIVER_NOT_EXPORTED); 469 } 470 } 471 teardownDynamicSensorBroadcastReceiver()472 private void teardownDynamicSensorBroadcastReceiver() { 473 mDynamicSensorCallbacks.clear(); 474 mContext.unregisterReceiver(mDynamicSensorBroadcastReceiver); 475 mDynamicSensorBroadcastReceiver = null; 476 } 477 478 /** @hide */ registerDynamicSensorCallbackImpl( DynamicSensorCallback callback, Handler handler)479 protected void registerDynamicSensorCallbackImpl( 480 DynamicSensorCallback callback, Handler handler) { 481 if (DEBUG_DYNAMIC_SENSOR) { 482 Log.i(TAG, "DYNS Register dynamic sensor callback"); 483 } 484 485 if (callback == null) { 486 throw new IllegalArgumentException("callback cannot be null"); 487 } 488 if (mDynamicSensorCallbacks.containsKey(callback)) { 489 // has been already registered, ignore 490 return; 491 } 492 493 setupDynamicSensorBroadcastReceiver(); 494 mDynamicSensorCallbacks.put(callback, handler); 495 } 496 497 /** @hide */ unregisterDynamicSensorCallbackImpl( DynamicSensorCallback callback)498 protected void unregisterDynamicSensorCallbackImpl( 499 DynamicSensorCallback callback) { 500 if (DEBUG_DYNAMIC_SENSOR) { 501 Log.i(TAG, "Removing dynamic sensor listerner"); 502 } 503 mDynamicSensorCallbacks.remove(callback); 504 } 505 506 /* 507 * Find the difference of two List<Sensor> assuming List are sorted by handle of sensor, 508 * assuming the input list is already sorted by handle. Inputs are ol and nl; outputs are 509 * updated, added and removed. Any of the output lists can be null in case the result is not 510 * interested. 511 */ diffSortedSensorList( List<Sensor> oldList, List<Sensor> newList, List<Sensor> updated, List<Sensor> added, List<Sensor> removed)512 private static boolean diffSortedSensorList( 513 List<Sensor> oldList, List<Sensor> newList, List<Sensor> updated, 514 List<Sensor> added, List<Sensor> removed) { 515 516 boolean changed = false; 517 518 int i = 0, j = 0; 519 while (true) { 520 if (j < oldList.size() && (i >= newList.size() 521 || newList.get(i).getHandle() > oldList.get(j).getHandle())) { 522 changed = true; 523 if (removed != null) { 524 removed.add(oldList.get(j)); 525 } 526 ++j; 527 } else if (i < newList.size() && (j >= oldList.size() 528 || newList.get(i).getHandle() < oldList.get(j).getHandle())) { 529 changed = true; 530 if (added != null) { 531 added.add(newList.get(i)); 532 } 533 if (updated != null) { 534 updated.add(newList.get(i)); 535 } 536 ++i; 537 } else if (i < newList.size() && j < oldList.size() 538 && newList.get(i).getHandle() == oldList.get(j).getHandle()) { 539 if (updated != null) { 540 updated.add(oldList.get(j)); 541 } 542 ++i; 543 ++j; 544 } else { 545 break; 546 } 547 } 548 return changed; 549 } 550 551 /** @hide */ configureDirectChannelImpl( SensorDirectChannel channel, Sensor sensor, int rate)552 protected int configureDirectChannelImpl( 553 SensorDirectChannel channel, Sensor sensor, int rate) { 554 if (!channel.isOpen()) { 555 throw new IllegalStateException("channel is closed"); 556 } 557 558 if (rate < SensorDirectChannel.RATE_STOP 559 || rate > SensorDirectChannel.RATE_VERY_FAST) { 560 throw new IllegalArgumentException("rate parameter invalid"); 561 } 562 563 if (sensor == null && rate != SensorDirectChannel.RATE_STOP) { 564 // the stop all sensors case 565 throw new IllegalArgumentException( 566 "when sensor is null, rate can only be DIRECT_RATE_STOP"); 567 } 568 569 int sensorHandle = (sensor == null) ? -1 : sensor.getHandle(); 570 if (sensor != null 571 && isSensorInCappedSet(sensor.getType()) 572 && rate > CAPPED_SAMPLING_RATE_LEVEL 573 && mIsPackageDebuggable 574 && !hasHighSamplingRateSensorsPermission() 575 && Compatibility.isChangeEnabled(CHANGE_ID_SAMPLING_RATE_SENSORS_PERMISSION)) { 576 throw new SecurityException("To use the sampling rate level " + rate 577 + ", app needs to declare the normal permission" 578 + " HIGH_SAMPLING_RATE_SENSORS."); 579 } 580 581 int ret = nativeConfigDirectChannel( 582 mNativeInstance, channel.getNativeHandle(), sensorHandle, rate); 583 if (rate == SensorDirectChannel.RATE_STOP) { 584 return (ret == 0) ? 1 : 0; 585 } else { 586 return (ret > 0) ? ret : 0; 587 } 588 } 589 590 /** @hide */ createDirectChannelImpl( MemoryFile memoryFile, HardwareBuffer hardwareBuffer)591 protected SensorDirectChannel createDirectChannelImpl( 592 MemoryFile memoryFile, HardwareBuffer hardwareBuffer) { 593 int id; 594 int type; 595 long size; 596 if (memoryFile != null) { 597 int fd; 598 try { 599 fd = memoryFile.getFileDescriptor().getInt$(); 600 } catch (IOException e) { 601 throw new IllegalArgumentException("MemoryFile object is not valid"); 602 } 603 604 if (memoryFile.length() < MIN_DIRECT_CHANNEL_BUFFER_SIZE) { 605 throw new IllegalArgumentException( 606 "Size of MemoryFile has to be greater than " 607 + MIN_DIRECT_CHANNEL_BUFFER_SIZE); 608 } 609 610 size = memoryFile.length(); 611 id = nativeCreateDirectChannel( 612 mNativeInstance, size, SensorDirectChannel.TYPE_MEMORY_FILE, fd, null); 613 if (id <= 0) { 614 throw new UncheckedIOException( 615 new IOException("create MemoryFile direct channel failed " + id)); 616 } 617 type = SensorDirectChannel.TYPE_MEMORY_FILE; 618 } else if (hardwareBuffer != null) { 619 if (hardwareBuffer.getFormat() != HardwareBuffer.BLOB) { 620 throw new IllegalArgumentException("Format of HardwareBuffer must be BLOB"); 621 } 622 if (hardwareBuffer.getHeight() != 1) { 623 throw new IllegalArgumentException("Height of HardwareBuffer must be 1"); 624 } 625 if (hardwareBuffer.getWidth() < MIN_DIRECT_CHANNEL_BUFFER_SIZE) { 626 throw new IllegalArgumentException( 627 "Width if HaradwareBuffer must be greater than " 628 + MIN_DIRECT_CHANNEL_BUFFER_SIZE); 629 } 630 if ((hardwareBuffer.getUsage() & HardwareBuffer.USAGE_SENSOR_DIRECT_DATA) == 0) { 631 throw new IllegalArgumentException( 632 "HardwareBuffer must set usage flag USAGE_SENSOR_DIRECT_DATA"); 633 } 634 size = hardwareBuffer.getWidth(); 635 id = nativeCreateDirectChannel( 636 mNativeInstance, size, SensorDirectChannel.TYPE_HARDWARE_BUFFER, 637 -1, hardwareBuffer); 638 if (id <= 0) { 639 throw new UncheckedIOException( 640 new IOException("create HardwareBuffer direct channel failed " + id)); 641 } 642 type = SensorDirectChannel.TYPE_HARDWARE_BUFFER; 643 } else { 644 throw new NullPointerException("shared memory object cannot be null"); 645 } 646 return new SensorDirectChannel(this, id, type, size); 647 } 648 649 /** @hide */ destroyDirectChannelImpl(SensorDirectChannel channel)650 protected void destroyDirectChannelImpl(SensorDirectChannel channel) { 651 if (channel != null) { 652 nativeDestroyDirectChannel(mNativeInstance, channel.getNativeHandle()); 653 } 654 } 655 656 /* 657 * BaseEventQueue is the communication channel with the sensor service, 658 * SensorEventQueue, TriggerEventQueue are subclases and there is one-to-one mapping between 659 * the queues and the listeners. InjectEventQueue is also a sub-class which is a special case 660 * where data is being injected into the sensor HAL through the sensor service. It is not 661 * associated with any listener and there is one InjectEventQueue associated with a 662 * SensorManager instance. 663 */ 664 private abstract static class BaseEventQueue { nativeInitBaseEventQueue(long nativeManager, WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ, String packageName, int mode, String opPackageName, String attributionTag)665 private static native long nativeInitBaseEventQueue(long nativeManager, 666 WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ, 667 String packageName, int mode, String opPackageName, String attributionTag); nativeEnableSensor(long eventQ, int handle, int rateUs, int maxBatchReportLatencyUs)668 private static native int nativeEnableSensor(long eventQ, int handle, int rateUs, 669 int maxBatchReportLatencyUs); nativeDisableSensor(long eventQ, int handle)670 private static native int nativeDisableSensor(long eventQ, int handle); nativeDestroySensorEventQueue(long eventQ)671 private static native void nativeDestroySensorEventQueue(long eventQ); nativeFlushSensor(long eventQ)672 private static native int nativeFlushSensor(long eventQ); nativeInjectSensorData(long eventQ, int handle, float[] values, int accuracy, long timestamp)673 private static native int nativeInjectSensorData(long eventQ, int handle, 674 float[] values, int accuracy, long timestamp); 675 676 private long mNativeSensorEventQueue; 677 private final SparseBooleanArray mActiveSensors = new SparseBooleanArray(); 678 protected final SparseIntArray mSensorAccuracies = new SparseIntArray(); 679 protected final SparseIntArray mSensorDiscontinuityCounts = new SparseIntArray(); 680 private final CloseGuard mCloseGuard = CloseGuard.get(); 681 protected final SystemSensorManager mManager; 682 683 protected static final int OPERATING_MODE_NORMAL = 0; 684 protected static final int OPERATING_MODE_DATA_INJECTION = 1; 685 BaseEventQueue(Looper looper, SystemSensorManager manager, int mode, String packageName)686 BaseEventQueue(Looper looper, SystemSensorManager manager, int mode, String packageName) { 687 if (packageName == null) packageName = ""; 688 mNativeSensorEventQueue = nativeInitBaseEventQueue(manager.mNativeInstance, 689 new WeakReference<>(this), looper.getQueue(), 690 packageName, mode, manager.mContext.getOpPackageName(), 691 manager.mContext.getAttributionTag()); 692 mCloseGuard.open("BaseEventQueue.dispose"); 693 mManager = manager; 694 } 695 dispose()696 public void dispose() { 697 dispose(false); 698 } 699 addSensor( Sensor sensor, int delayUs, int maxBatchReportLatencyUs)700 public boolean addSensor( 701 Sensor sensor, int delayUs, int maxBatchReportLatencyUs) { 702 // Check if already present. 703 int handle = sensor.getHandle(); 704 if (mActiveSensors.get(handle)) return false; 705 706 // Get ready to receive events before calling enable. 707 mActiveSensors.put(handle, true); 708 addSensorEvent(sensor); 709 if (enableSensor(sensor, delayUs, maxBatchReportLatencyUs) != 0) { 710 // Try continuous mode if batching fails. 711 if (maxBatchReportLatencyUs == 0 712 || maxBatchReportLatencyUs > 0 && enableSensor(sensor, delayUs, 0) != 0) { 713 removeSensor(sensor, false); 714 return false; 715 } 716 } 717 return true; 718 } 719 removeAllSensors()720 public boolean removeAllSensors() { 721 for (int i = 0; i < mActiveSensors.size(); i++) { 722 if (mActiveSensors.valueAt(i) == true) { 723 int handle = mActiveSensors.keyAt(i); 724 Sensor sensor = mManager.mHandleToSensor.get(handle); 725 if (sensor != null) { 726 disableSensor(sensor); 727 mActiveSensors.put(handle, false); 728 removeSensorEvent(sensor); 729 } else { 730 // sensor just disconnected -- just ignore. 731 } 732 } 733 } 734 return true; 735 } 736 removeSensor(Sensor sensor, boolean disable)737 public boolean removeSensor(Sensor sensor, boolean disable) { 738 final int handle = sensor.getHandle(); 739 if (mActiveSensors.get(handle)) { 740 if (disable) disableSensor(sensor); 741 mActiveSensors.put(sensor.getHandle(), false); 742 removeSensorEvent(sensor); 743 return true; 744 } 745 return false; 746 } 747 flush()748 public int flush() { 749 if (mNativeSensorEventQueue == 0) throw new NullPointerException(); 750 return nativeFlushSensor(mNativeSensorEventQueue); 751 } 752 hasSensors()753 public boolean hasSensors() { 754 // no more sensors are set 755 return mActiveSensors.indexOfValue(true) >= 0; 756 } 757 758 @Override finalize()759 protected void finalize() throws Throwable { 760 try { 761 dispose(true); 762 } finally { 763 super.finalize(); 764 } 765 } 766 dispose(boolean finalized)767 private void dispose(boolean finalized) { 768 if (mCloseGuard != null) { 769 if (finalized) { 770 mCloseGuard.warnIfOpen(); 771 } 772 mCloseGuard.close(); 773 } 774 if (mNativeSensorEventQueue != 0) { 775 nativeDestroySensorEventQueue(mNativeSensorEventQueue); 776 mNativeSensorEventQueue = 0; 777 } 778 } 779 enableSensor( Sensor sensor, int rateUs, int maxBatchReportLatencyUs)780 private int enableSensor( 781 Sensor sensor, int rateUs, int maxBatchReportLatencyUs) { 782 if (mNativeSensorEventQueue == 0) throw new NullPointerException(); 783 if (sensor == null) throw new NullPointerException(); 784 if (mManager.isSensorInCappedSet(sensor.getType()) 785 && rateUs < CAPPED_SAMPLING_PERIOD_US 786 && mManager.mIsPackageDebuggable 787 && !mManager.hasHighSamplingRateSensorsPermission() 788 && Compatibility.isChangeEnabled(CHANGE_ID_SAMPLING_RATE_SENSORS_PERMISSION)) { 789 throw new SecurityException("To use the sampling rate of " + rateUs 790 + " microseconds, app needs to declare the normal permission" 791 + " HIGH_SAMPLING_RATE_SENSORS."); 792 } 793 return nativeEnableSensor(mNativeSensorEventQueue, sensor.getHandle(), rateUs, 794 maxBatchReportLatencyUs); 795 } 796 injectSensorDataBase(int handle, float[] values, int accuracy, long timestamp)797 protected int injectSensorDataBase(int handle, float[] values, int accuracy, 798 long timestamp) { 799 return nativeInjectSensorData( 800 mNativeSensorEventQueue, handle, values, accuracy, timestamp); 801 } 802 disableSensor(Sensor sensor)803 private int disableSensor(Sensor sensor) { 804 if (mNativeSensorEventQueue == 0) throw new NullPointerException(); 805 if (sensor == null) throw new NullPointerException(); 806 return nativeDisableSensor(mNativeSensorEventQueue, sensor.getHandle()); 807 } 808 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) dispatchSensorEvent(int handle, float[] values, int accuracy, long timestamp)809 protected abstract void dispatchSensorEvent(int handle, float[] values, int accuracy, 810 long timestamp); 811 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) dispatchFlushCompleteEvent(int handle)812 protected abstract void dispatchFlushCompleteEvent(int handle); 813 814 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) dispatchAdditionalInfoEvent( int handle, int type, int serial, float[] floatValues, int[] intValues)815 protected void dispatchAdditionalInfoEvent( 816 int handle, int type, int serial, float[] floatValues, int[] intValues) { 817 // default implementation is do nothing 818 } 819 addSensorEvent(Sensor sensor)820 protected abstract void addSensorEvent(Sensor sensor); removeSensorEvent(Sensor sensor)821 protected abstract void removeSensorEvent(Sensor sensor); 822 } 823 824 static final class SensorEventQueue extends BaseEventQueue { 825 private final SensorEventListener mListener; 826 private final SparseArray<SensorEvent> mSensorsEvents = new SparseArray<SensorEvent>(); 827 SensorEventQueue(SensorEventListener listener, Looper looper, SystemSensorManager manager, String packageName)828 public SensorEventQueue(SensorEventListener listener, Looper looper, 829 SystemSensorManager manager, String packageName) { 830 super(looper, manager, OPERATING_MODE_NORMAL, packageName); 831 mListener = listener; 832 } 833 834 @Override addSensorEvent(Sensor sensor)835 public void addSensorEvent(Sensor sensor) { 836 SensorEvent t = new SensorEvent(Sensor.getMaxLengthValuesArray(sensor, 837 mManager.mTargetSdkLevel)); 838 synchronized (mSensorsEvents) { 839 mSensorsEvents.put(sensor.getHandle(), t); 840 } 841 } 842 843 @Override removeSensorEvent(Sensor sensor)844 public void removeSensorEvent(Sensor sensor) { 845 synchronized (mSensorsEvents) { 846 mSensorsEvents.delete(sensor.getHandle()); 847 } 848 } 849 850 // Called from native code. 851 @SuppressWarnings("unused") 852 @Override dispatchSensorEvent(int handle, float[] values, int inAccuracy, long timestamp)853 protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy, 854 long timestamp) { 855 final Sensor sensor = mManager.mHandleToSensor.get(handle); 856 if (sensor == null) { 857 // sensor disconnected 858 return; 859 } 860 861 SensorEvent t = null; 862 synchronized (mSensorsEvents) { 863 t = mSensorsEvents.get(handle); 864 } 865 866 if (t == null) { 867 // This may happen if the client has unregistered and there are pending events in 868 // the queue waiting to be delivered. Ignore. 869 return; 870 } 871 // Copy from the values array. 872 System.arraycopy(values, 0, t.values, 0, t.values.length); 873 t.timestamp = timestamp; 874 t.accuracy = inAccuracy; 875 t.sensor = sensor; 876 877 // call onAccuracyChanged() only if the value changes 878 final int accuracy = mSensorAccuracies.get(handle); 879 if (t.accuracy >= 0 && accuracy != t.accuracy) { 880 mSensorAccuracies.put(handle, t.accuracy); 881 mListener.onAccuracyChanged(t.sensor, t.accuracy); 882 } 883 884 // Indicate if the discontinuity count changed 885 if (t.sensor.getType() == Sensor.TYPE_HEAD_TRACKER) { 886 final int lastCount = mSensorDiscontinuityCounts.get(handle); 887 final int curCount = Float.floatToIntBits(values[6]); 888 if (lastCount >= 0 && lastCount != curCount) { 889 mSensorDiscontinuityCounts.put(handle, curCount); 890 t.firstEventAfterDiscontinuity = true; 891 } 892 } 893 894 mListener.onSensorChanged(t); 895 } 896 897 // Called from native code. 898 @SuppressWarnings("unused") 899 @Override dispatchFlushCompleteEvent(int handle)900 protected void dispatchFlushCompleteEvent(int handle) { 901 if (mListener instanceof SensorEventListener2) { 902 final Sensor sensor = mManager.mHandleToSensor.get(handle); 903 if (sensor == null) { 904 // sensor disconnected 905 return; 906 } 907 ((SensorEventListener2) mListener).onFlushCompleted(sensor); 908 } 909 return; 910 } 911 912 // Called from native code. 913 @SuppressWarnings("unused") 914 @Override dispatchAdditionalInfoEvent( int handle, int type, int serial, float[] floatValues, int[] intValues)915 protected void dispatchAdditionalInfoEvent( 916 int handle, int type, int serial, float[] floatValues, int[] intValues) { 917 if (mListener instanceof SensorEventCallback) { 918 final Sensor sensor = mManager.mHandleToSensor.get(handle); 919 if (sensor == null) { 920 // sensor disconnected 921 return; 922 } 923 SensorAdditionalInfo info = 924 new SensorAdditionalInfo(sensor, type, serial, intValues, floatValues); 925 ((SensorEventCallback) mListener).onSensorAdditionalInfo(info); 926 } 927 } 928 } 929 930 static final class TriggerEventQueue extends BaseEventQueue { 931 private final TriggerEventListener mListener; 932 private final SparseArray<TriggerEvent> mTriggerEvents = new SparseArray<TriggerEvent>(); 933 TriggerEventQueue(TriggerEventListener listener, Looper looper, SystemSensorManager manager, String packageName)934 public TriggerEventQueue(TriggerEventListener listener, Looper looper, 935 SystemSensorManager manager, String packageName) { 936 super(looper, manager, OPERATING_MODE_NORMAL, packageName); 937 mListener = listener; 938 } 939 940 @Override addSensorEvent(Sensor sensor)941 public void addSensorEvent(Sensor sensor) { 942 TriggerEvent t = new TriggerEvent(Sensor.getMaxLengthValuesArray(sensor, 943 mManager.mTargetSdkLevel)); 944 synchronized (mTriggerEvents) { 945 mTriggerEvents.put(sensor.getHandle(), t); 946 } 947 } 948 949 @Override removeSensorEvent(Sensor sensor)950 public void removeSensorEvent(Sensor sensor) { 951 synchronized (mTriggerEvents) { 952 mTriggerEvents.delete(sensor.getHandle()); 953 } 954 } 955 956 // Called from native code. 957 @SuppressWarnings("unused") 958 @Override dispatchSensorEvent(int handle, float[] values, int accuracy, long timestamp)959 protected void dispatchSensorEvent(int handle, float[] values, int accuracy, 960 long timestamp) { 961 final Sensor sensor = mManager.mHandleToSensor.get(handle); 962 if (sensor == null) { 963 // sensor disconnected 964 return; 965 } 966 TriggerEvent t = null; 967 synchronized (mTriggerEvents) { 968 t = mTriggerEvents.get(handle); 969 } 970 if (t == null) { 971 Log.e(TAG, "Error: Trigger Event is null for Sensor: " + sensor); 972 return; 973 } 974 975 // Copy from the values array. 976 System.arraycopy(values, 0, t.values, 0, t.values.length); 977 t.timestamp = timestamp; 978 t.sensor = sensor; 979 980 // A trigger sensor is auto disabled. So just clean up and don't call native 981 // disable. 982 mManager.cancelTriggerSensorImpl(mListener, sensor, false); 983 984 mListener.onTrigger(t); 985 } 986 987 @SuppressWarnings("unused") dispatchFlushCompleteEvent(int handle)988 protected void dispatchFlushCompleteEvent(int handle) { 989 } 990 } 991 992 final class InjectEventQueue extends BaseEventQueue { InjectEventQueue(Looper looper, SystemSensorManager manager, String packageName)993 public InjectEventQueue(Looper looper, SystemSensorManager manager, String packageName) { 994 super(looper, manager, OPERATING_MODE_DATA_INJECTION, packageName); 995 } 996 injectSensorData(int handle, float[] values, int accuracy, long timestamp)997 int injectSensorData(int handle, float[] values, int accuracy, long timestamp) { 998 return injectSensorDataBase(handle, values, accuracy, timestamp); 999 } 1000 1001 @SuppressWarnings("unused") dispatchSensorEvent(int handle, float[] values, int accuracy, long timestamp)1002 protected void dispatchSensorEvent(int handle, float[] values, int accuracy, 1003 long timestamp) { 1004 } 1005 1006 @SuppressWarnings("unused") dispatchFlushCompleteEvent(int handle)1007 protected void dispatchFlushCompleteEvent(int handle) { 1008 1009 } 1010 1011 @SuppressWarnings("unused") addSensorEvent(Sensor sensor)1012 protected void addSensorEvent(Sensor sensor) { 1013 1014 } 1015 1016 @SuppressWarnings("unused") removeSensorEvent(Sensor sensor)1017 protected void removeSensorEvent(Sensor sensor) { 1018 1019 } 1020 } 1021 setOperationParameterImpl(SensorAdditionalInfo parameter)1022 protected boolean setOperationParameterImpl(SensorAdditionalInfo parameter) { 1023 int handle = -1; 1024 if (parameter.sensor != null) handle = parameter.sensor.getHandle(); 1025 return nativeSetOperationParameter( 1026 mNativeInstance, handle, 1027 parameter.type, parameter.floatValues, parameter.intValues) == 0; 1028 } 1029 1030 /** 1031 * Checks if a sensor should be capped according to HIGH_SAMPLING_RATE_SENSORS 1032 * permission. 1033 * 1034 * This needs to be kept in sync with the list defined on the native side 1035 * in frameworks/native/services/sensorservice/SensorService.cpp 1036 */ isSensorInCappedSet(int sensorType)1037 private boolean isSensorInCappedSet(int sensorType) { 1038 return (sensorType == Sensor.TYPE_ACCELEROMETER 1039 || sensorType == Sensor.TYPE_ACCELEROMETER_UNCALIBRATED 1040 || sensorType == Sensor.TYPE_GYROSCOPE 1041 || sensorType == Sensor.TYPE_GYROSCOPE_UNCALIBRATED 1042 || sensorType == Sensor.TYPE_MAGNETIC_FIELD 1043 || sensorType == Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED); 1044 } 1045 hasHighSamplingRateSensorsPermission()1046 private boolean hasHighSamplingRateSensorsPermission() { 1047 if (!mHasHighSamplingRateSensorsPermission.isPresent()) { 1048 boolean granted = mContext.getPackageManager().checkPermission( 1049 HIGH_SAMPLING_RATE_SENSORS_PERMISSION, 1050 mContext.getApplicationInfo().packageName) == PERMISSION_GRANTED; 1051 mHasHighSamplingRateSensorsPermission = Optional.of(granted); 1052 } 1053 1054 return mHasHighSamplingRateSensorsPermission.get(); 1055 } 1056 } 1057