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