Home | History | Annotate | Download | only in hardware
      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