Home | History | Annotate | Download | only in car
      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 com.android.car;
     18 
     19 import android.car.Car;
     20 import android.car.hardware.CarSensorEvent;
     21 import android.car.hardware.CarSensorManager;
     22 import android.car.hardware.ICarSensor;
     23 import android.car.hardware.ICarSensorEventListener;
     24 import android.content.Context;
     25 import android.content.pm.PackageManager;
     26 import android.os.Binder;
     27 import android.os.Handler;
     28 import android.os.HandlerThread;
     29 import android.os.IBinder;
     30 import android.os.Looper;
     31 import android.os.Message;
     32 import android.os.Process;
     33 import android.os.RemoteException;
     34 import android.os.SystemClock;
     35 import android.util.ArrayMap;
     36 import android.util.Log;
     37 import android.util.SparseArray;
     38 import android.util.SparseBooleanArray;
     39 
     40 import static com.android.car.Listeners.ClientWithRate;
     41 import com.android.car.hal.SensorBase;
     42 import com.android.car.hal.SensorHalService.SensorListener;
     43 import com.google.android.collect.Lists;
     44 
     45 import com.android.car.hal.SensorHalService;
     46 import com.android.car.hal.SensorHalServiceBase;
     47 import com.android.internal.annotations.GuardedBy;
     48 
     49 import java.io.PrintWriter;
     50 import java.util.Arrays;
     51 import java.util.ConcurrentModificationException;
     52 import java.util.LinkedList;
     53 import java.util.List;
     54 import java.util.concurrent.TimeUnit;
     55 import java.util.concurrent.atomic.AtomicBoolean;
     56 import java.util.concurrent.locks.ReentrantLock;
     57 
     58 
     59 public class CarSensorService extends ICarSensor.Stub
     60         implements CarServiceBase, SensorHalService.SensorListener {
     61 
     62     /**
     63      * Abstraction for logical sensor which is not physical sensor but presented as sensor to
     64      * upper layer. Currently {@link CarSensorManager#SENSOR_TYPE_NIGHT} and
     65      * {@link CarSensorManager#SENSOR_TYPE_DRIVING_STATUS} falls into this category.
     66      * Implementation can call {@link CarSensorService#onSensorData(CarSensorEvent)} when there
     67      * is state change for the given sensor after {@link SensorHalServiceBase#init()}
     68      * is called.
     69      */
     70     public static abstract class LogicalSensor implements SensorBase {
     71         private final LinkedList<CarSensorEvent> mDispatchQ = new LinkedList<>();
     72 
     73         /** Sensor service is ready and all vehicle sensors are available. */
     74         public abstract void onSensorServiceReady();
     75 
     76         /**
     77          * Utility to help service to send one event as listener only takes list form.
     78          * @param listener
     79          * @param event
     80          */
     81         protected void dispatchCarSensorEvent(SensorListener listener, CarSensorEvent event) {
     82             synchronized (mDispatchQ) {
     83                 mDispatchQ.add(event);
     84                 listener.onSensorEvents(mDispatchQ);
     85                 mDispatchQ.clear();
     86             }
     87         }
     88     }
     89 
     90     /**
     91      * When set, sensor service sets its own dispatching rate limit.
     92      * VehicleNetworkService is already doing this, so not necessary to set it for now.
     93      */
     94     private static final boolean ENABLE_DISPATCHING_LIMIT = false;
     95 
     96     /** {@link #mSensorLock} is not waited forever for handling disconnection */
     97     private static final long MAX_SENSOR_LOCK_WAIT_MS = 1000;
     98 
     99     /** lock to access sensor structures */
    100     private final ReentrantLock mSensorLock = new ReentrantLock();
    101     /** hold clients callback  */
    102     @GuardedBy("mSensorLock")
    103     private final LinkedList<SensorClient> mClients = new LinkedList<>();
    104 
    105     /** key: sensor type. */
    106     @GuardedBy("mSensorLock")
    107     private final SparseArray<Listeners<SensorClient>> mSensorListeners = new SparseArray<>();
    108     /** key: sensor type. */
    109     @GuardedBy("mSensorLock")
    110     private final SparseArray<SensorRecord> mSensorRecords = new SparseArray<>();
    111 
    112     private final SensorHalService mSensorHal;
    113     private int[] mCarProvidedSensors;
    114     private int[] mSupportedSensors;
    115     private final AtomicBoolean mSensorDiscovered = new AtomicBoolean(false);
    116 
    117     private final Context mContext;
    118 
    119     private final DrivingStatePolicy mDrivingStatePolicy;
    120     private boolean mUseDefaultDrivingPolicy = true;
    121     private final DayNightModePolicy mDayNightModePolicy;
    122     private boolean mUseDefaultDayNightModePolicy = true;
    123 
    124     private final HandlerThread mHandlerThread;
    125     private final SensorDispatchHandler mSensorDispatchHandler;
    126 
    127     public CarSensorService(Context context, SensorHalService sensorHal) {
    128         mContext = context;
    129         if (ENABLE_DISPATCHING_LIMIT) {
    130             mHandlerThread = new HandlerThread("SENSOR", Process.THREAD_PRIORITY_AUDIO);
    131             mHandlerThread.start();
    132             mSensorDispatchHandler = new SensorDispatchHandler(mHandlerThread.getLooper());
    133         } else {
    134             mHandlerThread = null;
    135             mSensorDispatchHandler = null;
    136         }
    137         // This triggers sensor hal init as well.
    138         mSensorHal = sensorHal;
    139         mDrivingStatePolicy = new DrivingStatePolicy(context, this);
    140         mDayNightModePolicy = new DayNightModePolicy(context);
    141     }
    142 
    143     @Override
    144     public void init() {
    145         mSensorLock.lock();
    146         try {
    147             mSensorHal.registerSensorListener(this);
    148             mCarProvidedSensors = mSensorHal.getSupportedSensors();
    149             mSupportedSensors = refreshSupportedSensorsLocked();
    150 
    151             addNewSensorRecordLocked(CarSensorManager.SENSOR_TYPE_DRIVING_STATUS,
    152                     getInitialDrivingStatus());
    153             addNewSensorRecordLocked(CarSensorManager.SENSOR_TYPE_NIGHT, getInitialNightMode());
    154             addNewSensorRecordLocked(CarSensorManager.SENSOR_TYPE_IGNITION_STATE,
    155                 getInitialIgnitionState());
    156 
    157             notifyDefaultPoliciesLocked();
    158         } finally {
    159             mSensorLock.unlock();
    160         }
    161     }
    162 
    163     private CarSensorEvent getInitialIgnitionState() {
    164         return mSensorHal.getCurrentSensorValue(CarSensorManager.SENSOR_TYPE_IGNITION_STATE);
    165     }
    166 
    167     private CarSensorEvent getInitialNightMode() {
    168         CarSensorEvent event = null;
    169         if (mUseDefaultDayNightModePolicy) {
    170             mDayNightModePolicy.init();
    171             mDayNightModePolicy.registerSensorListener(this);
    172         } else {
    173             event = mSensorHal.getCurrentSensorValue(CarSensorManager.SENSOR_TYPE_NIGHT);
    174             Log.i(CarLog.TAG_SENSOR, "initial daynight: "
    175                     + ((event == null) ? "not ready" : + event.intValues[0]));
    176         }
    177         if (event == null) {
    178             event = DayNightModePolicy.getDefaultValue(CarSensorManager.SENSOR_TYPE_NIGHT);
    179             if (!mUseDefaultDayNightModePolicy) {
    180                 Log.w(CarLog.TAG_SENSOR, "Default daynight set as sensor not ready");
    181             }
    182         }
    183         return event;
    184     }
    185 
    186     private CarSensorEvent getInitialDrivingStatus() {
    187         CarSensorEvent event = null;
    188         if (mUseDefaultDrivingPolicy) {
    189             mDrivingStatePolicy.init();
    190             mDrivingStatePolicy.registerSensorListener(this);
    191         } else {
    192             event = mSensorHal.getCurrentSensorValue(
    193                     CarSensorManager.SENSOR_TYPE_DRIVING_STATUS);
    194             Log.i(CarLog.TAG_SENSOR, "initial driving status:" + ((event == null)?
    195                     "not ready" : " 0x" + Integer.toHexString(event.intValues[0])));
    196         }
    197         if (event == null) {
    198             event = DrivingStatePolicy.getDefaultValue(
    199                     CarSensorManager.SENSOR_TYPE_DRIVING_STATUS);
    200             if (!mUseDefaultDrivingPolicy) {
    201                 Log.w(CarLog.TAG_SENSOR, "Default driving status set as sensor not ready");
    202             }
    203         }
    204         return event;
    205     }
    206 
    207     private void addNewSensorRecordLocked(int type, CarSensorEvent event) {
    208         SensorRecord record = new SensorRecord();
    209         record.lastEvent = event;
    210         mSensorRecords.put(type,record);
    211     }
    212 
    213     @Override
    214     public void release() {
    215         if (mHandlerThread != null) {
    216             mHandlerThread.quit();
    217         }
    218         tryHoldSensorLock();
    219         try {
    220             if (mUseDefaultDrivingPolicy) {
    221                 mDrivingStatePolicy.release();
    222             }
    223             if (mUseDefaultDayNightModePolicy) {
    224                 mDayNightModePolicy.release();
    225             }
    226             for (int i = mSensorListeners.size() - 1; i >= 0; --i) {
    227                 Listeners listener = mSensorListeners.valueAt(i);
    228                 listener.release();
    229             }
    230             mSensorListeners.clear();
    231             mSensorRecords.clear();
    232             mClients.clear();
    233         } finally {
    234             releaseSensorLockSafely();
    235         }
    236     }
    237 
    238     private void tryHoldSensorLock() {
    239         try {
    240             mSensorLock.tryLock(MAX_SENSOR_LOCK_WAIT_MS, TimeUnit.MILLISECONDS);
    241         } catch (InterruptedException e) {
    242             //ignore
    243         }
    244     }
    245 
    246     private void releaseSensorLockSafely() {
    247         if (mSensorLock.isHeldByCurrentThread()) {
    248             mSensorLock.unlock();
    249         }
    250     }
    251 
    252     private void notifyDefaultPoliciesLocked() {
    253         if (mUseDefaultDrivingPolicy) {
    254             mDrivingStatePolicy.onSensorServiceReady();
    255         }
    256         if (mUseDefaultDayNightModePolicy) {
    257             mDayNightModePolicy.onSensorServiceReady();
    258         }
    259     }
    260 
    261     private void processSensorData(List<CarSensorEvent> events) {
    262         ArrayMap<SensorClient, List<CarSensorEvent>> eventsByClient = new ArrayMap<>();
    263 
    264         mSensorLock.lock();
    265         for (CarSensorEvent event: events) {
    266             SensorRecord record = mSensorRecords.get(event.sensorType);
    267             if (record != null) {
    268                 if (record.lastEvent == null) {
    269                     record.lastEvent = event;
    270                 } else if (record.lastEvent.timestamp < event.timestamp) {
    271                     record.lastEvent = event;
    272                     //TODO recycle event, bug: 32094595
    273                 } else { // wrong timestamp, throw away this.
    274                     //TODO recycle new event, bug: 32094595
    275                     continue;
    276                 }
    277 
    278                 Listeners<SensorClient> listeners = mSensorListeners.get(event.sensorType);
    279                 if (listeners == null) {
    280                     continue;
    281                 }
    282 
    283                 for (ClientWithRate<SensorClient> clientWithRate : listeners.getClients()) {
    284                     SensorClient client = clientWithRate.getClient();
    285                     List<CarSensorEvent> clientEvents = eventsByClient.get(client);
    286                     if (clientEvents == null) {
    287                         clientEvents = new LinkedList<>();
    288                         eventsByClient.put(client, clientEvents);
    289                     }
    290                     clientEvents.add(event);
    291                 }
    292             }
    293         }
    294         mSensorLock.unlock();
    295 
    296         for (ArrayMap.Entry<SensorClient, List<CarSensorEvent>> entry : eventsByClient.entrySet()) {
    297             SensorClient client = entry.getKey();
    298             List<CarSensorEvent> clientEvents = entry.getValue();
    299 
    300             client.dispatchSensorUpdate(clientEvents);
    301         }
    302     }
    303 
    304     /**
    305      * Received sensor data from car.
    306      */
    307     @Override
    308     public void onSensorEvents(List<CarSensorEvent> events) {
    309         if (ENABLE_DISPATCHING_LIMIT) {
    310             mSensorDispatchHandler.handleSensorEvents(events);
    311         } else {
    312             processSensorData(events);
    313         }
    314     }
    315 
    316     @Override
    317     public int[] getSupportedSensors() {
    318         mSensorLock.lock();
    319         int[] supportedSensors = mSupportedSensors;
    320         mSensorLock.unlock();
    321         return supportedSensors;
    322     }
    323 
    324     @Override
    325     public boolean registerOrUpdateSensorListener(int sensorType, int rate,
    326             ICarSensorEventListener listener) {
    327         boolean shouldStartSensors = false;
    328         SensorRecord sensorRecord = null;
    329         SensorClient sensorClient = null;
    330         Integer oldRate = null;
    331         Listeners<SensorClient> sensorListeners = null;
    332         mSensorLock.lock();
    333         try {
    334             sensorRecord = mSensorRecords.get(sensorType);
    335             if (sensorRecord == null) {
    336                 if (Log.isLoggable(CarLog.TAG_SENSOR, Log.INFO)) {
    337                     Log.i(CarLog.TAG_SENSOR, "Requested sensor " + sensorType + " not supported");
    338                 }
    339                 return false;
    340             }
    341             if (Binder.getCallingUid() != Process.myUid()) {
    342                 switch (getSensorPermission(sensorType)) {
    343                     case PackageManager.PERMISSION_DENIED:
    344                         throw new SecurityException("client does not have permission:"
    345                                 + getPermissionName(sensorType)
    346                                 + " pid:" + Binder.getCallingPid()
    347                                 + " uid:" + Binder.getCallingUid());
    348                     case PackageManager.PERMISSION_GRANTED:
    349                         break;
    350                 }
    351             }
    352             if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
    353                 Log.d(CarLog.TAG_SENSOR, "registerOrUpdateSensorListener " + sensorType + " " +
    354                         listener);
    355             }
    356             sensorClient = findSensorClientLocked(listener);
    357             ClientWithRate<SensorClient> sensorClientWithRate = null;
    358             sensorListeners = mSensorListeners.get(sensorType);
    359             if (sensorClient == null) {
    360                 sensorClient = new SensorClient(listener);
    361                 try {
    362                     listener.asBinder().linkToDeath(sensorClient, 0);
    363                 } catch (RemoteException e) {
    364                     if (Log.isLoggable(CarLog.TAG_SENSOR, Log.INFO)) {
    365                         Log.i(CarLog.TAG_SENSOR, "Adding listener failed.");
    366                     }
    367                     return false;
    368                 }
    369                 mClients.add(sensorClient);
    370             }
    371             // If we have a cached event for this sensor, send the event.
    372             SensorRecord record = mSensorRecords.get(sensorType);
    373             if (record != null && record.lastEvent != null) {
    374                 sensorClient.dispatchSensorUpdate(Lists.newArrayList(record.lastEvent));
    375             }
    376             if (sensorListeners == null) {
    377                 sensorListeners = new Listeners<>(rate);
    378                 mSensorListeners.put(sensorType, sensorListeners);
    379                 shouldStartSensors = true;
    380             } else {
    381                 oldRate = sensorListeners.getRate();
    382                 sensorClientWithRate = sensorListeners.findClientWithRate(sensorClient);
    383             }
    384             if (sensorClientWithRate == null) {
    385                 sensorClientWithRate = new ClientWithRate<>(sensorClient, rate);
    386                 sensorListeners.addClientWithRate(sensorClientWithRate);
    387             } else {
    388                 sensorClientWithRate.setRate(rate);
    389             }
    390             if (sensorListeners.getRate() > rate) {
    391                 sensorListeners.setRate(rate);
    392                 shouldStartSensors = sensorSupportRate(sensorType);
    393             }
    394             sensorClient.addSensor(sensorType);
    395         } finally {
    396             mSensorLock.unlock();
    397         }
    398         // start sensor outside lock as it can take time.
    399         if (shouldStartSensors) {
    400             if (!startSensor(sensorRecord, sensorType, rate)) {
    401                 // failed. so remove from active sensor list.
    402                 mSensorLock.lock();
    403                 try {
    404                     sensorClient.removeSensor(sensorType);
    405                     if (oldRate != null) {
    406                         sensorListeners.setRate(oldRate);
    407                     } else {
    408                         mSensorListeners.remove(sensorType);
    409                     }
    410                 } finally {
    411                     mSensorLock.unlock();
    412                 }
    413                 return false;
    414             }
    415         }
    416         return true;
    417     }
    418 
    419     private boolean sensorSupportRate(int sensorType) {
    420         switch (sensorType) {
    421             case CarSensorManager.SENSOR_TYPE_CAR_SPEED:
    422             case CarSensorManager.SENSOR_TYPE_RPM:
    423                 return true;
    424             case CarSensorManager.SENSOR_TYPE_ODOMETER:
    425             case CarSensorManager.SENSOR_TYPE_FUEL_LEVEL:
    426             case CarSensorManager.SENSOR_TYPE_PARKING_BRAKE:
    427             case CarSensorManager.SENSOR_TYPE_GEAR:
    428             case CarSensorManager.SENSOR_TYPE_NIGHT:
    429             case CarSensorManager.SENSOR_TYPE_DRIVING_STATUS:
    430             case CarSensorManager.SENSOR_TYPE_ENVIRONMENT:
    431                 return false;
    432             default:
    433                 Log.w(CarLog.TAG_SENSOR, "sensorSupportRate not listed sensor:" + sensorType);
    434                 return false;
    435         }
    436     }
    437 
    438     private int getSensorPermission(int sensorType) {
    439         String permission = getPermissionName(sensorType);
    440         int result = PackageManager.PERMISSION_GRANTED;
    441         if (permission != null) {
    442             return mContext.checkCallingOrSelfPermission(permission);
    443         }
    444         // If no permission is required, return granted.
    445         return result;
    446     }
    447 
    448     //TODO handle per property OEM permission. bug: 32094983
    449     private String getPermissionName(int sensorType) {
    450         if ((sensorType >= CarSensorManager.SENSOR_TYPE_VENDOR_EXTENSION_START) &&
    451                 (sensorType >= CarSensorManager.SENSOR_TYPE_VENDOR_EXTENSION_END)) {
    452             return Car.PERMISSION_VENDOR_EXTENSION;
    453         }
    454         String permission = null;
    455         switch (sensorType) {
    456             case CarSensorManager.SENSOR_TYPE_CAR_SPEED:
    457                 permission = Car.PERMISSION_SPEED;
    458                 break;
    459             case CarSensorManager.SENSOR_TYPE_ODOMETER:
    460                 permission = Car.PERMISSION_MILEAGE;
    461                 break;
    462             case CarSensorManager.SENSOR_TYPE_FUEL_LEVEL:
    463                 permission = Car.PERMISSION_FUEL;
    464                 break;
    465             default:
    466                 break;
    467         }
    468         return permission;
    469     }
    470 
    471     private boolean startSensor(SensorRecord record, int sensorType, int rate) {
    472         //TODO handle sensor rate properly. bug: 32095903
    473         //Some sensors which report only when there is change should be always set with maximum
    474         //rate. For now, set every sensor to the maximum.
    475         if (Log.isLoggable(CarLog.TAG_SENSOR, Log.VERBOSE)) {
    476             Log.v(CarLog.TAG_SENSOR, "startSensor " + sensorType + " with rate " + rate);
    477         }
    478         SensorBase sensorHal = getSensorHal(sensorType);
    479         if (sensorHal != null) {
    480             if (!sensorHal.isReady()) {
    481                 Log.w(CarLog.TAG_SENSOR, "Sensor channel not available.");
    482                 return false;
    483             }
    484             if (record.enabled) {
    485                 return true;
    486             }
    487             if (sensorHal.requestSensorStart(sensorType, 0)) {
    488                 record.enabled = true;
    489                 return true;
    490             }
    491         }
    492         Log.w(CarLog.TAG_SENSOR, "requestSensorStart failed, sensor type:" + sensorType);
    493         return false;
    494     }
    495 
    496     @Override
    497     public void unregisterSensorListener(int sensorType, ICarSensorEventListener listener) {
    498         boolean shouldStopSensor = false;
    499         boolean shouldRestartSensor = false;
    500         SensorRecord record = null;
    501         int newRate = 0;
    502         mSensorLock.lock();
    503         try {
    504             record = mSensorRecords.get(sensorType);
    505             if (record == null) {
    506                 // unregister not supported sensor. ignore.
    507                 if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
    508                     Log.d(CarLog.TAG_SENSOR, "unregister for unsupported sensor");
    509                 }
    510                 return;
    511             }
    512             SensorClient sensorClient = findSensorClientLocked(listener);
    513             if (sensorClient == null) {
    514                 // never registered or already unregistered.
    515                 if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
    516                     Log.d(CarLog.TAG_SENSOR, "unregister for not existing client");
    517                 }
    518                 return;
    519             }
    520             sensorClient.removeSensor(sensorType);
    521             if (sensorClient.getNumberOfActiveSensor() == 0) {
    522                 sensorClient.release();
    523                 mClients.remove(sensorClient);
    524             }
    525             Listeners<SensorClient> sensorListeners = mSensorListeners.get(sensorType);
    526             if (sensorListeners == null) {
    527                 // sensor not active
    528                 if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
    529                     Log.d(CarLog.TAG_SENSOR, "unregister for non-active sensor");
    530                 }
    531                 return;
    532             }
    533             ClientWithRate<SensorClient> clientWithRate =
    534                     sensorListeners.findClientWithRate(sensorClient);
    535             if (clientWithRate == null) {
    536                 if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
    537                     Log.d(CarLog.TAG_SENSOR, "unregister for not registered sensor");
    538                 }
    539                 return;
    540             }
    541             sensorListeners.removeClientWithRate(clientWithRate);
    542             if (sensorListeners.getNumberOfClients() == 0) {
    543                 shouldStopSensor = true;
    544                 mSensorListeners.remove(sensorType);
    545             } else if (sensorListeners.updateRate()) { // rate changed
    546                 newRate = sensorListeners.getRate();
    547                 shouldRestartSensor = sensorSupportRate(sensorType);
    548             }
    549             if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
    550                 Log.d(CarLog.TAG_SENSOR, "unregister succeeded");
    551             }
    552         } finally {
    553             mSensorLock.unlock();
    554         }
    555         if (shouldStopSensor) {
    556             stopSensor(record, sensorType);
    557         } else if (shouldRestartSensor) {
    558             startSensor(record, sensorType, newRate);
    559         }
    560     }
    561 
    562     private void stopSensor(SensorRecord record, int sensorType) {
    563         if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
    564             Log.d(CarLog.TAG_SENSOR, "stopSensor " + sensorType);
    565         }
    566         SensorBase sensorHal = getSensorHal(sensorType);
    567         if (sensorHal == null || !sensorHal.isReady()) {
    568             Log.w(CarLog.TAG_SENSOR, "Sensor channel not available.");
    569             return;
    570         }
    571         if (!record.enabled) {
    572             return;
    573         }
    574         record.enabled = false;
    575         // make lastEvent invalid as old data can be sent to client when subscription is restarted
    576         // later.
    577         record.lastEvent = null;
    578         if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
    579             Log.d(CarLog.TAG_SENSOR, "stopSensor requestStop " + sensorType);
    580         }
    581         sensorHal.requestSensorStop(sensorType);
    582     }
    583 
    584     private SensorBase getSensorHal(int sensorType) {
    585         try {
    586             mSensorLock.lock();
    587             switch (sensorType) {
    588                 case CarSensorManager.SENSOR_TYPE_DRIVING_STATUS:
    589                     if (mUseDefaultDrivingPolicy) {
    590                         return mDrivingStatePolicy;
    591                     }
    592                     break;
    593                 case CarSensorManager.SENSOR_TYPE_NIGHT:
    594                     if (mUseDefaultDayNightModePolicy) {
    595                         return mDayNightModePolicy;
    596                     }
    597                     break;
    598             }
    599             return mSensorHal;
    600         } finally {
    601             mSensorLock.unlock();
    602         }
    603     }
    604 
    605     @Override
    606     public CarSensorEvent getLatestSensorEvent(int sensorType) {
    607         SensorRecord record = null;
    608         mSensorLock.lock();
    609         try {
    610             record = mSensorRecords.get(sensorType);
    611         } finally {
    612             mSensorLock.unlock();
    613         }
    614         if (record != null) {
    615             return record.lastEvent;
    616         }
    617         return null;
    618     }
    619 
    620     private int[] refreshSupportedSensorsLocked() {
    621         int numCarSensors = (mCarProvidedSensors == null) ? 0 : mCarProvidedSensors.length;
    622         for (int i = 0; i < numCarSensors; i++) {
    623             int sensor = mCarProvidedSensors[i];
    624             if (sensor == CarSensorManager.SENSOR_TYPE_DRIVING_STATUS) {
    625                 mUseDefaultDrivingPolicy = false;
    626             } else if (sensor == CarSensorManager.SENSOR_TYPE_NIGHT) {
    627                 mUseDefaultDayNightModePolicy = false;
    628             }
    629         }
    630         int totalNumSensors = numCarSensors;
    631         if (mUseDefaultDrivingPolicy) {
    632             totalNumSensors++;
    633         }
    634         if (mUseDefaultDayNightModePolicy) {
    635             totalNumSensors++;
    636         }
    637         // Two logical sensors are always added.
    638         int[] supportedSensors = new int[totalNumSensors];
    639         int index = 0;
    640         if (mUseDefaultDrivingPolicy) {
    641             supportedSensors[index] = CarSensorManager.SENSOR_TYPE_DRIVING_STATUS;
    642             index++;
    643         }
    644         if (mUseDefaultDayNightModePolicy) {
    645             supportedSensors[index] = CarSensorManager.SENSOR_TYPE_NIGHT;
    646             index++;
    647         }
    648 
    649         for (int i = 0; i < numCarSensors; i++) {
    650             int sensor = mCarProvidedSensors[i];
    651 
    652             if (mSensorRecords.get(sensor) == null) {
    653                 SensorRecord record = new SensorRecord();
    654                 mSensorRecords.put(sensor, record);
    655             }
    656             supportedSensors[index] = sensor;
    657             index++;
    658         }
    659 
    660         return supportedSensors;
    661     }
    662 
    663     private boolean isSensorRealLocked(int sensorType) {
    664         if (mCarProvidedSensors != null) {
    665             for (int sensor : mCarProvidedSensors) {
    666                 if (sensor == sensorType ) {
    667                     return true;
    668                 }
    669             }
    670         }
    671         return false;
    672     }
    673 
    674     /**
    675      * Find SensorClient from client list and return it.
    676      * This should be called with mClients locked.
    677      * @param listener
    678      * @return null if not found.
    679      */
    680     private SensorClient findSensorClientLocked(ICarSensorEventListener listener) {
    681         IBinder binder = listener.asBinder();
    682         for (SensorClient sensorClient : mClients) {
    683             if (sensorClient.isHoldingListenerBinder(binder)) {
    684                 return sensorClient;
    685             }
    686         }
    687         return null;
    688     }
    689 
    690     private void removeClient(SensorClient sensorClient) {
    691         mSensorLock.lock();
    692         try {
    693             for (int sensor: sensorClient.getSensorArray()) {
    694                 unregisterSensorListener(sensor,
    695                         sensorClient.getICarSensorEventListener());
    696             }
    697             mClients.remove(sensorClient);
    698         } finally {
    699             mSensorLock.unlock();
    700         }
    701     }
    702 
    703     private class SensorDispatchHandler extends Handler {
    704         private static final long SENSOR_DISPATCH_MIN_INTERVAL_MS = 16; // over 60Hz
    705 
    706         private static final int MSG_SENSOR_DATA = 0;
    707 
    708         private long mLastSensorDispatchTime = -1;
    709         private int mFreeListIndex = 0;
    710         private final LinkedList<CarSensorEvent>[] mSensorDataList = new LinkedList[2];
    711 
    712         private SensorDispatchHandler(Looper looper) {
    713             super(looper);
    714             for (int i = 0; i < mSensorDataList.length; i++) {
    715                 mSensorDataList[i] = new LinkedList<CarSensorEvent>();
    716             }
    717         }
    718 
    719         private synchronized void handleSensorEvents(List<CarSensorEvent> data) {
    720             LinkedList<CarSensorEvent> list = mSensorDataList[mFreeListIndex];
    721             list.addAll(data);
    722             requestDispatchLocked();
    723         }
    724 
    725         private synchronized void handleSensorEvent(CarSensorEvent event) {
    726             LinkedList<CarSensorEvent> list = mSensorDataList[mFreeListIndex];
    727             list.add(event);
    728             requestDispatchLocked();
    729         }
    730 
    731         private void requestDispatchLocked() {
    732             Message msg = obtainMessage(MSG_SENSOR_DATA);
    733             long now = SystemClock.uptimeMillis();
    734             long delta = now - mLastSensorDispatchTime;
    735             if (delta > SENSOR_DISPATCH_MIN_INTERVAL_MS) {
    736                 sendMessage(msg);
    737             } else {
    738                 sendMessageDelayed(msg, SENSOR_DISPATCH_MIN_INTERVAL_MS - delta);
    739             }
    740         }
    741 
    742         @Override
    743         public void handleMessage(Message msg) {
    744             switch (msg.what) {
    745                 case MSG_SENSOR_DATA:
    746                     doHandleSensorData();
    747                     break;
    748                 default:
    749                     break;
    750             }
    751         }
    752 
    753         private void doHandleSensorData() {
    754             List<CarSensorEvent> listToDispatch = null;
    755             synchronized (this) {
    756                 mLastSensorDispatchTime = SystemClock.uptimeMillis();
    757                 int nonFreeListIndex = mFreeListIndex ^ 0x1;
    758                 List<CarSensorEvent> nonFreeList = mSensorDataList[nonFreeListIndex];
    759                 List<CarSensorEvent> freeList = mSensorDataList[mFreeListIndex];
    760                 if (nonFreeList.size() > 0) {
    761                     Log.w(CarLog.TAG_SENSOR, "non free list not empty");
    762                     // copy again, but this should not be normal case
    763                     nonFreeList.addAll(freeList);
    764                     listToDispatch = nonFreeList;
    765                     freeList.clear();
    766                 } else if (freeList.size() > 0) {
    767                     listToDispatch = freeList;
    768                     mFreeListIndex = nonFreeListIndex;
    769                 }
    770             }
    771             // leave this part outside lock so that time-taking dispatching can be done without
    772             // blocking sensor event notification.
    773             if (listToDispatch != null) {
    774                 processSensorData(listToDispatch);
    775                 listToDispatch.clear();
    776             }
    777         }
    778 
    779     }
    780 
    781     /** internal instance for pending client request */
    782     private class SensorClient implements Listeners.IListener {
    783         /** callback for sensor events */
    784         private final ICarSensorEventListener mListener;
    785         private final SparseBooleanArray mActiveSensors = new SparseBooleanArray();
    786 
    787         /** when false, it is already released */
    788         private volatile boolean mActive = true;
    789 
    790         SensorClient(ICarSensorEventListener listener) {
    791             this.mListener = listener;
    792         }
    793 
    794         @Override
    795         public boolean equals(Object o) {
    796             if (o instanceof SensorClient &&
    797                     mListener.asBinder() == ((SensorClient) o).mListener.asBinder()) {
    798                 return true;
    799             }
    800             return false;
    801         }
    802 
    803         boolean isHoldingListenerBinder(IBinder listenerBinder) {
    804             return mListener.asBinder() == listenerBinder;
    805         }
    806 
    807         void addSensor(int sensor) {
    808             mActiveSensors.put(sensor, true);
    809         }
    810 
    811         void removeSensor(int sensor) {
    812             mActiveSensors.delete(sensor);
    813         }
    814 
    815         int getNumberOfActiveSensor() {
    816             return mActiveSensors.size();
    817         }
    818 
    819         int[] getSensorArray() {
    820             int[] sensors = new int[mActiveSensors.size()];
    821             for (int i = sensors.length - 1; i >= 0; --i) {
    822                 sensors[i] = mActiveSensors.keyAt(i);
    823             }
    824             return sensors;
    825         }
    826 
    827         ICarSensorEventListener getICarSensorEventListener() {
    828             return mListener;
    829         }
    830 
    831         /**
    832          * Client dead. should remove all sensor requests from client
    833          */
    834         @Override
    835         public void binderDied() {
    836             mListener.asBinder().unlinkToDeath(this, 0);
    837             removeClient(this);
    838         }
    839 
    840         void dispatchSensorUpdate(List<CarSensorEvent> events) {
    841             if (events.size() == 0) {
    842                 return;
    843             }
    844             if (mActive) {
    845                 try {
    846                     mListener.onSensorChanged(events);
    847                 } catch (RemoteException e) {
    848                     //ignore. crash will be handled by death handler
    849                 }
    850             } else {
    851                 if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
    852                     Log.d(CarLog.TAG_SENSOR, "sensor update while client is already released");
    853                 }
    854             }
    855         }
    856 
    857         @Override
    858         public void release() {
    859             if (mActive) {
    860                 mListener.asBinder().unlinkToDeath(this, 0);
    861                 mActiveSensors.clear();
    862                 mActive = false;
    863             }
    864         }
    865     }
    866 
    867     private static class SensorRecord {
    868         /** Record the lastly received sensor event */
    869         CarSensorEvent lastEvent = null;
    870         /** sensor was enabled by at least one client */
    871         boolean enabled = false;
    872     }
    873 
    874     @Override
    875     public void dump(PrintWriter writer) {
    876         writer.println("*CarSensorService*");
    877         writer.println("supported sensors:" + Arrays.toString(mSupportedSensors));
    878         writer.println("**last events for sensors**");
    879         if (mSensorRecords != null) {
    880             try {
    881                 int sensorRecordSize = mSensorRecords.size();
    882                 for (int i = 0; i < sensorRecordSize; i++) {
    883                     int sensor = mSensorRecords.keyAt(i);
    884                     SensorRecord record = mSensorRecords.get(sensor);
    885                     if (record != null && record.lastEvent != null) {
    886                         writer.println("sensor: " + sensor
    887                                 + " active: " + record.enabled);
    888                         writer.println(" " + record.lastEvent.toString());
    889                     }
    890                     Listeners listeners = mSensorListeners.get(sensor);
    891                     if (listeners != null) {
    892                         writer.println(" rate: " + listeners.getRate());
    893                     }
    894                 }
    895             } catch (ConcurrentModificationException e) {
    896                 writer.println("concurrent modification happened");
    897             }
    898         } else {
    899             writer.println("null records");
    900         }
    901         writer.println("**clients**");
    902         try {
    903             for (SensorClient client: mClients) {
    904                 if (client != null) {
    905                     try {
    906                         writer.println("binder:" + client.mListener
    907                                 + " active sensors:" + Arrays.toString(client.getSensorArray()));
    908                     } catch (ConcurrentModificationException e) {
    909                         writer.println("concurrent modification happened");
    910                     }
    911                 } else {
    912                     writer.println("null client");
    913                 }
    914             }
    915         } catch  (ConcurrentModificationException e) {
    916             writer.println("concurrent modification happened");
    917         }
    918         writer.println("**sensor listeners**");
    919         try {
    920             int sensorListenerSize = mSensorListeners.size();
    921             for (int i = 0; i < sensorListenerSize; i++) {
    922                 int sensor = mSensorListeners.keyAt(i);
    923                 Listeners sensorListeners = mSensorListeners.get(sensor);
    924                 if (sensorListeners != null) {
    925                     writer.println(" Sensor:" + sensor
    926                             + " num client:" + sensorListeners.getNumberOfClients()
    927                             + " rate:" + sensorListeners.getRate());
    928                 }
    929             }
    930         }  catch  (ConcurrentModificationException e) {
    931             writer.println("concurrent modification happened");
    932         }
    933         writer.println("mUseDefaultDrivingPolicy:" + mUseDefaultDrivingPolicy +
    934                 ",mUseDefaultDayNightModePolicy" + mUseDefaultDayNightModePolicy);
    935         writer.println("**driving policy**");
    936         if (mUseDefaultDrivingPolicy) {
    937             mDrivingStatePolicy.dump(writer);
    938         }
    939         writer.println("**day/night policy**");
    940         if (mUseDefaultDayNightModePolicy) {
    941             mDayNightModePolicy.dump(writer);
    942         }
    943     }
    944 }
    945