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
17package com.android.car;
18
19import android.Manifest;
20import android.car.Car;
21import android.car.hardware.CarSensorEvent;
22import android.car.hardware.CarSensorManager;
23import android.car.hardware.ICarSensor;
24import android.car.hardware.ICarSensorEventListener;
25import android.car.hardware.CarSensorManager.CarSensorEventListener;
26import android.content.Context;
27import android.content.pm.PackageManager;
28import android.hardware.SensorEvent;
29import android.os.Binder;
30import android.os.Handler;
31import android.os.HandlerThread;
32import android.os.IBinder;
33import android.os.Looper;
34import android.os.Message;
35import android.os.Process;
36import android.os.RemoteException;
37import android.os.SystemClock;
38import android.util.Log;
39import android.util.SparseArray;
40import android.util.SparseBooleanArray;
41
42import com.android.car.hal.VehicleHal;
43import com.android.car.hal.SensorHalService;
44import com.android.car.hal.SensorHalServiceBase;
45import com.android.car.hal.SensorHalServiceBase.SensorListener;
46import com.android.internal.annotations.GuardedBy;
47
48import java.io.PrintWriter;
49import java.util.Arrays;
50import java.util.ConcurrentModificationException;
51import java.util.HashMap;
52import java.util.LinkedList;
53import java.util.List;
54import java.util.concurrent.TimeUnit;
55import java.util.concurrent.atomic.AtomicBoolean;
56import java.util.concurrent.locks.ReentrantLock;
57
58
59public 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. */
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
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
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
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
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
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
206    private void releaseSensorLockSafely() {
207        if (mSensorLock.isHeldByCurrentThread()) {
208            mSensorLock.unlock();
209        }
210    }
211
212    @Override
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
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
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
276    public int[] getSupportedSensors() {
277        return mSupportedSensors;
278    }
279
280    @Override
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
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
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
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
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
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
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
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
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
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
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     */
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
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
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
676        private synchronized void handleSensorEvents(List<CarSensorEvent> data) {
677            LinkedList<CarSensorEvent> list = mSensorDataList[mFreeListIndex];
678            list.addAll(data);
679            requestDispatchLocked();
680        }
681
682        private synchronized void handleSensorEvent(CarSensorEvent event) {
683            LinkedList<CarSensorEvent> list = mSensorDataList[mFreeListIndex];
684            list.add(event);
685            requestDispatchLocked();
686        }
687
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
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
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
749        SensorClient(ICarSensorEventListener listener) {
750            this.mListener = listener;
751        }
752
753        @Override
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
762        boolean isHoldingListernerBinder(IBinder listenerBinder) {
763            return mListener.asBinder() == listenerBinder;
764        }
765
766        void addSensor(int sensor) {
767            mActiveSensors.put(sensor, true);
768        }
769
770        void removeSensor(int sensor) {
771            mActiveSensors.delete(sensor);
772        }
773
774        int getNumberOfActiveSensor() {
775            return mActiveSensors.size();
776        }
777
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
786        ICarSensorEventListener getICarSensorEventListener() {
787            return mListener;
788        }
789
790        /**
791         * Client dead. should remove all sensor requests from client
792         */
793        @Override
794        public void binderDied() {
795            mListener.asBinder().unlinkToDeath(this, 0);
796            removeClient(this);
797        }
798
799        void queueSensorEvent(CarSensorEvent event) {
800            mSensorsToDispatch.add(event);
801        }
802
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
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
836        SensorClientWithRate(SensorClient client, int rate) {
837            mSensorClient = client;
838            mRate = rate;
839        }
840
841        @Override
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
850        int getRate() {
851            return mRate;
852        }
853
854        void setRate(int rate) {
855            mRate = rate;
856        }
857
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
876        SensorListeners(int rate) {
877            mRate = rate;
878        }
879
880        int getRate() {
881            return mRate;
882        }
883
884        void setRate(int rate) {
885            mRate = rate;
886        }
887
888        /** update rate from existing clients and return true if rate is changed. */
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
904        void addSensorClientWithRate(SensorClientWithRate clientWithRate) {
905            mSensorClients.add(clientWithRate);
906        }
907
908        void removeSensorClientWithRate(SensorClientWithRate clientWithRate) {
909            mSensorClients.remove(clientWithRate);
910        }
911
912        int getNumberOfClients() {
913            return mSensorClients.size();
914        }
915
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
925        void queueSensorEvent(CarSensorEvent event) {
926            for (SensorClientWithRate clientWithRate: mSensorClients) {
927                clientWithRate.getSensorClient().queueSensorEvent(event);
928            }
929        }
930
931        void release() {
932            for (SensorClientWithRate clientWithRate: mSensorClients) {
933                clientWithRate.mSensorClient.release();
934            }
935            mSensorClients.clear();
936        }
937    }
938
939    @Override
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