blob: ffb13ca9469092710df94784a05db562f8e83703 [file] [log] [blame]
keunyoungca515072015-07-10 12:21:47 -07001/*
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
Keun-young Parke54ac272016-02-16 19:02:18 -080019import android.car.Car;
20import android.car.hardware.CarSensorEvent;
21import android.car.hardware.CarSensorManager;
22import android.car.hardware.ICarSensor;
23import android.car.hardware.ICarSensorEventListener;
keunyoungca515072015-07-10 12:21:47 -070024import android.content.Context;
25import android.content.pm.PackageManager;
26import android.os.Binder;
keunyoungcc449f72015-08-12 10:46:27 -070027import android.os.Handler;
28import android.os.HandlerThread;
keunyoungca515072015-07-10 12:21:47 -070029import android.os.IBinder;
keunyoungcc449f72015-08-12 10:46:27 -070030import android.os.Looper;
31import android.os.Message;
keunyoungca515072015-07-10 12:21:47 -070032import android.os.Process;
33import android.os.RemoteException;
34import android.os.SystemClock;
Pavel Maltsev0d07c762016-11-03 16:40:15 -070035import android.util.ArrayMap;
keunyoungca515072015-07-10 12:21:47 -070036import android.util.Log;
37import android.util.SparseArray;
38import android.util.SparseBooleanArray;
39
Enrico Granata43f92802017-02-06 14:30:07 -080040import static com.android.car.Listeners.ClientWithRate;
Enrico Granata7096f5e2017-02-03 14:54:20 -080041import com.android.car.hal.SensorBase;
42import com.android.car.hal.SensorHalService.SensorListener;
Pavel Maltsev0d07c762016-11-03 16:40:15 -070043import com.google.android.collect.Lists;
44
keunyoungcc449f72015-08-12 10:46:27 -070045import com.android.car.hal.SensorHalService;
46import com.android.car.hal.SensorHalServiceBase;
keunyoungca515072015-07-10 12:21:47 -070047import com.android.internal.annotations.GuardedBy;
48
49import java.io.PrintWriter;
50import java.util.Arrays;
51import java.util.ConcurrentModificationException;
52import java.util.LinkedList;
keunyoungcc449f72015-08-12 10:46:27 -070053import java.util.List;
keunyoungca515072015-07-10 12:21:47 -070054import java.util.concurrent.TimeUnit;
55import java.util.concurrent.atomic.AtomicBoolean;
56import java.util.concurrent.locks.ReentrantLock;
57
58
59public class CarSensorService extends ICarSensor.Stub
keunyoungcc449f72015-08-12 10:46:27 -070060 implements CarServiceBase, SensorHalService.SensorListener {
keunyoungca515072015-07-10 12:21:47 -070061
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
keunyoungcc449f72015-08-12 10:46:27 -070067 * is state change for the given sensor after {@link SensorHalServiceBase#init()}
keunyoungca515072015-07-10 12:21:47 -070068 * is called.
69 */
Enrico Granata7096f5e2017-02-03 14:54:20 -080070 public static abstract class LogicalSensor implements SensorBase {
71 private final LinkedList<CarSensorEvent> mDispatchQ = new LinkedList<>();
keunyoungcc449f72015-08-12 10:46:27 -070072
keunyoungca515072015-07-10 12:21:47 -070073 /** Sensor service is ready and all vehicle sensors are available. */
74 public abstract void onSensorServiceReady();
Enrico Granata7096f5e2017-02-03 14:54:20 -080075
76 /**
77 * Utility to help service to send one event as listener only takes list form.
78 * @param listener
79 * @param event
80 */
81 protected void dispatchCarSensorEvent(SensorListener listener, CarSensorEvent event) {
82 synchronized (mDispatchQ) {
83 mDispatchQ.add(event);
84 listener.onSensorEvents(mDispatchQ);
85 mDispatchQ.clear();
86 }
87 }
keunyoungca515072015-07-10 12:21:47 -070088 }
89
keunyoungfe30ba02015-09-17 17:56:35 -070090 /**
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
keunyoungca515072015-07-10 12:21:47 -070096 /** {@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")
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700103 private final LinkedList<SensorClient> mClients = new LinkedList<>();
104
keunyoungca515072015-07-10 12:21:47 -0700105 /** key: sensor type. */
106 @GuardedBy("mSensorLock")
Enrico Granata43f92802017-02-06 14:30:07 -0800107 private final SparseArray<Listeners<SensorClient>> mSensorListeners = new SparseArray<>();
keunyoungca515072015-07-10 12:21:47 -0700108 /** key: sensor type. */
109 @GuardedBy("mSensorLock")
110 private final SparseArray<SensorRecord> mSensorRecords = new SparseArray<>();
111
keunyoungcc449f72015-08-12 10:46:27 -0700112 private final SensorHalService mSensorHal;
keunyoungca515072015-07-10 12:21:47 -0700113 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;
keunyoungcc449f72015-08-12 10:46:27 -0700120 private boolean mUseDefaultDrivingPolicy = true;
keunyoungca515072015-07-10 12:21:47 -0700121 private final DayNightModePolicy mDayNightModePolicy;
keunyoungcc449f72015-08-12 10:46:27 -0700122 private boolean mUseDefaultDayNightModePolicy = true;
123
124 private final HandlerThread mHandlerThread;
125 private final SensorDispatchHandler mSensorDispatchHandler;
keunyoungca515072015-07-10 12:21:47 -0700126
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700127 public CarSensorService(Context context, SensorHalService sensorHal) {
keunyoungca515072015-07-10 12:21:47 -0700128 mContext = context;
keunyoungfe30ba02015-09-17 17:56:35 -0700129 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 }
keunyoungca515072015-07-10 12:21:47 -0700137 // This triggers sensor hal init as well.
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700138 mSensorHal = sensorHal;
139 mDrivingStatePolicy = new DrivingStatePolicy(context, this);
keunyoungca515072015-07-10 12:21:47 -0700140 mDayNightModePolicy = new DayNightModePolicy(context);
141 }
142
143 @Override
144 public void init() {
keunyoungca515072015-07-10 12:21:47 -0700145 mSensorLock.lock();
146 try {
Keun-young Park9ec05472016-04-26 21:18:18 -0700147 mSensorHal.registerSensorListener(this);
148 mCarProvidedSensors = mSensorHal.getSupportedSensors();
keunyoungca515072015-07-10 12:21:47 -0700149 mSupportedSensors = refreshSupportedSensorsLocked();
Pavel Maltsev1e5a88b2016-12-15 17:51:29 -0800150
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
Keun-young Park9ec05472016-04-26 21:18:18 -0700157 notifyDefaultPoliciesLocked();
keunyoungca515072015-07-10 12:21:47 -0700158 } finally {
159 mSensorLock.unlock();
160 }
keunyoungca515072015-07-10 12:21:47 -0700161 }
162
Pavel Maltsev1e5a88b2016-12-15 17:51:29 -0800163 private CarSensorEvent getInitialIgnitionState() {
164 return mSensorHal.getCurrentSensorValue(CarSensorManager.SENSOR_TYPE_IGNITION_STATE);
165 }
166
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
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
keunyoungca515072015-07-10 12:21:47 -0700207 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
214 public void release() {
keunyoung1ab8e182015-09-24 09:25:22 -0700215 if (mHandlerThread != null) {
216 mHandlerThread.quit();
217 }
keunyoungca515072015-07-10 12:21:47 -0700218 tryHoldSensorLock();
219 try {
keunyoungcc449f72015-08-12 10:46:27 -0700220 if (mUseDefaultDrivingPolicy) {
221 mDrivingStatePolicy.release();
222 }
223 if (mUseDefaultDayNightModePolicy) {
224 mDayNightModePolicy.release();
225 }
keunyoungca515072015-07-10 12:21:47 -0700226 for (int i = mSensorListeners.size() - 1; i >= 0; --i) {
Enrico Granata43f92802017-02-06 14:30:07 -0800227 Listeners listener = mSensorListeners.valueAt(i);
keunyoungca515072015-07-10 12:21:47 -0700228 listener.release();
229 }
230 mSensorListeners.clear();
231 mSensorRecords.clear();
232 mClients.clear();
233 } finally {
234 releaseSensorLockSafely();
235 }
236 }
237
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
246 private void releaseSensorLockSafely() {
247 if (mSensorLock.isHeldByCurrentThread()) {
248 mSensorLock.unlock();
249 }
250 }
251
Keun-young Park9ec05472016-04-26 21:18:18 -0700252 private void notifyDefaultPoliciesLocked() {
253 if (mUseDefaultDrivingPolicy) {
254 mDrivingStatePolicy.onSensorServiceReady();
255 }
256 if (mUseDefaultDayNightModePolicy) {
257 mDayNightModePolicy.onSensorServiceReady();
keunyoungca515072015-07-10 12:21:47 -0700258 }
259 }
260
keunyoungcc449f72015-08-12 10:46:27 -0700261 private void processSensorData(List<CarSensorEvent> events) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700262 ArrayMap<SensorClient, List<CarSensorEvent>> eventsByClient = new ArrayMap<>();
263
keunyoungcc449f72015-08-12 10:46:27 -0700264 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;
Jason Tholstrupd72b5352016-09-22 16:32:14 -0700270 } else if (record.lastEvent.timestamp < event.timestamp) {
keunyoungcc449f72015-08-12 10:46:27 -0700271 record.lastEvent = event;
Keun-young Parkf9215202016-10-10 12:34:08 -0700272 //TODO recycle event, bug: 32094595
keunyoungcc449f72015-08-12 10:46:27 -0700273 } else { // wrong timestamp, throw away this.
Keun-young Parkf9215202016-10-10 12:34:08 -0700274 //TODO recycle new event, bug: 32094595
keunyoungcc449f72015-08-12 10:46:27 -0700275 continue;
276 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700277
Enrico Granata43f92802017-02-06 14:30:07 -0800278 Listeners<SensorClient> listeners = mSensorListeners.get(event.sensorType);
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700279 if (listeners == null) {
280 continue;
281 }
282
Enrico Granata43f92802017-02-06 14:30:07 -0800283 for (ClientWithRate<SensorClient> clientWithRate : listeners.getClients()) {
284 SensorClient client = clientWithRate.getClient();
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700285 List<CarSensorEvent> clientEvents = eventsByClient.get(client);
286 if (clientEvents == null) {
287 clientEvents = new LinkedList<>();
288 eventsByClient.put(client, clientEvents);
289 }
290 clientEvents.add(event);
keunyoungcc449f72015-08-12 10:46:27 -0700291 }
keunyoungca515072015-07-10 12:21:47 -0700292 }
293 }
Keun-young Park901392c2016-05-06 14:50:11 -0700294 mSensorLock.unlock();
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700295
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);
keunyoungca515072015-07-10 12:21:47 -0700301 }
keunyoungca515072015-07-10 12:21:47 -0700302 }
303
304 /**
305 * Received sensor data from car.
keunyoungca515072015-07-10 12:21:47 -0700306 */
307 @Override
keunyoungcc449f72015-08-12 10:46:27 -0700308 public void onSensorEvents(List<CarSensorEvent> events) {
keunyoungfe30ba02015-09-17 17:56:35 -0700309 if (ENABLE_DISPATCHING_LIMIT) {
310 mSensorDispatchHandler.handleSensorEvents(events);
311 } else {
312 processSensorData(events);
313 }
keunyoungca515072015-07-10 12:21:47 -0700314 }
315
316 @Override
317 public int[] getSupportedSensors() {
Vitalii Tomkiva8386362016-07-29 12:27:25 -0700318 mSensorLock.lock();
Vitalii Tomkivbb051042016-07-27 17:13:24 -0700319 int[] supportedSensors = mSupportedSensors;
Vitalii Tomkiva8386362016-07-29 12:27:25 -0700320 mSensorLock.unlock();
Vitalii Tomkivbb051042016-07-27 17:13:24 -0700321 return supportedSensors;
keunyoungca515072015-07-10 12:21:47 -0700322 }
323
keunyoungca515072015-07-10 12:21:47 -0700324 @Override
325 public boolean registerOrUpdateSensorListener(int sensorType, int rate,
Keun-young Parke54ac272016-02-16 19:02:18 -0800326 ICarSensorEventListener listener) {
keunyoungca515072015-07-10 12:21:47 -0700327 boolean shouldStartSensors = false;
328 SensorRecord sensorRecord = null;
329 SensorClient sensorClient = null;
330 Integer oldRate = null;
Enrico Granata43f92802017-02-06 14:30:07 -0800331 Listeners<SensorClient> sensorListeners = null;
keunyoungca515072015-07-10 12:21:47 -0700332 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);
Enrico Granata43f92802017-02-06 14:30:07 -0800357 ClientWithRate<SensorClient> sensorClientWithRate = null;
keunyoungca515072015-07-10 12:21:47 -0700358 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) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700374 sensorClient.dispatchSensorUpdate(Lists.newArrayList(record.lastEvent));
keunyoungca515072015-07-10 12:21:47 -0700375 }
376 if (sensorListeners == null) {
Enrico Granata43f92802017-02-06 14:30:07 -0800377 sensorListeners = new Listeners<>(rate);
keunyoungca515072015-07-10 12:21:47 -0700378 mSensorListeners.put(sensorType, sensorListeners);
keunyoungcc449f72015-08-12 10:46:27 -0700379 shouldStartSensors = true;
keunyoungca515072015-07-10 12:21:47 -0700380 } else {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700381 oldRate = sensorListeners.getRate();
Enrico Granata43f92802017-02-06 14:30:07 -0800382 sensorClientWithRate = sensorListeners.findClientWithRate(sensorClient);
keunyoungca515072015-07-10 12:21:47 -0700383 }
384 if (sensorClientWithRate == null) {
Enrico Granata43f92802017-02-06 14:30:07 -0800385 sensorClientWithRate = new ClientWithRate<>(sensorClient, rate);
386 sensorListeners.addClientWithRate(sensorClientWithRate);
keunyoungca515072015-07-10 12:21:47 -0700387 } else {
388 sensorClientWithRate.setRate(rate);
389 }
390 if (sensorListeners.getRate() > rate) {
391 sensorListeners.setRate(rate);
keunyoungcc449f72015-08-12 10:46:27 -0700392 shouldStartSensors = sensorSupportRate(sensorType);
keunyoungca515072015-07-10 12:21:47 -0700393 }
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
keunyoungcc449f72015-08-12 10:46:27 -0700419 private boolean sensorSupportRate(int sensorType) {
420 switch (sensorType) {
keunyoungcc449f72015-08-12 10:46:27 -0700421 case CarSensorManager.SENSOR_TYPE_CAR_SPEED:
422 case CarSensorManager.SENSOR_TYPE_RPM:
keunyoungcc449f72015-08-12 10:46:27 -0700423 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
keunyoungca515072015-07-10 12:21:47 -0700438 private int getSensorPermission(int sensorType) {
439 String permission = getPermissionName(sensorType);
440 int result = PackageManager.PERMISSION_GRANTED;
441 if (permission != null) {
Keun-young Park064ddd82015-12-21 23:57:50 +0000442 return mContext.checkCallingOrSelfPermission(permission);
keunyoungca515072015-07-10 12:21:47 -0700443 }
444 // If no permission is required, return granted.
445 return result;
446 }
447
Keun-young Parkf9215202016-10-10 12:34:08 -0700448 //TODO handle per property OEM permission. bug: 32094983
keunyoungca515072015-07-10 12:21:47 -0700449 private String getPermissionName(int sensorType) {
Keun-young Park064ddd82015-12-21 23:57:50 +0000450 if ((sensorType >= CarSensorManager.SENSOR_TYPE_VENDOR_EXTENSION_START) &&
451 (sensorType >= CarSensorManager.SENSOR_TYPE_VENDOR_EXTENSION_END)) {
452 return Car.PERMISSION_VENDOR_EXTENSION;
453 }
keunyoungca515072015-07-10 12:21:47 -0700454 String permission = null;
455 switch (sensorType) {
keunyoungca515072015-07-10 12:21:47 -0700456 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
471 private boolean startSensor(SensorRecord record, int sensorType, int rate) {
Keun-young Parkf9215202016-10-10 12:34:08 -0700472 //TODO handle sensor rate properly. bug: 32095903
keunyoungca515072015-07-10 12:21:47 -0700473 //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 }
Enrico Granata7096f5e2017-02-03 14:54:20 -0800478 SensorBase sensorHal = getSensorHal(sensorType);
keunyoungca515072015-07-10 12:21:47 -0700479 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 }
Keun-young Park05f44812016-02-10 15:32:48 -0800492 Log.w(CarLog.TAG_SENSOR, "requestSensorStart failed, sensor type:" + sensorType);
keunyoungca515072015-07-10 12:21:47 -0700493 return false;
494 }
495
496 @Override
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 }
Enrico Granata43f92802017-02-06 14:30:07 -0800525 Listeners<SensorClient> sensorListeners = mSensorListeners.get(sensorType);
keunyoungca515072015-07-10 12:21:47 -0700526 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 }
Enrico Granata43f92802017-02-06 14:30:07 -0800533 ClientWithRate<SensorClient> clientWithRate =
534 sensorListeners.findClientWithRate(sensorClient);
keunyoungca515072015-07-10 12:21:47 -0700535 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 }
Enrico Granata43f92802017-02-06 14:30:07 -0800541 sensorListeners.removeClientWithRate(clientWithRate);
keunyoungca515072015-07-10 12:21:47 -0700542 if (sensorListeners.getNumberOfClients() == 0) {
keunyoungcc449f72015-08-12 10:46:27 -0700543 shouldStopSensor = true;
keunyoungca515072015-07-10 12:21:47 -0700544 mSensorListeners.remove(sensorType);
545 } else if (sensorListeners.updateRate()) { // rate changed
546 newRate = sensorListeners.getRate();
keunyoungcc449f72015-08-12 10:46:27 -0700547 shouldRestartSensor = sensorSupportRate(sensorType);
keunyoungca515072015-07-10 12:21:47 -0700548 }
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
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 }
Enrico Granata7096f5e2017-02-03 14:54:20 -0800566 SensorBase sensorHal = getSensorHal(sensorType);
keunyoungca515072015-07-10 12:21:47 -0700567 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
Enrico Granata7096f5e2017-02-03 14:54:20 -0800584 private SensorBase getSensorHal(int sensorType) {
keunyoungcc449f72015-08-12 10:46:27 -0700585 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();
keunyoungca515072015-07-10 12:21:47 -0700602 }
603 }
604
605 @Override
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
620 private int[] refreshSupportedSensorsLocked() {
621 int numCarSensors = (mCarProvidedSensors == null) ? 0 : mCarProvidedSensors.length;
keunyoungcc449f72015-08-12 10:46:27 -0700622 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 }
keunyoungca515072015-07-10 12:21:47 -0700637 // Two logical sensors are always added.
keunyoungcc449f72015-08-12 10:46:27 -0700638 int[] supportedSensors = new int[totalNumSensors];
keunyoungca515072015-07-10 12:21:47 -0700639 int index = 0;
keunyoungcc449f72015-08-12 10:46:27 -0700640 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 }
keunyoungca515072015-07-10 12:21:47 -0700648
649 for (int i = 0; i < numCarSensors; i++) {
650 int sensor = mCarProvidedSensors[i];
keunyoungcc449f72015-08-12 10:46:27 -0700651
keunyoungca515072015-07-10 12:21:47 -0700652 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
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
keunyoungca515072015-07-10 12:21:47 -0700674 /**
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 */
680 private SensorClient findSensorClientLocked(ICarSensorEventListener listener) {
681 IBinder binder = listener.asBinder();
682 for (SensorClient sensorClient : mClients) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700683 if (sensorClient.isHoldingListenerBinder(binder)) {
keunyoungca515072015-07-10 12:21:47 -0700684 return sensorClient;
685 }
686 }
687 return null;
688 }
689
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
keunyoungcc449f72015-08-12 10:46:27 -0700703 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
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
719 private synchronized void handleSensorEvents(List<CarSensorEvent> data) {
720 LinkedList<CarSensorEvent> list = mSensorDataList[mFreeListIndex];
721 list.addAll(data);
722 requestDispatchLocked();
723 }
724
725 private synchronized void handleSensorEvent(CarSensorEvent event) {
726 LinkedList<CarSensorEvent> list = mSensorDataList[mFreeListIndex];
727 list.add(event);
728 requestDispatchLocked();
729 }
730
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
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
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
keunyoungca515072015-07-10 12:21:47 -0700781 /** internal instance for pending client request */
Enrico Granata43f92802017-02-06 14:30:07 -0800782 private class SensorClient implements Listeners.IListener {
keunyoungca515072015-07-10 12:21:47 -0700783 /** 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
790 SensorClient(ICarSensorEventListener listener) {
791 this.mListener = listener;
792 }
793
794 @Override
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
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700803 boolean isHoldingListenerBinder(IBinder listenerBinder) {
keunyoungca515072015-07-10 12:21:47 -0700804 return mListener.asBinder() == listenerBinder;
805 }
806
807 void addSensor(int sensor) {
808 mActiveSensors.put(sensor, true);
809 }
810
811 void removeSensor(int sensor) {
812 mActiveSensors.delete(sensor);
813 }
814
815 int getNumberOfActiveSensor() {
816 return mActiveSensors.size();
817 }
818
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
827 ICarSensorEventListener getICarSensorEventListener() {
828 return mListener;
829 }
830
831 /**
832 * Client dead. should remove all sensor requests from client
833 */
834 @Override
835 public void binderDied() {
836 mListener.asBinder().unlinkToDeath(this, 0);
837 removeClient(this);
838 }
839
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700840 void dispatchSensorUpdate(List<CarSensorEvent> events) {
841 if (events.size() == 0) {
keunyoungcc449f72015-08-12 10:46:27 -0700842 return;
keunyoungca515072015-07-10 12:21:47 -0700843 }
keunyoungcc449f72015-08-12 10:46:27 -0700844 if (mActive) {
845 try {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700846 mListener.onSensorChanged(events);
keunyoungcc449f72015-08-12 10:46:27 -0700847 } 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 }
keunyoungca515072015-07-10 12:21:47 -0700855 }
856
Enrico Granata43f92802017-02-06 14:30:07 -0800857 @Override
858 public void release() {
keunyoungca515072015-07-10 12:21:47 -0700859 if (mActive) {
860 mListener.asBinder().unlinkToDeath(this, 0);
861 mActiveSensors.clear();
862 mActive = false;
863 }
864 }
865 }
866
keunyoungca515072015-07-10 12:21:47 -0700867 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
keunyoungca515072015-07-10 12:21:47 -0700874 @Override
875 public void dump(PrintWriter writer) {
keunyounga3b28d82015-08-25 13:05:15 -0700876 writer.println("*CarSensorService*");
keunyoungca515072015-07-10 12:21:47 -0700877 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);
Keun-young Park4afc6ee2016-03-04 18:18:19 -0800888 writer.println(" " + record.lastEvent.toString());
keunyoungca515072015-07-10 12:21:47 -0700889 }
Enrico Granata43f92802017-02-06 14:30:07 -0800890 Listeners listeners = mSensorListeners.get(sensor);
keunyoungca515072015-07-10 12:21:47 -0700891 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);
Enrico Granata43f92802017-02-06 14:30:07 -0800923 Listeners sensorListeners = mSensorListeners.get(sensor);
keunyoungca515072015-07-10 12:21:47 -0700924 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 }
Keun-young Park9ec05472016-04-26 21:18:18 -0700933 writer.println("mUseDefaultDrivingPolicy:" + mUseDefaultDrivingPolicy +
934 ",mUseDefaultDayNightModePolicy" + mUseDefaultDayNightModePolicy);
keunyoungca515072015-07-10 12:21:47 -0700935 writer.println("**driving policy**");
keunyoungcc449f72015-08-12 10:46:27 -0700936 if (mUseDefaultDrivingPolicy) {
937 mDrivingStatePolicy.dump(writer);
938 }
keunyoungca515072015-07-10 12:21:47 -0700939 writer.println("**day/night policy**");
keunyoungcc449f72015-08-12 10:46:27 -0700940 if (mUseDefaultDayNightModePolicy) {
941 mDayNightModePolicy.dump(writer);
942 }
keunyoungca515072015-07-10 12:21:47 -0700943 }
944}