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. */
onSensorServiceReady()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          */
dispatchCarSensorEvent(SensorListener listener, CarSensorEvent event)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 
CarSensorService(Context context, SensorHalService sensorHal)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
init()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 
getInitialIgnitionState()163     private CarSensorEvent getInitialIgnitionState() {
164         return mSensorHal.getCurrentSensorValue(CarSensorManager.SENSOR_TYPE_IGNITION_STATE);
165     }
166 
getInitialNightMode()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 
getInitialDrivingStatus()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 
addNewSensorRecordLocked(int type, CarSensorEvent event)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
release()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 
tryHoldSensorLock()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 
releaseSensorLockSafely()246     private void releaseSensorLockSafely() {
247         if (mSensorLock.isHeldByCurrentThread()) {
248             mSensorLock.unlock();
249         }
250     }
251 
notifyDefaultPoliciesLocked()252     private void notifyDefaultPoliciesLocked() {
253         if (mUseDefaultDrivingPolicy) {
254             mDrivingStatePolicy.onSensorServiceReady();
255         }
256         if (mUseDefaultDayNightModePolicy) {
257             mDayNightModePolicy.onSensorServiceReady();
258         }
259     }
260 
processSensorData(List<CarSensorEvent> events)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
onSensorEvents(List<CarSensorEvent> events)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
getSupportedSensors()317     public int[] getSupportedSensors() {
318         mSensorLock.lock();
319         int[] supportedSensors = mSupportedSensors;
320         mSensorLock.unlock();
321         return supportedSensors;
322     }
323 
324     @Override
registerOrUpdateSensorListener(int sensorType, int rate, ICarSensorEventListener listener)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 
sensorSupportRate(int sensorType)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 
getSensorPermission(int sensorType)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
getPermissionName(int sensorType)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 
startSensor(SensorRecord record, int sensorType, int rate)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
unregisterSensorListener(int sensorType, ICarSensorEventListener listener)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 
stopSensor(SensorRecord record, int sensorType)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 
getSensorHal(int sensorType)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
getLatestSensorEvent(int sensorType)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 
refreshSupportedSensorsLocked()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 
isSensorRealLocked(int sensorType)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      */
findSensorClientLocked(ICarSensorEventListener listener)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 
removeClient(SensorClient sensorClient)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 
SensorDispatchHandler(Looper looper)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 
handleSensorEvents(List<CarSensorEvent> data)719         private synchronized void handleSensorEvents(List<CarSensorEvent> data) {
720             LinkedList<CarSensorEvent> list = mSensorDataList[mFreeListIndex];
721             list.addAll(data);
722             requestDispatchLocked();
723         }
724 
handleSensorEvent(CarSensorEvent event)725         private synchronized void handleSensorEvent(CarSensorEvent event) {
726             LinkedList<CarSensorEvent> list = mSensorDataList[mFreeListIndex];
727             list.add(event);
728             requestDispatchLocked();
729         }
730 
requestDispatchLocked()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
handleMessage(Message msg)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 
doHandleSensorData()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 
SensorClient(ICarSensorEventListener listener)790         SensorClient(ICarSensorEventListener listener) {
791             this.mListener = listener;
792         }
793 
794         @Override
equals(Object o)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 
isHoldingListenerBinder(IBinder listenerBinder)803         boolean isHoldingListenerBinder(IBinder listenerBinder) {
804             return mListener.asBinder() == listenerBinder;
805         }
806 
addSensor(int sensor)807         void addSensor(int sensor) {
808             mActiveSensors.put(sensor, true);
809         }
810 
removeSensor(int sensor)811         void removeSensor(int sensor) {
812             mActiveSensors.delete(sensor);
813         }
814 
getNumberOfActiveSensor()815         int getNumberOfActiveSensor() {
816             return mActiveSensors.size();
817         }
818 
getSensorArray()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 
getICarSensorEventListener()827         ICarSensorEventListener getICarSensorEventListener() {
828             return mListener;
829         }
830 
831         /**
832          * Client dead. should remove all sensor requests from client
833          */
834         @Override
binderDied()835         public void binderDied() {
836             mListener.asBinder().unlinkToDeath(this, 0);
837             removeClient(this);
838         }
839 
dispatchSensorUpdate(List<CarSensorEvent> events)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
release()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
dump(PrintWriter writer)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