1 /* 2 * Copyright (C) 2015 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.car.hardware; 18 19 import android.Manifest; 20 import android.annotation.IntDef; 21 import android.annotation.RequiresPermission; 22 import android.car.Car; 23 import android.car.CarApiUtil; 24 import android.car.CarLibLog; 25 import android.car.CarManagerBase; 26 import android.car.CarNotConnectedException; 27 import android.content.Context; 28 import android.os.Bundle; 29 import android.os.Handler; 30 import android.os.IBinder; 31 import android.os.RemoteException; 32 import android.util.Log; 33 import android.util.SparseArray; 34 import android.util.SparseIntArray; 35 36 import com.android.car.internal.CarRatedListeners; 37 import com.android.car.internal.SingleMessageHandler; 38 39 import java.lang.annotation.Retention; 40 import java.lang.annotation.RetentionPolicy; 41 import java.lang.ref.WeakReference; 42 import java.util.ArrayList; 43 import java.util.Iterator; 44 import java.util.List; 45 import java.util.function.Consumer; 46 47 /** 48 * API for monitoring car sensor data. 49 */ 50 public final class CarSensorManager implements CarManagerBase { 51 /** @hide */ 52 public static final int SENSOR_TYPE_RESERVED1 = 1; 53 /** 54 * This sensor represents vehicle speed in m/s. 55 * Sensor data in {@link CarSensorEvent} is a float which will be >= 0. 56 * This requires {@link Car#PERMISSION_SPEED} permission. 57 */ 58 public static final int SENSOR_TYPE_CAR_SPEED = 2; 59 /** 60 * Represents engine RPM of the car. Sensor data in {@link CarSensorEvent} is a float. 61 */ 62 public static final int SENSOR_TYPE_RPM = 3; 63 /** 64 * Total travel distance of the car in Kilometer. Sensor data is a float. 65 * This requires {@link Car#PERMISSION_MILEAGE} permission. 66 */ 67 public static final int SENSOR_TYPE_ODOMETER = 4; 68 /** 69 * Indicates fuel level of the car. 70 * In {@link CarSensorEvent}, floatValues[{@link CarSensorEvent#INDEX_FUEL_LEVEL_IN_PERCENTILE}] 71 * represents fuel level in percentile (0 to 100) while 72 * floatValues[{@link CarSensorEvent#INDEX_FUEL_LEVEL_IN_DISTANCE}] represents estimated range 73 * in Kilometer with the remaining fuel. 74 * Note that the gas mileage used for the estimation may not represent the current driving 75 * condition. 76 * This requires {@link Car#PERMISSION_FUEL} permission. 77 */ 78 public static final int SENSOR_TYPE_FUEL_LEVEL = 5; 79 /** 80 * Represents the current status of parking brake. Sensor data in {@link CarSensorEvent} is an 81 * intValues[0]. Value of 1 represents parking brake applied while 0 means the other way 82 * around. For this sensor, rate in {@link #registerListener(OnSensorChangedListener, int, int)} 83 * will be ignored and all changes will be notified. 84 */ 85 public static final int SENSOR_TYPE_PARKING_BRAKE = 6; 86 /** 87 * This represents the current position of transmission gear. Sensor data in 88 * {@link CarSensorEvent} is an intValues[0]. For the meaning of the value, check 89 * {@link CarSensorEvent#GEAR_NEUTRAL} and other GEAR_*. 90 */ 91 public static final int SENSOR_TYPE_GEAR = 7; 92 /** @hide */ 93 public static final int SENSOR_TYPE_RESERVED8 = 8; 94 /** 95 * Day/night sensor. Sensor data is intValues[0]. 96 */ 97 public static final int SENSOR_TYPE_NIGHT = 9; 98 /** @hide */ 99 public static final int SENSOR_TYPE_RESERVED10 = 10; 100 /** 101 * Represents the current driving status of car. Different user interaction should be used 102 * depending on the current driving status. Driving status is intValues[0]. 103 */ 104 public static final int SENSOR_TYPE_DRIVING_STATUS = 11; 105 /** 106 * Environment like temperature and pressure. 107 */ 108 public static final int SENSOR_TYPE_ENVIRONMENT = 12; 109 /** @hide */ 110 public static final int SENSOR_TYPE_RESERVED13 = 13; 111 /** @hide */ 112 public static final int SENSOR_TYPE_RESERVED14 = 14; 113 /** @hide */ 114 public static final int SENSOR_TYPE_RESERVED15 = 15; 115 /** @hide */ 116 public static final int SENSOR_TYPE_RESERVED16 = 16; 117 /** @hide */ 118 public static final int SENSOR_TYPE_RESERVED17 = 17; 119 /** @hide */ 120 public static final int SENSOR_TYPE_RESERVED18 = 18; 121 /** @hide */ 122 public static final int SENSOR_TYPE_RESERVED19 = 19; 123 /** @hide */ 124 public static final int SENSOR_TYPE_RESERVED20 = 20; 125 /** @hide */ 126 public static final int SENSOR_TYPE_RESERVED21 = 21; 127 /** 128 * Represents ignition state. The value should be one of the constants that starts with 129 * IGNITION_STATE_* in {@link CarSensorEvent}. 130 */ 131 public static final int SENSOR_TYPE_IGNITION_STATE = 22; 132 /** 133 * Represents wheel distance in millimeters. Some cars may not have individual sensors on each 134 * wheel. If a value is not available, Long.MAX_VALUE will be reported. The wheel distance 135 * accumulates over time. It increments on forward movement, and decrements on reverse. Wheel 136 * distance shall be reset to zero each time a vehicle is started by the user. 137 * This requires {@link Car#PERMISSION_SPEED} permission. 138 */ 139 public static final int SENSOR_TYPE_WHEEL_TICK_DISTANCE = 23; 140 /** 141 * Set to true when ABS is active. This sensor is event driven. 142 * This requires {@link Car#PERMISSION_VEHICLE_DYNAMICS_STATE} permission. 143 */ 144 public static final int SENSOR_TYPE_ABS_ACTIVE = 24; 145 /** 146 * Set to true when traction control is active. This sensor is event driven. 147 * This requires {@link Car#PERMISSION_VEHICLE_DYNAMICS_STATE} permission. 148 */ 149 public static final int SENSOR_TYPE_TRACTION_CONTROL_ACTIVE = 25; 150 151 /** 152 * Sensor type bigger than this is invalid. Always update this after adding a new sensor. 153 * @hide 154 */ 155 private static final int SENSOR_TYPE_MAX = SENSOR_TYPE_TRACTION_CONTROL_ACTIVE; 156 157 /** 158 * Sensors defined in this range [{@link #SENSOR_TYPE_VENDOR_EXTENSION_START}, 159 * {@link #SENSOR_TYPE_VENDOR_EXTENSION_END}] is for each car vendor's to use. 160 * This should be only used for system app to access sensors not defined as standard types. 161 * So the sensor supported in this range can vary depending on car models / manufacturers. 162 * 3rd party apps should not use sensors in this range as they are not compatible across 163 * different cars. Additionally 3rd party apps trying to access sensor in this range will get 164 * security exception as their access is restricted to system apps. 165 * 166 * @hide 167 */ 168 public static final int SENSOR_TYPE_VENDOR_EXTENSION_START = 0x60000000; 169 public static final int SENSOR_TYPE_VENDOR_EXTENSION_END = 0x6fffffff; 170 171 /** @hide */ 172 @IntDef({ 173 SENSOR_TYPE_CAR_SPEED, 174 SENSOR_TYPE_RPM, 175 SENSOR_TYPE_ODOMETER, 176 SENSOR_TYPE_FUEL_LEVEL, 177 SENSOR_TYPE_PARKING_BRAKE, 178 SENSOR_TYPE_GEAR, 179 SENSOR_TYPE_NIGHT, 180 SENSOR_TYPE_DRIVING_STATUS, 181 SENSOR_TYPE_ENVIRONMENT, 182 SENSOR_TYPE_IGNITION_STATE, 183 SENSOR_TYPE_WHEEL_TICK_DISTANCE, 184 SENSOR_TYPE_ABS_ACTIVE, 185 SENSOR_TYPE_TRACTION_CONTROL_ACTIVE, 186 }) 187 @Retention(RetentionPolicy.SOURCE) 188 public @interface SensorType {} 189 190 /** Read sensor in default normal rate set for each sensors. This is default rate. */ 191 public static final int SENSOR_RATE_NORMAL = 3; 192 public static final int SENSOR_RATE_UI = 2; 193 public static final int SENSOR_RATE_FAST = 1; 194 /** Read sensor at the maximum rate. Actual rate will be different depending on the sensor. */ 195 public static final int SENSOR_RATE_FASTEST = 0; 196 197 /** @hide */ 198 @IntDef({ 199 SENSOR_RATE_NORMAL, 200 SENSOR_RATE_UI, 201 SENSOR_RATE_FAST, 202 SENSOR_RATE_FASTEST 203 }) 204 @Retention(RetentionPolicy.SOURCE) 205 public @interface SensorRate {} 206 207 private static final int MSG_SENSOR_EVENTS = 0; 208 209 private final ICarSensor mService; 210 211 private CarSensorEventListenerToService mCarSensorEventListenerToService; 212 213 /** 214 * To keep record of locally active sensors. Key is sensor type. This is used as a basic lock 215 * for all client accesses. 216 */ 217 private final SparseArray<CarSensorListeners> mActiveSensorListeners = new SparseArray<>(); 218 219 /** Handles call back into clients. */ 220 private final SingleMessageHandler<CarSensorEvent> mHandlerCallback; 221 222 223 /** @hide */ 224 public CarSensorManager(IBinder service, Context context, Handler handler) { 225 mService = ICarSensor.Stub.asInterface(service); 226 mHandlerCallback = new SingleMessageHandler<CarSensorEvent>(handler.getLooper(), 227 MSG_SENSOR_EVENTS) { 228 @Override 229 protected void handleEvent(CarSensorEvent event) { 230 CarSensorListeners listeners; 231 synchronized (mActiveSensorListeners) { 232 listeners = mActiveSensorListeners.get(event.sensorType); 233 } 234 if (listeners != null) { 235 listeners.onSensorChanged(event); 236 } 237 } 238 }; 239 } 240 241 /** @hide */ 242 @Override 243 public void onCarDisconnected() { 244 synchronized(mActiveSensorListeners) { 245 mActiveSensorListeners.clear(); 246 mCarSensorEventListenerToService = null; 247 } 248 } 249 250 /** 251 * Give the list of CarSensors available in the connected car. 252 * @return array of all sensor types supported. 253 * @throws CarNotConnectedException if the connection to the car service has been lost. 254 */ 255 public int[] getSupportedSensors() throws CarNotConnectedException { 256 try { 257 return mService.getSupportedSensors(); 258 } catch (IllegalStateException e) { 259 CarApiUtil.checkCarNotConnectedExceptionFromCarService(e); 260 } catch (RemoteException e) { 261 throw new CarNotConnectedException(e); 262 } 263 return new int[0]; 264 } 265 266 /** 267 * Tells if given sensor is supported or not. 268 * @param sensorType 269 * @return true if the sensor is supported. 270 * @throws CarNotConnectedException if the connection to the car service has been lost. 271 */ 272 public boolean isSensorSupported(@SensorType int sensorType) throws CarNotConnectedException { 273 int[] sensors = getSupportedSensors(); 274 for (int sensorSupported: sensors) { 275 if (sensorType == sensorSupported) { 276 return true; 277 } 278 } 279 return false; 280 } 281 282 /** 283 * Check if given sensorList is including the sensorType. 284 * @param sensorList 285 * @param sensorType 286 * @return 287 */ 288 public static boolean isSensorSupported(int[] sensorList, @SensorType int sensorType) { 289 for (int sensorSupported: sensorList) { 290 if (sensorType == sensorSupported) { 291 return true; 292 } 293 } 294 return false; 295 } 296 297 /** 298 * Listener for car sensor data change. 299 * Callbacks are called in the Looper context. 300 */ 301 public interface OnSensorChangedListener { 302 /** 303 * Called when there is a new sensor data from car. 304 * @param event Incoming sensor event for the given sensor type. 305 */ 306 void onSensorChanged(final CarSensorEvent event); 307 } 308 309 /** 310 * Register {@link OnSensorChangedListener} to get repeated sensor updates. Multiple listeners 311 * can be registered for a single sensor or the same listener can be used for different sensors. 312 * If the same listener is registered again for the same sensor, it will be either ignored or 313 * updated depending on the rate. 314 * <p> 315 * Requires {@link Car#PERMISSION_SPEED} for {@link #SENSOR_TYPE_CAR_SPEED} and 316 * {@link #SENSOR_TYPE_WHEEL_TICK_DISTANCE}, {@link Car#PERMISSION_MILEAGE} for 317 * {@link #SENSOR_TYPE_ODOMETER}, {@link Car#PERMISSION_FUEL} for 318 * {@link #SENSOR_TYPE_FUEL_LEVEL}, or {@link Car#PERMISSION_VEHICLE_DYNAMICS_STATE} for 319 * {@link #SENSOR_TYPE_ABS_ACTIVE} and {@link #SENSOR_TYPE_TRACTION_CONTROL_ACTIVE} 320 * 321 * @param listener 322 * @param sensorType sensor type to subscribe. 323 * @param rate how fast the sensor events are delivered. It should be one of 324 * {@link #SENSOR_RATE_FASTEST}, {@link #SENSOR_RATE_FAST}, {@link #SENSOR_RATE_UI}, 325 * {@link #SENSOR_RATE_NORMAL}. Rate may not be respected especially when the same sensor 326 * is registered with different listener with different rates. Also, rate might be 327 * ignored when vehicle property raises events only when the value is actually changed, 328 * for example {@link #SENSOR_TYPE_PARKING_BRAKE} will raise an event only when parking 329 * brake was engaged or disengaged. 330 * @return if the sensor was successfully enabled. 331 * @throws CarNotConnectedException if the connection to the car service has been lost. 332 * @throws IllegalArgumentException for wrong argument like wrong rate 333 * @throws SecurityException if missing the appropriate permission 334 */ 335 @RequiresPermission(anyOf={Manifest.permission.ACCESS_FINE_LOCATION, Car.PERMISSION_SPEED, 336 Car.PERMISSION_MILEAGE, Car.PERMISSION_FUEL, Car.PERMISSION_VEHICLE_DYNAMICS_STATE}, 337 conditional=true) 338 public boolean registerListener(OnSensorChangedListener listener, @SensorType int sensorType, 339 @SensorRate int rate) throws CarNotConnectedException, IllegalArgumentException { 340 assertSensorType(sensorType); 341 if (rate != SENSOR_RATE_FASTEST && rate != SENSOR_RATE_NORMAL 342 && rate != SENSOR_RATE_UI && rate != SENSOR_RATE_FAST) { 343 throw new IllegalArgumentException("wrong rate " + rate); 344 } 345 synchronized(mActiveSensorListeners) { 346 if (mCarSensorEventListenerToService == null) { 347 mCarSensorEventListenerToService = new CarSensorEventListenerToService(this); 348 } 349 boolean needsServerUpdate = false; 350 CarSensorListeners listeners; 351 listeners = mActiveSensorListeners.get(sensorType); 352 if (listeners == null) { 353 listeners = new CarSensorListeners(rate); 354 mActiveSensorListeners.put(sensorType, listeners); 355 needsServerUpdate = true; 356 } 357 if (listeners.addAndUpdateRate(listener, rate)) { 358 needsServerUpdate = true; 359 } 360 if (needsServerUpdate) { 361 if (!registerOrUpdateSensorListener(sensorType, rate)) { 362 return false; 363 } 364 } 365 } 366 return true; 367 } 368 369 /** 370 * Stop getting sensor update for the given listener. If there are multiple registrations for 371 * this listener, all listening will be stopped. 372 * @param listener 373 */ 374 public void unregisterListener(OnSensorChangedListener listener) { 375 //TODO: removing listener should reset update rate, bug: 32060307 376 synchronized(mActiveSensorListeners) { 377 for (int i = 0; i < mActiveSensorListeners.size(); i++) { 378 doUnregisterListenerLocked(listener, mActiveSensorListeners.keyAt(i)); 379 } 380 } 381 } 382 383 /** 384 * Stop getting sensor update for the given listener and sensor. If the same listener is used 385 * for other sensors, those subscriptions will not be affected. 386 * @param listener 387 * @param sensorType 388 */ 389 public void unregisterListener(OnSensorChangedListener listener, @SensorType int sensorType) { 390 synchronized(mActiveSensorListeners) { 391 doUnregisterListenerLocked(listener, sensorType); 392 } 393 } 394 395 private void doUnregisterListenerLocked(OnSensorChangedListener listener, Integer sensor) { 396 CarSensorListeners listeners = mActiveSensorListeners.get(sensor); 397 if (listeners != null) { 398 boolean needsServerUpdate = false; 399 if (listeners.contains(listener)) { 400 needsServerUpdate = listeners.remove(listener); 401 } 402 if (listeners.isEmpty()) { 403 try { 404 mService.unregisterSensorListener(sensor.intValue(), 405 mCarSensorEventListenerToService); 406 } catch (RemoteException e) { 407 //ignore 408 } 409 mActiveSensorListeners.remove(sensor); 410 } else if (needsServerUpdate) { 411 try { 412 registerOrUpdateSensorListener(sensor, listeners.getRate()); 413 } catch (CarNotConnectedException e) { 414 // ignore 415 } 416 } 417 } 418 } 419 420 private boolean registerOrUpdateSensorListener(int sensor, int rate) 421 throws CarNotConnectedException { 422 try { 423 if (!mService.registerOrUpdateSensorListener(sensor, rate, 424 mCarSensorEventListenerToService)) { 425 return false; 426 } 427 } catch (IllegalStateException e) { 428 CarApiUtil.checkCarNotConnectedExceptionFromCarService(e); 429 } catch (RemoteException e) { 430 throw new CarNotConnectedException(e); 431 } 432 return true; 433 } 434 435 /** 436 * Get the most recent CarSensorEvent for the given type. Note that latest sensor data from car 437 * will not be available if it was never subscribed before. This call will return immediately 438 * with null if there is no data available. 439 * @param type A sensor to request 440 * @return null if there was no sensor update since connected to the car. 441 * @throws CarNotConnectedException if the connection to the car service has been lost. 442 */ 443 public CarSensorEvent getLatestSensorEvent(@SensorType int type) 444 throws CarNotConnectedException { 445 assertSensorType(type); 446 try { 447 return mService.getLatestSensorEvent(type); 448 } catch (IllegalStateException e) { 449 CarApiUtil.checkCarNotConnectedExceptionFromCarService(e); 450 } catch(RemoteException e) { 451 handleCarServiceRemoteExceptionAndThrow(e); 452 } 453 return null; 454 } 455 456 private void handleCarServiceRemoteExceptionAndThrow(RemoteException e) 457 throws CarNotConnectedException { 458 if (Log.isLoggable(CarLibLog.TAG_SENSOR, Log.INFO)) { 459 Log.i(CarLibLog.TAG_SENSOR, "RemoteException from car service:" + e.getMessage()); 460 } 461 throw new CarNotConnectedException(); 462 } 463 464 private void assertSensorType(int sensorType) { 465 if (sensorType == 0 || !((sensorType <= SENSOR_TYPE_MAX) || 466 ((sensorType >= SENSOR_TYPE_VENDOR_EXTENSION_START) && 467 (sensorType <= SENSOR_TYPE_VENDOR_EXTENSION_END)))) { 468 throw new IllegalArgumentException("invalid sensor type " + sensorType); 469 } 470 } 471 472 private void handleOnSensorChanged(List<CarSensorEvent> events) { 473 mHandlerCallback.sendEvents(events); 474 } 475 476 private static class CarSensorEventListenerToService extends ICarSensorEventListener.Stub { 477 private final WeakReference<CarSensorManager> mManager; 478 479 public CarSensorEventListenerToService(CarSensorManager manager) { 480 mManager = new WeakReference<>(manager); 481 } 482 483 @Override 484 public void onSensorChanged(List<CarSensorEvent> events) { 485 CarSensorManager manager = mManager.get(); 486 if (manager != null) { 487 manager.handleOnSensorChanged(events); 488 } 489 } 490 } 491 492 private class CarSensorListeners extends CarRatedListeners<OnSensorChangedListener> { 493 CarSensorListeners(int rate) { 494 super(rate); 495 } 496 497 void onSensorChanged(final CarSensorEvent event) { 498 // throw away old sensor data as oneway binder call can change order. 499 long updateTime = event.timestamp; 500 if (updateTime < mLastUpdateTime) { 501 Log.w(CarLibLog.TAG_SENSOR, "dropping old sensor data"); 502 return; 503 } 504 mLastUpdateTime = updateTime; 505 List<OnSensorChangedListener> listeners; 506 synchronized (mActiveSensorListeners) { 507 listeners = new ArrayList<>(getListeners()); 508 } 509 listeners.forEach(new Consumer<OnSensorChangedListener>() { 510 @Override 511 public void accept(OnSensorChangedListener listener) { 512 listener.onSensorChanged(event); 513 } 514 }); 515 } 516 } 517 518 /** 519 * Get the config data for the given type. 520 * 521 * A CarSensorConfig object is returned for every sensor type. However, if there is no 522 * config, the data will be empty. 523 * 524 * @param sensor type to request 525 * @return CarSensorConfig object 526 * @throws CarNotConnectedException if the connection to the car service has been lost. 527 * @hide 528 */ 529 public CarSensorConfig getSensorConfig(@SensorType int type) 530 throws CarNotConnectedException { 531 assertSensorType(type); 532 try { 533 return mService.getSensorConfig(type); 534 } catch (IllegalStateException e) { 535 CarApiUtil.checkCarNotConnectedExceptionFromCarService(e); 536 } catch(RemoteException e) { 537 handleCarServiceRemoteExceptionAndThrow(e); 538 } 539 return new CarSensorConfig(0, Bundle.EMPTY); 540 } 541 } 542