• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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. */
onSensorServiceReady()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          */
dispatchCarSensorEvent(SensorListener listener, CarSensorEvent event)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 
CarSensorService(Context context, SensorHalService sensorHal)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
init()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 
getInitialIgnitionState()164     private CarSensorEvent getInitialIgnitionState() {
165         return mSensorHal.getCurrentSensorValue(CarSensorManager.SENSOR_TYPE_IGNITION_STATE);
166     }
167 
getInitialNightMode()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 
getInitialDrivingStatus()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 
addNewSensorRecordLocked(int type, CarSensorEvent event)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
release()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 
tryHoldSensorLock()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 
releaseSensorLockSafely()247     private void releaseSensorLockSafely() {
248         if (mSensorLock.isHeldByCurrentThread()) {
249             mSensorLock.unlock();
250         }
251     }
252 
notifyDefaultPoliciesLocked()253     private void notifyDefaultPoliciesLocked() {
254         if (mUseDefaultDrivingPolicy) {
255             mDrivingStatePolicy.onSensorServiceReady();
256         }
257         if (mUseDefaultDayNightModePolicy) {
258             mDayNightModePolicy.onSensorServiceReady();
259         }
260     }
261 
processSensorData(List<CarSensorEvent> events)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
onSensorEvents(List<CarSensorEvent> events)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
getSupportedSensors()318     public int[] getSupportedSensors() {
319         mSensorLock.lock();
320         int[] supportedSensors = mSupportedSensors;
321         mSensorLock.unlock();
322         return supportedSensors;
323     }
324 
325     @Override
registerOrUpdateSensorListener(int sensorType, int rate, ICarSensorEventListener listener)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 
sensorSupportRate(int sensorType)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 
getSensorPermission(int sensorType)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
getPermissionName(int sensorType)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 
startSensor(SensorRecord record, int sensorType, int rate)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
unregisterSensorListener(int sensorType, ICarSensorEventListener listener)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
getSensorConfig(int sensorType)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 
stopSensor(SensorRecord record, int sensorType)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 
getSensorHal(int sensorType)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
getLatestSensorEvent(int sensorType)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 
refreshSupportedSensorsLocked()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 
isSensorRealLocked(int sensorType)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      */
findSensorClientLocked(ICarSensorEventListener listener)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 
removeClient(SensorClient sensorClient)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 
SensorDispatchHandler(Looper looper)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 
handleSensorEvents(List<CarSensorEvent> data)742         private synchronized void handleSensorEvents(List<CarSensorEvent> data) {
743             LinkedList<CarSensorEvent> list = mSensorDataList[mFreeListIndex];
744             list.addAll(data);
745             requestDispatchLocked();
746         }
747 
handleSensorEvent(CarSensorEvent event)748         private synchronized void handleSensorEvent(CarSensorEvent event) {
749             LinkedList<CarSensorEvent> list = mSensorDataList[mFreeListIndex];
750             list.add(event);
751             requestDispatchLocked();
752         }
753 
requestDispatchLocked()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
handleMessage(Message msg)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 
doHandleSensorData()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 
SensorClient(ICarSensorEventListener listener)813         SensorClient(ICarSensorEventListener listener) {
814             this.mListener = listener;
815         }
816 
817         @Override
equals(Object o)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 
isHoldingListenerBinder(IBinder listenerBinder)826         boolean isHoldingListenerBinder(IBinder listenerBinder) {
827             return mListener.asBinder() == listenerBinder;
828         }
829 
addSensor(int sensor)830         void addSensor(int sensor) {
831             mActiveSensors.put(sensor, true);
832         }
833 
removeSensor(int sensor)834         void removeSensor(int sensor) {
835             mActiveSensors.delete(sensor);
836         }
837 
getNumberOfActiveSensor()838         int getNumberOfActiveSensor() {
839             return mActiveSensors.size();
840         }
841 
getSensorArray()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 
getICarSensorEventListener()850         ICarSensorEventListener getICarSensorEventListener() {
851             return mListener;
852         }
853 
854         /**
855          * Client dead. should remove all sensor requests from client
856          */
857         @Override
binderDied()858         public void binderDied() {
859             mListener.asBinder().unlinkToDeath(this, 0);
860             removeClient(this);
861         }
862 
dispatchSensorUpdate(List<CarSensorEvent> events)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
release()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
dump(PrintWriter writer)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