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