blob: 82cd32fdc912389a6990b659625d350559d2d8d0 [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
19import android.Manifest;
Keun-young Parke54ac272016-02-16 19:02:18 -080020import 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;
keunyoungca515072015-07-10 12:21:47 -070026import android.content.Context;
27import android.content.pm.PackageManager;
keunyoungcc449f72015-08-12 10:46:27 -070028import android.hardware.SensorEvent;
keunyoungca515072015-07-10 12:21:47 -070029import android.os.Binder;
keunyoungcc449f72015-08-12 10:46:27 -070030import android.os.Handler;
31import android.os.HandlerThread;
keunyoungca515072015-07-10 12:21:47 -070032import android.os.IBinder;
keunyoungcc449f72015-08-12 10:46:27 -070033import android.os.Looper;
34import android.os.Message;
keunyoungca515072015-07-10 12:21:47 -070035import android.os.Process;
36import android.os.RemoteException;
37import android.os.SystemClock;
keunyoungca515072015-07-10 12:21:47 -070038import android.util.Log;
39import android.util.SparseArray;
40import android.util.SparseBooleanArray;
41
keunyoungcc449f72015-08-12 10:46:27 -070042import com.android.car.hal.VehicleHal;
keunyoungcc449f72015-08-12 10:46:27 -070043import com.android.car.hal.SensorHalService;
44import com.android.car.hal.SensorHalServiceBase;
45import com.android.car.hal.SensorHalServiceBase.SensorListener;
keunyoungca515072015-07-10 12:21:47 -070046import com.android.internal.annotations.GuardedBy;
47
48import java.io.PrintWriter;
49import java.util.Arrays;
50import java.util.ConcurrentModificationException;
keunyoungcc449f72015-08-12 10:46:27 -070051import java.util.HashMap;
keunyoungca515072015-07-10 12:21:47 -070052import 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 */
keunyoungcc449f72015-08-12 10:46:27 -070070 public static abstract class LogicalSensorHalBase extends SensorHalServiceBase {
71
keunyoungca515072015-07-10 12:21:47 -070072 /** Sensor service is ready and all vehicle sensors are available. */
73 public abstract void onSensorServiceReady();
keunyoungca515072015-07-10 12:21:47 -070074 }
75
keunyoungfe30ba02015-09-17 17:56:35 -070076 /**
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
keunyoungca515072015-07-10 12:21:47 -070082 /** {@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>();
Keun-young Park901392c2016-05-06 14:50:11 -070090 /** should be used only as temp data for event dispatching */
91 private final LinkedList<SensorClient> mClientDispatchList = new LinkedList<>();
keunyoungca515072015-07-10 12:21:47 -070092 /** key: sensor type. */
93 @GuardedBy("mSensorLock")
94 private final SparseArray<SensorListeners> mSensorListeners = new SparseArray<>();
95 /** key: sensor type. */
96 @GuardedBy("mSensorLock")
97 private final SparseArray<SensorRecord> mSensorRecords = new SparseArray<>();
98
keunyoungcc449f72015-08-12 10:46:27 -070099 private final SensorHalService mSensorHal;
keunyoungca515072015-07-10 12:21:47 -0700100 private int[] mCarProvidedSensors;
101 private int[] mSupportedSensors;
102 private final AtomicBoolean mSensorDiscovered = new AtomicBoolean(false);
103
104 private final Context mContext;
105
106 private final DrivingStatePolicy mDrivingStatePolicy;
keunyoungcc449f72015-08-12 10:46:27 -0700107 private boolean mUseDefaultDrivingPolicy = true;
keunyoungca515072015-07-10 12:21:47 -0700108 private final DayNightModePolicy mDayNightModePolicy;
keunyoungcc449f72015-08-12 10:46:27 -0700109 private boolean mUseDefaultDayNightModePolicy = true;
110
111 private final HandlerThread mHandlerThread;
112 private final SensorDispatchHandler mSensorDispatchHandler;
keunyoungca515072015-07-10 12:21:47 -0700113
114 public CarSensorService(Context context) {
115 mContext = context;
keunyoungfe30ba02015-09-17 17:56:35 -0700116 if (ENABLE_DISPATCHING_LIMIT) {
117 mHandlerThread = new HandlerThread("SENSOR", Process.THREAD_PRIORITY_AUDIO);
118 mHandlerThread.start();
119 mSensorDispatchHandler = new SensorDispatchHandler(mHandlerThread.getLooper());
120 } else {
121 mHandlerThread = null;
122 mSensorDispatchHandler = null;
123 }
keunyoungca515072015-07-10 12:21:47 -0700124 // This triggers sensor hal init as well.
keunyoungfe30ba02015-09-17 17:56:35 -0700125 mSensorHal = VehicleHal.getInstance().getSensorHal();
keunyoungca515072015-07-10 12:21:47 -0700126 mDrivingStatePolicy = new DrivingStatePolicy(context);
127 mDayNightModePolicy = new DayNightModePolicy(context);
128 }
129
130 @Override
131 public void init() {
keunyoungca515072015-07-10 12:21:47 -0700132 mSensorLock.lock();
133 try {
Keun-young Park9ec05472016-04-26 21:18:18 -0700134 mSensorHal.registerSensorListener(this);
135 mCarProvidedSensors = mSensorHal.getSupportedSensors();
keunyoungca515072015-07-10 12:21:47 -0700136 mSupportedSensors = refreshSupportedSensorsLocked();
Keun-young Park05f44812016-02-10 15:32:48 -0800137 CarSensorEvent event = null;
keunyoungcc449f72015-08-12 10:46:27 -0700138 if (mUseDefaultDrivingPolicy) {
139 mDrivingStatePolicy.init();
keunyoungcc449f72015-08-12 10:46:27 -0700140 mDrivingStatePolicy.registerSensorListener(this);
Keun-young Park05f44812016-02-10 15:32:48 -0800141 } else {
142 event = mSensorHal.getCurrentSensorValue(
143 CarSensorManager.SENSOR_TYPE_DRIVING_STATUS);
Keun-young Park9ec05472016-04-26 21:18:18 -0700144 Log.i(CarLog.TAG_SENSOR, "initial driving status:" + ((event == null)?
145 "not ready" : " 0x" + Integer.toHexString(event.intValues[0])));
Keun-young Park05f44812016-02-10 15:32:48 -0800146 }
147 if (event == null) {
148 event = DrivingStatePolicy.getDefaultValue(
149 CarSensorManager.SENSOR_TYPE_DRIVING_STATUS);
Keun-young Park9ec05472016-04-26 21:18:18 -0700150 if (!mUseDefaultDrivingPolicy) {
151 Log.w(CarLog.TAG_SENSOR, "Default driving status set as sensor not ready");
152 }
keunyoungcc449f72015-08-12 10:46:27 -0700153 }
keunyoung1ab8e182015-09-24 09:25:22 -0700154 // always populate default value
Keun-young Park05f44812016-02-10 15:32:48 -0800155 addNewSensorRecordLocked(CarSensorManager.SENSOR_TYPE_DRIVING_STATUS, event);
156 event = null;
keunyoungcc449f72015-08-12 10:46:27 -0700157 if (mUseDefaultDayNightModePolicy) {
158 mDayNightModePolicy.init();
keunyoungcc449f72015-08-12 10:46:27 -0700159 mDayNightModePolicy.registerSensorListener(this);
Keun-young Park05f44812016-02-10 15:32:48 -0800160 } else {
161 event = mSensorHal.getCurrentSensorValue(CarSensorManager.SENSOR_TYPE_NIGHT);
Keun-young Park9ec05472016-04-26 21:18:18 -0700162 Log.i(CarLog.TAG_SENSOR, "initial daynight:" + ((event == null)?
163 "not ready" : + event.intValues[0]));
Keun-young Park05f44812016-02-10 15:32:48 -0800164 }
165 if (event == null) {
166 event = DayNightModePolicy.getDefaultValue(CarSensorManager.SENSOR_TYPE_NIGHT);
Keun-young Park9ec05472016-04-26 21:18:18 -0700167 if (!mUseDefaultDayNightModePolicy) {
168 Log.w(CarLog.TAG_SENSOR, "Default daynight set as sensor not ready");
169 }
keunyoungcc449f72015-08-12 10:46:27 -0700170 }
keunyoung1ab8e182015-09-24 09:25:22 -0700171 // always populate default value
Keun-young Park05f44812016-02-10 15:32:48 -0800172 addNewSensorRecordLocked(CarSensorManager.SENSOR_TYPE_NIGHT, event);
Keun-young Park9ec05472016-04-26 21:18:18 -0700173 notifyDefaultPoliciesLocked();
keunyoungca515072015-07-10 12:21:47 -0700174 } finally {
175 mSensorLock.unlock();
176 }
keunyoungca515072015-07-10 12:21:47 -0700177 }
178
179 private void addNewSensorRecordLocked(int type, CarSensorEvent event) {
180 SensorRecord record = new SensorRecord();
181 record.lastEvent = event;
182 mSensorRecords.put(type,record);
183 }
184
185 @Override
186 public void release() {
keunyoung1ab8e182015-09-24 09:25:22 -0700187 if (mHandlerThread != null) {
188 mHandlerThread.quit();
189 }
keunyoungca515072015-07-10 12:21:47 -0700190 tryHoldSensorLock();
191 try {
keunyoungcc449f72015-08-12 10:46:27 -0700192 if (mUseDefaultDrivingPolicy) {
193 mDrivingStatePolicy.release();
194 }
195 if (mUseDefaultDayNightModePolicy) {
196 mDayNightModePolicy.release();
197 }
keunyoungca515072015-07-10 12:21:47 -0700198 for (int i = mSensorListeners.size() - 1; i >= 0; --i) {
199 SensorListeners listener = mSensorListeners.valueAt(i);
200 listener.release();
201 }
202 mSensorListeners.clear();
203 mSensorRecords.clear();
204 mClients.clear();
205 } finally {
206 releaseSensorLockSafely();
207 }
208 }
209
210 private void tryHoldSensorLock() {
211 try {
212 mSensorLock.tryLock(MAX_SENSOR_LOCK_WAIT_MS, TimeUnit.MILLISECONDS);
213 } catch (InterruptedException e) {
214 //ignore
215 }
216 }
217
218 private void releaseSensorLockSafely() {
219 if (mSensorLock.isHeldByCurrentThread()) {
220 mSensorLock.unlock();
221 }
222 }
223
Keun-young Park9ec05472016-04-26 21:18:18 -0700224 private void notifyDefaultPoliciesLocked() {
225 if (mUseDefaultDrivingPolicy) {
226 mDrivingStatePolicy.onSensorServiceReady();
227 }
228 if (mUseDefaultDayNightModePolicy) {
229 mDayNightModePolicy.onSensorServiceReady();
keunyoungca515072015-07-10 12:21:47 -0700230 }
231 }
232
keunyoungcc449f72015-08-12 10:46:27 -0700233 private void processSensorData(List<CarSensorEvent> events) {
234 mSensorLock.lock();
235 for (CarSensorEvent event: events) {
236 SensorRecord record = mSensorRecords.get(event.sensorType);
237 if (record != null) {
238 if (record.lastEvent == null) {
239 record.lastEvent = event;
240 } else if (record.lastEvent.timeStampNs < event.timeStampNs) {
241 record.lastEvent = event;
242 //TODO recycle event
243 } else { // wrong timestamp, throw away this.
244 //TODO recycle new event
245 continue;
246 }
247 SensorListeners listeners = mSensorListeners.get(event.sensorType);
248 if (listeners != null) {
249 listeners.queueSensorEvent(event);
250 }
keunyoungca515072015-07-10 12:21:47 -0700251 }
252 }
Keun-young Park901392c2016-05-06 14:50:11 -0700253 mClientDispatchList.addAll(mClients);
254 mSensorLock.unlock();
255 for (SensorClient client: mClientDispatchList) {
keunyoungcc449f72015-08-12 10:46:27 -0700256 client.dispatchSensorUpdate();
keunyoungca515072015-07-10 12:21:47 -0700257 }
Keun-young Park901392c2016-05-06 14:50:11 -0700258 mClientDispatchList.clear();
keunyoungca515072015-07-10 12:21:47 -0700259 }
260
261 /**
262 * Received sensor data from car.
263 *
264 * @param event
265 */
266 @Override
keunyoungcc449f72015-08-12 10:46:27 -0700267 public void onSensorEvents(List<CarSensorEvent> events) {
keunyoungfe30ba02015-09-17 17:56:35 -0700268 if (ENABLE_DISPATCHING_LIMIT) {
269 mSensorDispatchHandler.handleSensorEvents(events);
270 } else {
271 processSensorData(events);
272 }
keunyoungca515072015-07-10 12:21:47 -0700273 }
274
275 @Override
276 public int[] getSupportedSensors() {
277 return mSupportedSensors;
278 }
279
keunyoungca515072015-07-10 12:21:47 -0700280 @Override
281 public boolean registerOrUpdateSensorListener(int sensorType, int rate,
Keun-young Parke54ac272016-02-16 19:02:18 -0800282 ICarSensorEventListener listener) {
keunyoungca515072015-07-10 12:21:47 -0700283 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) {
keunyoungcc449f72015-08-12 10:46:27 -0700330 sensorClient.queueSensorEvent(record.lastEvent);
331 sensorClient.dispatchSensorUpdate();
keunyoungca515072015-07-10 12:21:47 -0700332 }
333 if (sensorListeners == null) {
334 sensorListeners = new SensorListeners(rate);
335 mSensorListeners.put(sensorType, sensorListeners);
keunyoungcc449f72015-08-12 10:46:27 -0700336 shouldStartSensors = true;
keunyoungca515072015-07-10 12:21:47 -0700337 } 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);
keunyoungcc449f72015-08-12 10:46:27 -0700349 shouldStartSensors = sensorSupportRate(sensorType);
keunyoungca515072015-07-10 12:21:47 -0700350 }
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
keunyoungcc449f72015-08-12 10:46:27 -0700376 private boolean sensorSupportRate(int sensorType) {
377 switch (sensorType) {
keunyoungcc449f72015-08-12 10:46:27 -0700378 case CarSensorManager.SENSOR_TYPE_CAR_SPEED:
379 case CarSensorManager.SENSOR_TYPE_RPM:
keunyoungcc449f72015-08-12 10:46:27 -0700380 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
keunyoungca515072015-07-10 12:21:47 -0700395 private int getSensorPermission(int sensorType) {
396 String permission = getPermissionName(sensorType);
397 int result = PackageManager.PERMISSION_GRANTED;
398 if (permission != null) {
Keun-young Park064ddd82015-12-21 23:57:50 +0000399 return mContext.checkCallingOrSelfPermission(permission);
keunyoungca515072015-07-10 12:21:47 -0700400 }
401 // If no permission is required, return granted.
402 return result;
403 }
404
keunyoungfe30ba02015-09-17 17:56:35 -0700405 //TODO handle per property OEM permission
keunyoungca515072015-07-10 12:21:47 -0700406 private String getPermissionName(int sensorType) {
Keun-young Park064ddd82015-12-21 23:57:50 +0000407 if ((sensorType >= CarSensorManager.SENSOR_TYPE_VENDOR_EXTENSION_START) &&
408 (sensorType >= CarSensorManager.SENSOR_TYPE_VENDOR_EXTENSION_END)) {
409 return Car.PERMISSION_VENDOR_EXTENSION;
410 }
keunyoungca515072015-07-10 12:21:47 -0700411 String permission = null;
412 switch (sensorType) {
keunyoungca515072015-07-10 12:21:47 -0700413 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 }
keunyoungcc449f72015-08-12 10:46:27 -0700435 SensorHalServiceBase sensorHal = getSensorHal(sensorType);
keunyoungca515072015-07-10 12:21:47 -0700436 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 }
Keun-young Park05f44812016-02-10 15:32:48 -0800449 Log.w(CarLog.TAG_SENSOR, "requestSensorStart failed, sensor type:" + sensorType);
keunyoungca515072015-07-10 12:21:47 -0700450 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) {
keunyoungcc449f72015-08-12 10:46:27 -0700500 shouldStopSensor = true;
keunyoungca515072015-07-10 12:21:47 -0700501 mSensorListeners.remove(sensorType);
502 } else if (sensorListeners.updateRate()) { // rate changed
503 newRate = sensorListeners.getRate();
keunyoungcc449f72015-08-12 10:46:27 -0700504 shouldRestartSensor = sensorSupportRate(sensorType);
keunyoungca515072015-07-10 12:21:47 -0700505 }
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 }
keunyoungcc449f72015-08-12 10:46:27 -0700523 SensorHalServiceBase sensorHal = getSensorHal(sensorType);
keunyoungca515072015-07-10 12:21:47 -0700524 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
keunyoungcc449f72015-08-12 10:46:27 -0700541 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();
keunyoungca515072015-07-10 12:21:47 -0700559 }
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;
keunyoungcc449f72015-08-12 10:46:27 -0700579 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 }
keunyoungca515072015-07-10 12:21:47 -0700594 // Two logical sensors are always added.
keunyoungcc449f72015-08-12 10:46:27 -0700595 int[] supportedSensors = new int[totalNumSensors];
keunyoungca515072015-07-10 12:21:47 -0700596 int index = 0;
keunyoungcc449f72015-08-12 10:46:27 -0700597 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 }
keunyoungca515072015-07-10 12:21:47 -0700605
606 for (int i = 0; i < numCarSensors; i++) {
607 int sensor = mCarProvidedSensors[i];
keunyoungcc449f72015-08-12 10:46:27 -0700608
keunyoungca515072015-07-10 12:21:47 -0700609 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
keunyoungca515072015-07-10 12:21:47 -0700631 /**
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
keunyoungcc449f72015-08-12 10:46:27 -0700660 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
keunyoungca515072015-07-10 12:21:47 -0700738 /** 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();
keunyoungcc449f72015-08-12 10:46:27 -0700743 private final LinkedList<CarSensorEvent> mSensorsToDispatch =
744 new LinkedList<CarSensorEvent>();
keunyoungca515072015-07-10 12:21:47 -0700745
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
keunyoungcc449f72015-08-12 10:46:27 -0700799 void queueSensorEvent(CarSensorEvent event) {
800 mSensorsToDispatch.add(event);
801 }
802
803 void dispatchSensorUpdate() {
804 if (mSensorsToDispatch.size() == 0) {
805 return;
keunyoungca515072015-07-10 12:21:47 -0700806 }
keunyoungcc449f72015-08-12 10:46:27 -0700807 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();
keunyoungca515072015-07-10 12:21:47 -0700819 }
820
821 void release() {
822 if (mActive) {
823 mListener.asBinder().unlinkToDeath(this, 0);
824 mActiveSensors.clear();
keunyoungcc449f72015-08-12 10:46:27 -0700825 mSensorsToDispatch.clear();
keunyoungca515072015-07-10 12:21:47 -0700826 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
keunyoungcc449f72015-08-12 10:46:27 -0700925 void queueSensorEvent(CarSensorEvent event) {
keunyoungca515072015-07-10 12:21:47 -0700926 for (SensorClientWithRate clientWithRate: mSensorClients) {
keunyoungcc449f72015-08-12 10:46:27 -0700927 clientWithRate.getSensorClient().queueSensorEvent(event);
keunyoungca515072015-07-10 12:21:47 -0700928 }
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) {
keunyounga3b28d82015-08-25 13:05:15 -0700941 writer.println("*CarSensorService*");
keunyoungca515072015-07-10 12:21:47 -0700942 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);
Keun-young Park4afc6ee2016-03-04 18:18:19 -0800953 writer.println(" " + record.lastEvent.toString());
keunyoungca515072015-07-10 12:21:47 -0700954 }
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 }
Keun-young Park9ec05472016-04-26 21:18:18 -0700998 writer.println("mUseDefaultDrivingPolicy:" + mUseDefaultDrivingPolicy +
999 ",mUseDefaultDayNightModePolicy" + mUseDefaultDayNightModePolicy);
keunyoungca515072015-07-10 12:21:47 -07001000 writer.println("**driving policy**");
keunyoungcc449f72015-08-12 10:46:27 -07001001 if (mUseDefaultDrivingPolicy) {
1002 mDrivingStatePolicy.dump(writer);
1003 }
keunyoungca515072015-07-10 12:21:47 -07001004 writer.println("**day/night policy**");
keunyoungcc449f72015-08-12 10:46:27 -07001005 if (mUseDefaultDayNightModePolicy) {
1006 mDayNightModePolicy.dump(writer);
1007 }
keunyoungca515072015-07-10 12:21:47 -07001008 }
1009}