blob: f0bc8d11b7edf9827cc1ff9f5489a6a450d739a6 [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;
keunyoungca515072015-07-10 12:21:47 -070035import android.util.Log;
36import android.util.SparseArray;
37import android.util.SparseBooleanArray;
38
keunyoungcc449f72015-08-12 10:46:27 -070039import com.android.car.hal.VehicleHal;
keunyoungcc449f72015-08-12 10:46:27 -070040import com.android.car.hal.SensorHalService;
41import com.android.car.hal.SensorHalServiceBase;
keunyoungca515072015-07-10 12:21:47 -070042import com.android.internal.annotations.GuardedBy;
43
44import java.io.PrintWriter;
45import java.util.Arrays;
46import java.util.ConcurrentModificationException;
47import java.util.LinkedList;
keunyoungcc449f72015-08-12 10:46:27 -070048import java.util.List;
keunyoungca515072015-07-10 12:21:47 -070049import java.util.concurrent.TimeUnit;
50import java.util.concurrent.atomic.AtomicBoolean;
51import java.util.concurrent.locks.ReentrantLock;
52
53
54public class CarSensorService extends ICarSensor.Stub
keunyoungcc449f72015-08-12 10:46:27 -070055 implements CarServiceBase, SensorHalService.SensorListener {
keunyoungca515072015-07-10 12:21:47 -070056
57 /**
58 * Abstraction for logical sensor which is not physical sensor but presented as sensor to
59 * upper layer. Currently {@link CarSensorManager#SENSOR_TYPE_NIGHT} and
60 * {@link CarSensorManager#SENSOR_TYPE_DRIVING_STATUS} falls into this category.
61 * Implementation can call {@link CarSensorService#onSensorData(CarSensorEvent)} when there
keunyoungcc449f72015-08-12 10:46:27 -070062 * is state change for the given sensor after {@link SensorHalServiceBase#init()}
keunyoungca515072015-07-10 12:21:47 -070063 * is called.
64 */
keunyoungcc449f72015-08-12 10:46:27 -070065 public static abstract class LogicalSensorHalBase extends SensorHalServiceBase {
66
keunyoungca515072015-07-10 12:21:47 -070067 /** Sensor service is ready and all vehicle sensors are available. */
68 public abstract void onSensorServiceReady();
keunyoungca515072015-07-10 12:21:47 -070069 }
70
keunyoungfe30ba02015-09-17 17:56:35 -070071 /**
72 * When set, sensor service sets its own dispatching rate limit.
73 * VehicleNetworkService is already doing this, so not necessary to set it for now.
74 */
75 private static final boolean ENABLE_DISPATCHING_LIMIT = false;
76
keunyoungca515072015-07-10 12:21:47 -070077 /** {@link #mSensorLock} is not waited forever for handling disconnection */
78 private static final long MAX_SENSOR_LOCK_WAIT_MS = 1000;
79
80 /** lock to access sensor structures */
81 private final ReentrantLock mSensorLock = new ReentrantLock();
82 /** hold clients callback */
83 @GuardedBy("mSensorLock")
84 private final LinkedList<SensorClient> mClients = new LinkedList<SensorClient>();
Keun-young Park901392c2016-05-06 14:50:11 -070085 /** should be used only as temp data for event dispatching */
86 private final LinkedList<SensorClient> mClientDispatchList = new LinkedList<>();
keunyoungca515072015-07-10 12:21:47 -070087 /** key: sensor type. */
88 @GuardedBy("mSensorLock")
89 private final SparseArray<SensorListeners> mSensorListeners = new SparseArray<>();
90 /** key: sensor type. */
91 @GuardedBy("mSensorLock")
92 private final SparseArray<SensorRecord> mSensorRecords = new SparseArray<>();
93
keunyoungcc449f72015-08-12 10:46:27 -070094 private final SensorHalService mSensorHal;
keunyoungca515072015-07-10 12:21:47 -070095 private int[] mCarProvidedSensors;
96 private int[] mSupportedSensors;
97 private final AtomicBoolean mSensorDiscovered = new AtomicBoolean(false);
98
99 private final Context mContext;
100
101 private final DrivingStatePolicy mDrivingStatePolicy;
keunyoungcc449f72015-08-12 10:46:27 -0700102 private boolean mUseDefaultDrivingPolicy = true;
keunyoungca515072015-07-10 12:21:47 -0700103 private final DayNightModePolicy mDayNightModePolicy;
keunyoungcc449f72015-08-12 10:46:27 -0700104 private boolean mUseDefaultDayNightModePolicy = true;
105
106 private final HandlerThread mHandlerThread;
107 private final SensorDispatchHandler mSensorDispatchHandler;
keunyoungca515072015-07-10 12:21:47 -0700108
109 public CarSensorService(Context context) {
110 mContext = context;
keunyoungfe30ba02015-09-17 17:56:35 -0700111 if (ENABLE_DISPATCHING_LIMIT) {
112 mHandlerThread = new HandlerThread("SENSOR", Process.THREAD_PRIORITY_AUDIO);
113 mHandlerThread.start();
114 mSensorDispatchHandler = new SensorDispatchHandler(mHandlerThread.getLooper());
115 } else {
116 mHandlerThread = null;
117 mSensorDispatchHandler = null;
118 }
keunyoungca515072015-07-10 12:21:47 -0700119 // This triggers sensor hal init as well.
keunyoungfe30ba02015-09-17 17:56:35 -0700120 mSensorHal = VehicleHal.getInstance().getSensorHal();
keunyoungca515072015-07-10 12:21:47 -0700121 mDrivingStatePolicy = new DrivingStatePolicy(context);
122 mDayNightModePolicy = new DayNightModePolicy(context);
123 }
124
125 @Override
126 public void init() {
keunyoungca515072015-07-10 12:21:47 -0700127 mSensorLock.lock();
128 try {
Keun-young Park9ec05472016-04-26 21:18:18 -0700129 mSensorHal.registerSensorListener(this);
130 mCarProvidedSensors = mSensorHal.getSupportedSensors();
keunyoungca515072015-07-10 12:21:47 -0700131 mSupportedSensors = refreshSupportedSensorsLocked();
Keun-young Park05f44812016-02-10 15:32:48 -0800132 CarSensorEvent event = null;
keunyoungcc449f72015-08-12 10:46:27 -0700133 if (mUseDefaultDrivingPolicy) {
134 mDrivingStatePolicy.init();
keunyoungcc449f72015-08-12 10:46:27 -0700135 mDrivingStatePolicy.registerSensorListener(this);
Keun-young Park05f44812016-02-10 15:32:48 -0800136 } else {
137 event = mSensorHal.getCurrentSensorValue(
138 CarSensorManager.SENSOR_TYPE_DRIVING_STATUS);
Keun-young Park9ec05472016-04-26 21:18:18 -0700139 Log.i(CarLog.TAG_SENSOR, "initial driving status:" + ((event == null)?
140 "not ready" : " 0x" + Integer.toHexString(event.intValues[0])));
Keun-young Park05f44812016-02-10 15:32:48 -0800141 }
142 if (event == null) {
143 event = DrivingStatePolicy.getDefaultValue(
144 CarSensorManager.SENSOR_TYPE_DRIVING_STATUS);
Keun-young Park9ec05472016-04-26 21:18:18 -0700145 if (!mUseDefaultDrivingPolicy) {
146 Log.w(CarLog.TAG_SENSOR, "Default driving status set as sensor not ready");
147 }
keunyoungcc449f72015-08-12 10:46:27 -0700148 }
keunyoung1ab8e182015-09-24 09:25:22 -0700149 // always populate default value
Keun-young Park05f44812016-02-10 15:32:48 -0800150 addNewSensorRecordLocked(CarSensorManager.SENSOR_TYPE_DRIVING_STATUS, event);
151 event = null;
keunyoungcc449f72015-08-12 10:46:27 -0700152 if (mUseDefaultDayNightModePolicy) {
153 mDayNightModePolicy.init();
keunyoungcc449f72015-08-12 10:46:27 -0700154 mDayNightModePolicy.registerSensorListener(this);
Keun-young Park05f44812016-02-10 15:32:48 -0800155 } else {
156 event = mSensorHal.getCurrentSensorValue(CarSensorManager.SENSOR_TYPE_NIGHT);
Keun-young Park9ec05472016-04-26 21:18:18 -0700157 Log.i(CarLog.TAG_SENSOR, "initial daynight:" + ((event == null)?
158 "not ready" : + event.intValues[0]));
Keun-young Park05f44812016-02-10 15:32:48 -0800159 }
160 if (event == null) {
161 event = DayNightModePolicy.getDefaultValue(CarSensorManager.SENSOR_TYPE_NIGHT);
Keun-young Park9ec05472016-04-26 21:18:18 -0700162 if (!mUseDefaultDayNightModePolicy) {
163 Log.w(CarLog.TAG_SENSOR, "Default daynight set as sensor not ready");
164 }
keunyoungcc449f72015-08-12 10:46:27 -0700165 }
keunyoung1ab8e182015-09-24 09:25:22 -0700166 // always populate default value
Keun-young Park05f44812016-02-10 15:32:48 -0800167 addNewSensorRecordLocked(CarSensorManager.SENSOR_TYPE_NIGHT, event);
Keun-young Park9ec05472016-04-26 21:18:18 -0700168 notifyDefaultPoliciesLocked();
keunyoungca515072015-07-10 12:21:47 -0700169 } finally {
170 mSensorLock.unlock();
171 }
keunyoungca515072015-07-10 12:21:47 -0700172 }
173
174 private void addNewSensorRecordLocked(int type, CarSensorEvent event) {
175 SensorRecord record = new SensorRecord();
176 record.lastEvent = event;
177 mSensorRecords.put(type,record);
178 }
179
180 @Override
181 public void release() {
keunyoung1ab8e182015-09-24 09:25:22 -0700182 if (mHandlerThread != null) {
183 mHandlerThread.quit();
184 }
keunyoungca515072015-07-10 12:21:47 -0700185 tryHoldSensorLock();
186 try {
keunyoungcc449f72015-08-12 10:46:27 -0700187 if (mUseDefaultDrivingPolicy) {
188 mDrivingStatePolicy.release();
189 }
190 if (mUseDefaultDayNightModePolicy) {
191 mDayNightModePolicy.release();
192 }
keunyoungca515072015-07-10 12:21:47 -0700193 for (int i = mSensorListeners.size() - 1; i >= 0; --i) {
194 SensorListeners listener = mSensorListeners.valueAt(i);
195 listener.release();
196 }
197 mSensorListeners.clear();
198 mSensorRecords.clear();
199 mClients.clear();
200 } finally {
201 releaseSensorLockSafely();
202 }
203 }
204
205 private void tryHoldSensorLock() {
206 try {
207 mSensorLock.tryLock(MAX_SENSOR_LOCK_WAIT_MS, TimeUnit.MILLISECONDS);
208 } catch (InterruptedException e) {
209 //ignore
210 }
211 }
212
213 private void releaseSensorLockSafely() {
214 if (mSensorLock.isHeldByCurrentThread()) {
215 mSensorLock.unlock();
216 }
217 }
218
Keun-young Park9ec05472016-04-26 21:18:18 -0700219 private void notifyDefaultPoliciesLocked() {
220 if (mUseDefaultDrivingPolicy) {
221 mDrivingStatePolicy.onSensorServiceReady();
222 }
223 if (mUseDefaultDayNightModePolicy) {
224 mDayNightModePolicy.onSensorServiceReady();
keunyoungca515072015-07-10 12:21:47 -0700225 }
226 }
227
keunyoungcc449f72015-08-12 10:46:27 -0700228 private void processSensorData(List<CarSensorEvent> events) {
229 mSensorLock.lock();
230 for (CarSensorEvent event: events) {
231 SensorRecord record = mSensorRecords.get(event.sensorType);
232 if (record != null) {
233 if (record.lastEvent == null) {
234 record.lastEvent = event;
Jason Tholstrupd72b5352016-09-22 16:32:14 -0700235 } else if (record.lastEvent.timestamp < event.timestamp) {
keunyoungcc449f72015-08-12 10:46:27 -0700236 record.lastEvent = event;
237 //TODO recycle event
238 } else { // wrong timestamp, throw away this.
239 //TODO recycle new event
240 continue;
241 }
242 SensorListeners listeners = mSensorListeners.get(event.sensorType);
243 if (listeners != null) {
244 listeners.queueSensorEvent(event);
245 }
keunyoungca515072015-07-10 12:21:47 -0700246 }
247 }
Keun-young Park901392c2016-05-06 14:50:11 -0700248 mClientDispatchList.addAll(mClients);
249 mSensorLock.unlock();
250 for (SensorClient client: mClientDispatchList) {
keunyoungcc449f72015-08-12 10:46:27 -0700251 client.dispatchSensorUpdate();
keunyoungca515072015-07-10 12:21:47 -0700252 }
Keun-young Park901392c2016-05-06 14:50:11 -0700253 mClientDispatchList.clear();
keunyoungca515072015-07-10 12:21:47 -0700254 }
255
256 /**
257 * Received sensor data from car.
258 *
259 * @param event
260 */
261 @Override
keunyoungcc449f72015-08-12 10:46:27 -0700262 public void onSensorEvents(List<CarSensorEvent> events) {
keunyoungfe30ba02015-09-17 17:56:35 -0700263 if (ENABLE_DISPATCHING_LIMIT) {
264 mSensorDispatchHandler.handleSensorEvents(events);
265 } else {
266 processSensorData(events);
267 }
keunyoungca515072015-07-10 12:21:47 -0700268 }
269
270 @Override
271 public int[] getSupportedSensors() {
Vitalii Tomkiva8386362016-07-29 12:27:25 -0700272 mSensorLock.lock();
Vitalii Tomkivbb051042016-07-27 17:13:24 -0700273 int[] supportedSensors = mSupportedSensors;
Vitalii Tomkiva8386362016-07-29 12:27:25 -0700274 mSensorLock.unlock();
Vitalii Tomkivbb051042016-07-27 17:13:24 -0700275 return supportedSensors;
keunyoungca515072015-07-10 12:21:47 -0700276 }
277
keunyoungca515072015-07-10 12:21:47 -0700278 @Override
279 public boolean registerOrUpdateSensorListener(int sensorType, int rate,
Keun-young Parke54ac272016-02-16 19:02:18 -0800280 ICarSensorEventListener listener) {
keunyoungca515072015-07-10 12:21:47 -0700281 boolean shouldStartSensors = false;
282 SensorRecord sensorRecord = null;
283 SensorClient sensorClient = null;
284 Integer oldRate = null;
285 SensorListeners sensorListeners = null;
286 mSensorLock.lock();
287 try {
288 sensorRecord = mSensorRecords.get(sensorType);
289 if (sensorRecord == null) {
290 if (Log.isLoggable(CarLog.TAG_SENSOR, Log.INFO)) {
291 Log.i(CarLog.TAG_SENSOR, "Requested sensor " + sensorType + " not supported");
292 }
293 return false;
294 }
295 if (Binder.getCallingUid() != Process.myUid()) {
296 switch (getSensorPermission(sensorType)) {
297 case PackageManager.PERMISSION_DENIED:
298 throw new SecurityException("client does not have permission:"
299 + getPermissionName(sensorType)
300 + " pid:" + Binder.getCallingPid()
301 + " uid:" + Binder.getCallingUid());
302 case PackageManager.PERMISSION_GRANTED:
303 break;
304 }
305 }
306 if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
307 Log.d(CarLog.TAG_SENSOR, "registerOrUpdateSensorListener " + sensorType + " " +
308 listener);
309 }
310 sensorClient = findSensorClientLocked(listener);
311 SensorClientWithRate sensorClientWithRate = null;
312 sensorListeners = mSensorListeners.get(sensorType);
313 if (sensorClient == null) {
314 sensorClient = new SensorClient(listener);
315 try {
316 listener.asBinder().linkToDeath(sensorClient, 0);
317 } catch (RemoteException e) {
318 if (Log.isLoggable(CarLog.TAG_SENSOR, Log.INFO)) {
319 Log.i(CarLog.TAG_SENSOR, "Adding listener failed.");
320 }
321 return false;
322 }
323 mClients.add(sensorClient);
324 }
325 // If we have a cached event for this sensor, send the event.
326 SensorRecord record = mSensorRecords.get(sensorType);
327 if (record != null && record.lastEvent != null) {
keunyoungcc449f72015-08-12 10:46:27 -0700328 sensorClient.queueSensorEvent(record.lastEvent);
329 sensorClient.dispatchSensorUpdate();
keunyoungca515072015-07-10 12:21:47 -0700330 }
331 if (sensorListeners == null) {
332 sensorListeners = new SensorListeners(rate);
333 mSensorListeners.put(sensorType, sensorListeners);
keunyoungcc449f72015-08-12 10:46:27 -0700334 shouldStartSensors = true;
keunyoungca515072015-07-10 12:21:47 -0700335 } else {
336 oldRate = Integer.valueOf(sensorListeners.getRate());
337 sensorClientWithRate = sensorListeners.findSensorClientWithRate(sensorClient);
338 }
339 if (sensorClientWithRate == null) {
340 sensorClientWithRate = new SensorClientWithRate(sensorClient, rate);
341 sensorListeners.addSensorClientWithRate(sensorClientWithRate);
342 } else {
343 sensorClientWithRate.setRate(rate);
344 }
345 if (sensorListeners.getRate() > rate) {
346 sensorListeners.setRate(rate);
keunyoungcc449f72015-08-12 10:46:27 -0700347 shouldStartSensors = sensorSupportRate(sensorType);
keunyoungca515072015-07-10 12:21:47 -0700348 }
349 sensorClient.addSensor(sensorType);
350 } finally {
351 mSensorLock.unlock();
352 }
353 // start sensor outside lock as it can take time.
354 if (shouldStartSensors) {
355 if (!startSensor(sensorRecord, sensorType, rate)) {
356 // failed. so remove from active sensor list.
357 mSensorLock.lock();
358 try {
359 sensorClient.removeSensor(sensorType);
360 if (oldRate != null) {
361 sensorListeners.setRate(oldRate);
362 } else {
363 mSensorListeners.remove(sensorType);
364 }
365 } finally {
366 mSensorLock.unlock();
367 }
368 return false;
369 }
370 }
371 return true;
372 }
373
keunyoungcc449f72015-08-12 10:46:27 -0700374 private boolean sensorSupportRate(int sensorType) {
375 switch (sensorType) {
keunyoungcc449f72015-08-12 10:46:27 -0700376 case CarSensorManager.SENSOR_TYPE_CAR_SPEED:
377 case CarSensorManager.SENSOR_TYPE_RPM:
keunyoungcc449f72015-08-12 10:46:27 -0700378 return true;
379 case CarSensorManager.SENSOR_TYPE_ODOMETER:
380 case CarSensorManager.SENSOR_TYPE_FUEL_LEVEL:
381 case CarSensorManager.SENSOR_TYPE_PARKING_BRAKE:
382 case CarSensorManager.SENSOR_TYPE_GEAR:
383 case CarSensorManager.SENSOR_TYPE_NIGHT:
384 case CarSensorManager.SENSOR_TYPE_DRIVING_STATUS:
385 case CarSensorManager.SENSOR_TYPE_ENVIRONMENT:
386 return false;
387 default:
388 Log.w(CarLog.TAG_SENSOR, "sensorSupportRate not listed sensor:" + sensorType);
389 return false;
390 }
391 }
392
keunyoungca515072015-07-10 12:21:47 -0700393 private int getSensorPermission(int sensorType) {
394 String permission = getPermissionName(sensorType);
395 int result = PackageManager.PERMISSION_GRANTED;
396 if (permission != null) {
Keun-young Park064ddd82015-12-21 23:57:50 +0000397 return mContext.checkCallingOrSelfPermission(permission);
keunyoungca515072015-07-10 12:21:47 -0700398 }
399 // If no permission is required, return granted.
400 return result;
401 }
402
keunyoungfe30ba02015-09-17 17:56:35 -0700403 //TODO handle per property OEM permission
keunyoungca515072015-07-10 12:21:47 -0700404 private String getPermissionName(int sensorType) {
Keun-young Park064ddd82015-12-21 23:57:50 +0000405 if ((sensorType >= CarSensorManager.SENSOR_TYPE_VENDOR_EXTENSION_START) &&
406 (sensorType >= CarSensorManager.SENSOR_TYPE_VENDOR_EXTENSION_END)) {
407 return Car.PERMISSION_VENDOR_EXTENSION;
408 }
keunyoungca515072015-07-10 12:21:47 -0700409 String permission = null;
410 switch (sensorType) {
keunyoungca515072015-07-10 12:21:47 -0700411 case CarSensorManager.SENSOR_TYPE_CAR_SPEED:
412 permission = Car.PERMISSION_SPEED;
413 break;
414 case CarSensorManager.SENSOR_TYPE_ODOMETER:
415 permission = Car.PERMISSION_MILEAGE;
416 break;
417 case CarSensorManager.SENSOR_TYPE_FUEL_LEVEL:
418 permission = Car.PERMISSION_FUEL;
419 break;
420 default:
421 break;
422 }
423 return permission;
424 }
425
426 private boolean startSensor(SensorRecord record, int sensorType, int rate) {
427 //TODO choose proper sensor rate per each sensor.
428 //Some sensors which report only when there is change should be always set with maximum
429 //rate. For now, set every sensor to the maximum.
430 if (Log.isLoggable(CarLog.TAG_SENSOR, Log.VERBOSE)) {
431 Log.v(CarLog.TAG_SENSOR, "startSensor " + sensorType + " with rate " + rate);
432 }
keunyoungcc449f72015-08-12 10:46:27 -0700433 SensorHalServiceBase sensorHal = getSensorHal(sensorType);
keunyoungca515072015-07-10 12:21:47 -0700434 if (sensorHal != null) {
435 if (!sensorHal.isReady()) {
436 Log.w(CarLog.TAG_SENSOR, "Sensor channel not available.");
437 return false;
438 }
439 if (record.enabled) {
440 return true;
441 }
442 if (sensorHal.requestSensorStart(sensorType, 0)) {
443 record.enabled = true;
444 return true;
445 }
446 }
Keun-young Park05f44812016-02-10 15:32:48 -0800447 Log.w(CarLog.TAG_SENSOR, "requestSensorStart failed, sensor type:" + sensorType);
keunyoungca515072015-07-10 12:21:47 -0700448 return false;
449 }
450
451 @Override
452 public void unregisterSensorListener(int sensorType, ICarSensorEventListener listener) {
453 boolean shouldStopSensor = false;
454 boolean shouldRestartSensor = false;
455 SensorRecord record = null;
456 int newRate = 0;
457 mSensorLock.lock();
458 try {
459 record = mSensorRecords.get(sensorType);
460 if (record == null) {
461 // unregister not supported sensor. ignore.
462 if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
463 Log.d(CarLog.TAG_SENSOR, "unregister for unsupported sensor");
464 }
465 return;
466 }
467 SensorClient sensorClient = findSensorClientLocked(listener);
468 if (sensorClient == null) {
469 // never registered or already unregistered.
470 if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
471 Log.d(CarLog.TAG_SENSOR, "unregister for not existing client");
472 }
473 return;
474 }
475 sensorClient.removeSensor(sensorType);
476 if (sensorClient.getNumberOfActiveSensor() == 0) {
477 sensorClient.release();
478 mClients.remove(sensorClient);
479 }
480 SensorListeners sensorListeners = mSensorListeners.get(sensorType);
481 if (sensorListeners == null) {
482 // sensor not active
483 if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
484 Log.d(CarLog.TAG_SENSOR, "unregister for non-active sensor");
485 }
486 return;
487 }
488 SensorClientWithRate clientWithRate =
489 sensorListeners.findSensorClientWithRate(sensorClient);
490 if (clientWithRate == null) {
491 if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
492 Log.d(CarLog.TAG_SENSOR, "unregister for not registered sensor");
493 }
494 return;
495 }
496 sensorListeners.removeSensorClientWithRate(clientWithRate);
497 if (sensorListeners.getNumberOfClients() == 0) {
keunyoungcc449f72015-08-12 10:46:27 -0700498 shouldStopSensor = true;
keunyoungca515072015-07-10 12:21:47 -0700499 mSensorListeners.remove(sensorType);
500 } else if (sensorListeners.updateRate()) { // rate changed
501 newRate = sensorListeners.getRate();
keunyoungcc449f72015-08-12 10:46:27 -0700502 shouldRestartSensor = sensorSupportRate(sensorType);
keunyoungca515072015-07-10 12:21:47 -0700503 }
504 if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
505 Log.d(CarLog.TAG_SENSOR, "unregister succeeded");
506 }
507 } finally {
508 mSensorLock.unlock();
509 }
510 if (shouldStopSensor) {
511 stopSensor(record, sensorType);
512 } else if (shouldRestartSensor) {
513 startSensor(record, sensorType, newRate);
514 }
515 }
516
517 private void stopSensor(SensorRecord record, int sensorType) {
518 if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
519 Log.d(CarLog.TAG_SENSOR, "stopSensor " + sensorType);
520 }
keunyoungcc449f72015-08-12 10:46:27 -0700521 SensorHalServiceBase sensorHal = getSensorHal(sensorType);
keunyoungca515072015-07-10 12:21:47 -0700522 if (sensorHal == null || !sensorHal.isReady()) {
523 Log.w(CarLog.TAG_SENSOR, "Sensor channel not available.");
524 return;
525 }
526 if (!record.enabled) {
527 return;
528 }
529 record.enabled = false;
530 // make lastEvent invalid as old data can be sent to client when subscription is restarted
531 // later.
532 record.lastEvent = null;
533 if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
534 Log.d(CarLog.TAG_SENSOR, "stopSensor requestStop " + sensorType);
535 }
536 sensorHal.requestSensorStop(sensorType);
537 }
538
keunyoungcc449f72015-08-12 10:46:27 -0700539 private SensorHalServiceBase getSensorHal(int sensorType) {
540 try {
541 mSensorLock.lock();
542 switch (sensorType) {
543 case CarSensorManager.SENSOR_TYPE_DRIVING_STATUS:
544 if (mUseDefaultDrivingPolicy) {
545 return mDrivingStatePolicy;
546 }
547 break;
548 case CarSensorManager.SENSOR_TYPE_NIGHT:
549 if (mUseDefaultDayNightModePolicy) {
550 return mDayNightModePolicy;
551 }
552 break;
553 }
554 return mSensorHal;
555 } finally {
556 mSensorLock.unlock();
keunyoungca515072015-07-10 12:21:47 -0700557 }
558 }
559
560 @Override
561 public CarSensorEvent getLatestSensorEvent(int sensorType) {
562 SensorRecord record = null;
563 mSensorLock.lock();
564 try {
565 record = mSensorRecords.get(sensorType);
566 } finally {
567 mSensorLock.unlock();
568 }
569 if (record != null) {
570 return record.lastEvent;
571 }
572 return null;
573 }
574
575 private int[] refreshSupportedSensorsLocked() {
576 int numCarSensors = (mCarProvidedSensors == null) ? 0 : mCarProvidedSensors.length;
keunyoungcc449f72015-08-12 10:46:27 -0700577 for (int i = 0; i < numCarSensors; i++) {
578 int sensor = mCarProvidedSensors[i];
579 if (sensor == CarSensorManager.SENSOR_TYPE_DRIVING_STATUS) {
580 mUseDefaultDrivingPolicy = false;
581 } else if (sensor == CarSensorManager.SENSOR_TYPE_NIGHT) {
582 mUseDefaultDayNightModePolicy = false;
583 }
584 }
585 int totalNumSensors = numCarSensors;
586 if (mUseDefaultDrivingPolicy) {
587 totalNumSensors++;
588 }
589 if (mUseDefaultDayNightModePolicy) {
590 totalNumSensors++;
591 }
keunyoungca515072015-07-10 12:21:47 -0700592 // Two logical sensors are always added.
keunyoungcc449f72015-08-12 10:46:27 -0700593 int[] supportedSensors = new int[totalNumSensors];
keunyoungca515072015-07-10 12:21:47 -0700594 int index = 0;
keunyoungcc449f72015-08-12 10:46:27 -0700595 if (mUseDefaultDrivingPolicy) {
596 supportedSensors[index] = CarSensorManager.SENSOR_TYPE_DRIVING_STATUS;
597 index++;
598 }
599 if (mUseDefaultDayNightModePolicy) {
600 supportedSensors[index] = CarSensorManager.SENSOR_TYPE_NIGHT;
601 index++;
602 }
keunyoungca515072015-07-10 12:21:47 -0700603
604 for (int i = 0; i < numCarSensors; i++) {
605 int sensor = mCarProvidedSensors[i];
keunyoungcc449f72015-08-12 10:46:27 -0700606
keunyoungca515072015-07-10 12:21:47 -0700607 if (mSensorRecords.get(sensor) == null) {
608 SensorRecord record = new SensorRecord();
609 mSensorRecords.put(sensor, record);
610 }
611 supportedSensors[index] = sensor;
612 index++;
613 }
614
615 return supportedSensors;
616 }
617
618 private boolean isSensorRealLocked(int sensorType) {
619 if (mCarProvidedSensors != null) {
620 for (int sensor : mCarProvidedSensors) {
621 if (sensor == sensorType ) {
622 return true;
623 }
624 }
625 }
626 return false;
627 }
628
keunyoungca515072015-07-10 12:21:47 -0700629 /**
630 * Find SensorClient from client list and return it.
631 * This should be called with mClients locked.
632 * @param listener
633 * @return null if not found.
634 */
635 private SensorClient findSensorClientLocked(ICarSensorEventListener listener) {
636 IBinder binder = listener.asBinder();
637 for (SensorClient sensorClient : mClients) {
638 if (sensorClient.isHoldingListernerBinder(binder)) {
639 return sensorClient;
640 }
641 }
642 return null;
643 }
644
645 private void removeClient(SensorClient sensorClient) {
646 mSensorLock.lock();
647 try {
648 for (int sensor: sensorClient.getSensorArray()) {
649 unregisterSensorListener(sensor,
650 sensorClient.getICarSensorEventListener());
651 }
652 mClients.remove(sensorClient);
653 } finally {
654 mSensorLock.unlock();
655 }
656 }
657
keunyoungcc449f72015-08-12 10:46:27 -0700658 private class SensorDispatchHandler extends Handler {
659 private static final long SENSOR_DISPATCH_MIN_INTERVAL_MS = 16; // over 60Hz
660
661 private static final int MSG_SENSOR_DATA = 0;
662
663 private long mLastSensorDispatchTime = -1;
664 private int mFreeListIndex = 0;
665 private final LinkedList<CarSensorEvent>[] mSensorDataList = new LinkedList[2];
666
667 private SensorDispatchHandler(Looper looper) {
668 super(looper);
669 for (int i = 0; i < mSensorDataList.length; i++) {
670 mSensorDataList[i] = new LinkedList<CarSensorEvent>();
671 }
672 }
673
674 private synchronized void handleSensorEvents(List<CarSensorEvent> data) {
675 LinkedList<CarSensorEvent> list = mSensorDataList[mFreeListIndex];
676 list.addAll(data);
677 requestDispatchLocked();
678 }
679
680 private synchronized void handleSensorEvent(CarSensorEvent event) {
681 LinkedList<CarSensorEvent> list = mSensorDataList[mFreeListIndex];
682 list.add(event);
683 requestDispatchLocked();
684 }
685
686 private void requestDispatchLocked() {
687 Message msg = obtainMessage(MSG_SENSOR_DATA);
688 long now = SystemClock.uptimeMillis();
689 long delta = now - mLastSensorDispatchTime;
690 if (delta > SENSOR_DISPATCH_MIN_INTERVAL_MS) {
691 sendMessage(msg);
692 } else {
693 sendMessageDelayed(msg, SENSOR_DISPATCH_MIN_INTERVAL_MS - delta);
694 }
695 }
696
697 @Override
698 public void handleMessage(Message msg) {
699 switch (msg.what) {
700 case MSG_SENSOR_DATA:
701 doHandleSensorData();
702 break;
703 default:
704 break;
705 }
706 }
707
708 private void doHandleSensorData() {
709 List<CarSensorEvent> listToDispatch = null;
710 synchronized (this) {
711 mLastSensorDispatchTime = SystemClock.uptimeMillis();
712 int nonFreeListIndex = mFreeListIndex ^ 0x1;
713 List<CarSensorEvent> nonFreeList = mSensorDataList[nonFreeListIndex];
714 List<CarSensorEvent> freeList = mSensorDataList[mFreeListIndex];
715 if (nonFreeList.size() > 0) {
716 Log.w(CarLog.TAG_SENSOR, "non free list not empty");
717 // copy again, but this should not be normal case
718 nonFreeList.addAll(freeList);
719 listToDispatch = nonFreeList;
720 freeList.clear();
721 } else if (freeList.size() > 0) {
722 listToDispatch = freeList;
723 mFreeListIndex = nonFreeListIndex;
724 }
725 }
726 // leave this part outside lock so that time-taking dispatching can be done without
727 // blocking sensor event notification.
728 if (listToDispatch != null) {
729 processSensorData(listToDispatch);
730 listToDispatch.clear();
731 }
732 }
733
734 }
735
keunyoungca515072015-07-10 12:21:47 -0700736 /** internal instance for pending client request */
737 private class SensorClient implements IBinder.DeathRecipient {
738 /** callback for sensor events */
739 private final ICarSensorEventListener mListener;
740 private final SparseBooleanArray mActiveSensors = new SparseBooleanArray();
keunyoungcc449f72015-08-12 10:46:27 -0700741 private final LinkedList<CarSensorEvent> mSensorsToDispatch =
742 new LinkedList<CarSensorEvent>();
keunyoungca515072015-07-10 12:21:47 -0700743
744 /** when false, it is already released */
745 private volatile boolean mActive = true;
746
747 SensorClient(ICarSensorEventListener listener) {
748 this.mListener = listener;
749 }
750
751 @Override
752 public boolean equals(Object o) {
753 if (o instanceof SensorClient &&
754 mListener.asBinder() == ((SensorClient) o).mListener.asBinder()) {
755 return true;
756 }
757 return false;
758 }
759
760 boolean isHoldingListernerBinder(IBinder listenerBinder) {
761 return mListener.asBinder() == listenerBinder;
762 }
763
764 void addSensor(int sensor) {
765 mActiveSensors.put(sensor, true);
766 }
767
768 void removeSensor(int sensor) {
769 mActiveSensors.delete(sensor);
770 }
771
772 int getNumberOfActiveSensor() {
773 return mActiveSensors.size();
774 }
775
776 int[] getSensorArray() {
777 int[] sensors = new int[mActiveSensors.size()];
778 for (int i = sensors.length - 1; i >= 0; --i) {
779 sensors[i] = mActiveSensors.keyAt(i);
780 }
781 return sensors;
782 }
783
784 ICarSensorEventListener getICarSensorEventListener() {
785 return mListener;
786 }
787
788 /**
789 * Client dead. should remove all sensor requests from client
790 */
791 @Override
792 public void binderDied() {
793 mListener.asBinder().unlinkToDeath(this, 0);
794 removeClient(this);
795 }
796
keunyoungcc449f72015-08-12 10:46:27 -0700797 void queueSensorEvent(CarSensorEvent event) {
798 mSensorsToDispatch.add(event);
799 }
800
801 void dispatchSensorUpdate() {
802 if (mSensorsToDispatch.size() == 0) {
803 return;
keunyoungca515072015-07-10 12:21:47 -0700804 }
keunyoungcc449f72015-08-12 10:46:27 -0700805 if (mActive) {
806 try {
807 mListener.onSensorChanged(mSensorsToDispatch);
808 } catch (RemoteException e) {
809 //ignore. crash will be handled by death handler
810 }
811 } else {
812 if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
813 Log.d(CarLog.TAG_SENSOR, "sensor update while client is already released");
814 }
815 }
816 mSensorsToDispatch.clear();
keunyoungca515072015-07-10 12:21:47 -0700817 }
818
819 void release() {
820 if (mActive) {
821 mListener.asBinder().unlinkToDeath(this, 0);
822 mActiveSensors.clear();
keunyoungcc449f72015-08-12 10:46:27 -0700823 mSensorsToDispatch.clear();
keunyoungca515072015-07-10 12:21:47 -0700824 mActive = false;
825 }
826 }
827 }
828
829 private class SensorClientWithRate {
830 private final SensorClient mSensorClient;
831 /** rate requested from client */
832 private int mRate;
833
834 SensorClientWithRate(SensorClient client, int rate) {
835 mSensorClient = client;
836 mRate = rate;
837 }
838
839 @Override
840 public boolean equals(Object o) {
841 if (o instanceof SensorClientWithRate &&
842 mSensorClient == ((SensorClientWithRate) o).mSensorClient) {
843 return true;
844 }
845 return false;
846 }
847
848 int getRate() {
849 return mRate;
850 }
851
852 void setRate(int rate) {
853 mRate = rate;
854 }
855
856 SensorClient getSensorClient() {
857 return mSensorClient;
858 }
859 }
860
861 private static class SensorRecord {
862 /** Record the lastly received sensor event */
863 CarSensorEvent lastEvent = null;
864 /** sensor was enabled by at least one client */
865 boolean enabled = false;
866 }
867
868 private static class SensorListeners {
869 private final LinkedList<SensorClientWithRate> mSensorClients =
870 new LinkedList<SensorClientWithRate>();
871 /** rate for this sensor, sent to car */
872 private int mRate;
873
874 SensorListeners(int rate) {
875 mRate = rate;
876 }
877
878 int getRate() {
879 return mRate;
880 }
881
882 void setRate(int rate) {
883 mRate = rate;
884 }
885
886 /** update rate from existing clients and return true if rate is changed. */
887 boolean updateRate() {
888 int fastestRate = CarSensorManager.SENSOR_RATE_NORMAL;
889 for (SensorClientWithRate clientWithRate: mSensorClients) {
890 int clientRate = clientWithRate.getRate();
891 if (clientRate < fastestRate) {
892 fastestRate = clientRate;
893 }
894 }
895 if (mRate != fastestRate) {
896 mRate = fastestRate;
897 return true;
898 }
899 return false;
900 }
901
902 void addSensorClientWithRate(SensorClientWithRate clientWithRate) {
903 mSensorClients.add(clientWithRate);
904 }
905
906 void removeSensorClientWithRate(SensorClientWithRate clientWithRate) {
907 mSensorClients.remove(clientWithRate);
908 }
909
910 int getNumberOfClients() {
911 return mSensorClients.size();
912 }
913
914 SensorClientWithRate findSensorClientWithRate(SensorClient sensorClient) {
915 for (SensorClientWithRate clientWithRates: mSensorClients) {
916 if (clientWithRates.getSensorClient() == sensorClient) {
917 return clientWithRates;
918 }
919 }
920 return null;
921 }
922
keunyoungcc449f72015-08-12 10:46:27 -0700923 void queueSensorEvent(CarSensorEvent event) {
keunyoungca515072015-07-10 12:21:47 -0700924 for (SensorClientWithRate clientWithRate: mSensorClients) {
keunyoungcc449f72015-08-12 10:46:27 -0700925 clientWithRate.getSensorClient().queueSensorEvent(event);
keunyoungca515072015-07-10 12:21:47 -0700926 }
927 }
928
929 void release() {
930 for (SensorClientWithRate clientWithRate: mSensorClients) {
931 clientWithRate.mSensorClient.release();
932 }
933 mSensorClients.clear();
934 }
935 }
936
937 @Override
938 public void dump(PrintWriter writer) {
keunyounga3b28d82015-08-25 13:05:15 -0700939 writer.println("*CarSensorService*");
keunyoungca515072015-07-10 12:21:47 -0700940 writer.println("supported sensors:" + Arrays.toString(mSupportedSensors));
941 writer.println("**last events for sensors**");
942 if (mSensorRecords != null) {
943 try {
944 int sensorRecordSize = mSensorRecords.size();
945 for (int i = 0; i < sensorRecordSize; i++) {
946 int sensor = mSensorRecords.keyAt(i);
947 SensorRecord record = mSensorRecords.get(sensor);
948 if (record != null && record.lastEvent != null) {
949 writer.println("sensor: " + sensor
950 + " active: " + record.enabled);
Keun-young Park4afc6ee2016-03-04 18:18:19 -0800951 writer.println(" " + record.lastEvent.toString());
keunyoungca515072015-07-10 12:21:47 -0700952 }
953 SensorListeners listeners = mSensorListeners.get(sensor);
954 if (listeners != null) {
955 writer.println(" rate: " + listeners.getRate());
956 }
957 }
958 } catch (ConcurrentModificationException e) {
959 writer.println("concurrent modification happened");
960 }
961 } else {
962 writer.println("null records");
963 }
964 writer.println("**clients**");
965 try {
966 for (SensorClient client: mClients) {
967 if (client != null) {
968 try {
969 writer.println("binder:" + client.mListener
970 + " active sensors:" + Arrays.toString(client.getSensorArray()));
971 } catch (ConcurrentModificationException e) {
972 writer.println("concurrent modification happened");
973 }
974 } else {
975 writer.println("null client");
976 }
977 }
978 } catch (ConcurrentModificationException e) {
979 writer.println("concurrent modification happened");
980 }
981 writer.println("**sensor listeners**");
982 try {
983 int sensorListenerSize = mSensorListeners.size();
984 for (int i = 0; i < sensorListenerSize; i++) {
985 int sensor = mSensorListeners.keyAt(i);
986 SensorListeners sensorListeners = mSensorListeners.get(sensor);
987 if (sensorListeners != null) {
988 writer.println(" Sensor:" + sensor
989 + " num client:" + sensorListeners.getNumberOfClients()
990 + " rate:" + sensorListeners.getRate());
991 }
992 }
993 } catch (ConcurrentModificationException e) {
994 writer.println("concurrent modification happened");
995 }
Keun-young Park9ec05472016-04-26 21:18:18 -0700996 writer.println("mUseDefaultDrivingPolicy:" + mUseDefaultDrivingPolicy +
997 ",mUseDefaultDayNightModePolicy" + mUseDefaultDayNightModePolicy);
keunyoungca515072015-07-10 12:21:47 -0700998 writer.println("**driving policy**");
keunyoungcc449f72015-08-12 10:46:27 -0700999 if (mUseDefaultDrivingPolicy) {
1000 mDrivingStatePolicy.dump(writer);
1001 }
keunyoungca515072015-07-10 12:21:47 -07001002 writer.println("**day/night policy**");
keunyoungcc449f72015-08-12 10:46:27 -07001003 if (mUseDefaultDayNightModePolicy) {
1004 mDayNightModePolicy.dump(writer);
1005 }
keunyoungca515072015-07-10 12:21:47 -07001006 }
1007}