1/* 2 * Copyright (C) 2017 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.test; 18 19import static java.lang.Integer.toHexString; 20 21import android.car.Car; 22import android.car.hardware.CarDiagnosticEvent; 23import android.car.hardware.CarDiagnosticEvent.FuelSystemStatus; 24import android.car.hardware.CarDiagnosticEvent.FuelType; 25import android.car.hardware.CarDiagnosticEvent.IgnitionMonitors.CommonIgnitionMonitors; 26import android.car.hardware.CarDiagnosticEvent.IgnitionMonitors.CompressionIgnitionMonitors; 27import android.car.hardware.CarDiagnosticEvent.IgnitionMonitors.SparkIgnitionMonitors; 28import android.car.hardware.CarDiagnosticEvent.SecondaryAirStatus; 29import android.car.hardware.CarDiagnosticManager; 30import android.car.hardware.CarDiagnosticSensorIndices.Obd2FloatSensorIndex; 31import android.car.hardware.CarDiagnosticSensorIndices.Obd2IntegerSensorIndex; 32import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; 33import android.hardware.automotive.vehicle.V2_1.VehicleProperty; 34import android.os.SystemClock; 35import android.test.suitebuilder.annotation.MediumTest; 36import android.util.Log; 37import com.android.car.internal.FeatureConfiguration; 38import com.android.car.vehiclehal.DiagnosticEventBuilder; 39import com.android.car.vehiclehal.VehiclePropValueBuilder; 40import com.android.car.vehiclehal.test.MockedVehicleHal.VehicleHalPropertyHandler; 41import java.util.Arrays; 42import java.util.HashMap; 43import java.util.HashSet; 44import java.util.Set; 45 46/** Test the public entry points for the CarDiagnosticManager */ 47@MediumTest 48public class CarDiagnosticManagerTest extends MockedCarTestBase { 49 private static final String TAG = CarDiagnosticManagerTest.class.getSimpleName(); 50 51 private final DiagnosticEventBuilder mLiveFrameEventBuilder = 52 new DiagnosticEventBuilder(VehicleProperty.OBD2_LIVE_FRAME); 53 private final DiagnosticEventBuilder mFreezeFrameEventBuilder = 54 new DiagnosticEventBuilder(VehicleProperty.OBD2_FREEZE_FRAME); 55 private final FreezeFrameProperties mFreezeFrameProperties = new FreezeFrameProperties(); 56 57 private CarDiagnosticManager mCarDiagnosticManager; 58 59 private static final String DTC = "P1010"; 60 61 /** 62 * This class is a central repository for freeze frame data. It ensures that timestamps and 63 * events are kept in sync and provides a consistent access model for diagnostic properties. 64 */ 65 class FreezeFrameProperties { 66 private final HashMap<Long, VehiclePropValue> mEvents = new HashMap<>(); 67 68 public final VehicleHalPropertyHandler mFreezeFrameInfoHandler = 69 new FreezeFrameInfoHandler(); 70 public final VehicleHalPropertyHandler mFreezeFrameHandler = new FreezeFrameHandler(); 71 public final VehicleHalPropertyHandler mFreezeFrameClearHandler = 72 new FreezeFrameClearHandler(); 73 74 synchronized VehiclePropValue addNewEvent(DiagnosticEventBuilder builder) { 75 long timestamp = SystemClock.elapsedRealtimeNanos(); 76 return addNewEvent(builder, timestamp); 77 } 78 79 synchronized VehiclePropValue addNewEvent(DiagnosticEventBuilder builder, long timestamp) { 80 VehiclePropValue newEvent = builder.build(timestamp); 81 mEvents.put(timestamp, newEvent); 82 return newEvent; 83 } 84 85 synchronized VehiclePropValue removeEvent(long timestamp) { 86 return mEvents.remove(timestamp); 87 } 88 89 synchronized void removeEvents() { 90 mEvents.clear(); 91 } 92 93 synchronized long[] getTimestamps() { 94 return mEvents.keySet().stream().mapToLong(Long::longValue).toArray(); 95 } 96 97 synchronized VehiclePropValue getEvent(long timestamp) { 98 return mEvents.get(timestamp); 99 } 100 101 class FreezeFramePropertyHandler implements VehicleHalPropertyHandler { 102 private boolean mSubscribed = false; 103 104 protected final int VEHICLE_PROPERTY; 105 106 protected FreezeFramePropertyHandler(int propertyId) { 107 VEHICLE_PROPERTY = propertyId; 108 } 109 110 @Override 111 public synchronized void onPropertySet(VehiclePropValue value) { 112 assertEquals(VEHICLE_PROPERTY, value.prop); 113 } 114 115 @Override 116 public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) { 117 assertEquals(VEHICLE_PROPERTY, value.prop); 118 return null; 119 } 120 121 @Override 122 public synchronized void onPropertySubscribe( 123 int property, int zones, float sampleRate) { 124 assertEquals(VEHICLE_PROPERTY, property); 125 mSubscribed = true; 126 } 127 128 @Override 129 public synchronized void onPropertyUnsubscribe(int property) { 130 assertEquals(VEHICLE_PROPERTY, property); 131 if (!mSubscribed) { 132 throw new IllegalArgumentException( 133 "Property was not subscribed 0x" + toHexString(property)); 134 } 135 mSubscribed = false; 136 } 137 } 138 139 class FreezeFrameInfoHandler extends FreezeFramePropertyHandler { 140 FreezeFrameInfoHandler() { 141 super(VehicleProperty.OBD2_FREEZE_FRAME_INFO); 142 } 143 144 @Override 145 public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) { 146 super.onPropertyGet(value); 147 VehiclePropValueBuilder builder = 148 VehiclePropValueBuilder.newBuilder(VEHICLE_PROPERTY); 149 builder.setInt64Value(getTimestamps()); 150 return builder.build(); 151 } 152 } 153 154 class FreezeFrameHandler extends FreezeFramePropertyHandler { 155 FreezeFrameHandler() { 156 super(VehicleProperty.OBD2_FREEZE_FRAME); 157 } 158 159 @Override 160 public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) { 161 super.onPropertyGet(value); 162 long timestamp = value.value.int64Values.get(0); 163 return getEvent(timestamp); 164 } 165 } 166 167 class FreezeFrameClearHandler extends FreezeFramePropertyHandler { 168 FreezeFrameClearHandler() { 169 super(VehicleProperty.OBD2_FREEZE_FRAME_CLEAR); 170 } 171 172 @Override 173 public synchronized void onPropertySet(VehiclePropValue value) { 174 super.onPropertySet(value); 175 if (0 == value.value.int64Values.size()) { 176 removeEvents(); 177 } else { 178 for (long timestamp : value.value.int64Values) { 179 removeEvent(timestamp); 180 } 181 } 182 } 183 } 184 } 185 186 @Override 187 protected synchronized void configureMockedHal() { 188 java.util.Collection<Integer> numVendorSensors = Arrays.asList(0, 0); 189 addProperty(VehicleProperty.OBD2_LIVE_FRAME, mLiveFrameEventBuilder.build()) 190 .setConfigArray(numVendorSensors); 191 addProperty( 192 VehicleProperty.OBD2_FREEZE_FRAME_INFO, 193 mFreezeFrameProperties.mFreezeFrameInfoHandler); 194 addProperty(VehicleProperty.OBD2_FREEZE_FRAME, mFreezeFrameProperties.mFreezeFrameHandler) 195 .setConfigArray(numVendorSensors); 196 addProperty( 197 VehicleProperty.OBD2_FREEZE_FRAME_CLEAR, 198 mFreezeFrameProperties.mFreezeFrameClearHandler); 199 } 200 201 private boolean isFeatureEnabled() { 202 return FeatureConfiguration.ENABLE_DIAGNOSTIC; 203 } 204 205 @Override 206 protected void setUp() throws Exception { 207 mLiveFrameEventBuilder.addIntSensor(Obd2IntegerSensorIndex.AMBIENT_AIR_TEMPERATURE, 30); 208 mLiveFrameEventBuilder.addIntSensor( 209 Obd2IntegerSensorIndex.FUEL_SYSTEM_STATUS, 210 FuelSystemStatus.OPEN_ENGINE_LOAD_OR_DECELERATION); 211 mLiveFrameEventBuilder.addIntSensor( 212 Obd2IntegerSensorIndex.RUNTIME_SINCE_ENGINE_START, 5000); 213 mLiveFrameEventBuilder.addIntSensor(Obd2IntegerSensorIndex.CONTROL_MODULE_VOLTAGE, 2); 214 mLiveFrameEventBuilder.addFloatSensor(Obd2FloatSensorIndex.CALCULATED_ENGINE_LOAD, 0.125f); 215 mLiveFrameEventBuilder.addFloatSensor(Obd2FloatSensorIndex.VEHICLE_SPEED, 12.5f); 216 217 mFreezeFrameEventBuilder.addIntSensor(Obd2IntegerSensorIndex.AMBIENT_AIR_TEMPERATURE, 30); 218 mFreezeFrameEventBuilder.addIntSensor( 219 Obd2IntegerSensorIndex.RUNTIME_SINCE_ENGINE_START, 5000); 220 mFreezeFrameEventBuilder.addIntSensor(Obd2IntegerSensorIndex.CONTROL_MODULE_VOLTAGE, 2); 221 mFreezeFrameEventBuilder.addFloatSensor( 222 Obd2FloatSensorIndex.CALCULATED_ENGINE_LOAD, 0.125f); 223 mFreezeFrameEventBuilder.addFloatSensor(Obd2FloatSensorIndex.VEHICLE_SPEED, 12.5f); 224 mFreezeFrameEventBuilder.setDTC(DTC); 225 226 super.setUp(); 227 228 if (isFeatureEnabled()) { 229 Log.i(TAG, "attempting to get DIAGNOSTIC_SERVICE"); 230 mCarDiagnosticManager = 231 (CarDiagnosticManager) getCar().getCarManager(Car.DIAGNOSTIC_SERVICE); 232 } else { 233 Log.i(TAG, "skipping diagnostic tests as ENABLE_DIAGNOSTIC flag is false"); 234 } 235 } 236 237 public void testLiveFrameRead() throws Exception { 238 if (!isFeatureEnabled()) { 239 Log.i(TAG, "skipping testLiveFrameRead as diagnostics API is not enabled"); 240 return; 241 } 242 243 CarDiagnosticEvent liveFrame = mCarDiagnosticManager.getLatestLiveFrame(); 244 245 assertNotNull(liveFrame); 246 assertTrue(liveFrame.isLiveFrame()); 247 assertFalse(liveFrame.isFreezeFrame()); 248 assertFalse(liveFrame.isEmptyFrame()); 249 250 assertEquals( 251 5000, 252 liveFrame 253 .getSystemIntegerSensor(Obd2IntegerSensorIndex.RUNTIME_SINCE_ENGINE_START) 254 .intValue()); 255 assertEquals( 256 30, 257 liveFrame 258 .getSystemIntegerSensor(Obd2IntegerSensorIndex.AMBIENT_AIR_TEMPERATURE) 259 .intValue()); 260 assertEquals( 261 2, 262 liveFrame 263 .getSystemIntegerSensor(Obd2IntegerSensorIndex.CONTROL_MODULE_VOLTAGE) 264 .intValue()); 265 assertEquals( 266 0.125f, 267 liveFrame 268 .getSystemFloatSensor(Obd2FloatSensorIndex.CALCULATED_ENGINE_LOAD) 269 .floatValue()); 270 assertEquals( 271 12.5f, 272 liveFrame.getSystemFloatSensor(Obd2FloatSensorIndex.VEHICLE_SPEED).floatValue()); 273 } 274 275 public void testLiveFrameEvent() throws Exception { 276 if (!isFeatureEnabled()) { 277 Log.i(TAG, "skipping testLiveFrameEvent as diagnostics API is not enabled"); 278 return; 279 } 280 281 Listener listener = new Listener(); 282 mCarDiagnosticManager.registerListener( 283 listener, 284 CarDiagnosticManager.FRAME_TYPE_FLAG_LIVE, 285 android.car.hardware.CarSensorManager.SENSOR_RATE_NORMAL); 286 287 listener.reset(); 288 long time = SystemClock.elapsedRealtimeNanos(); 289 mLiveFrameEventBuilder.addIntSensor( 290 Obd2IntegerSensorIndex.RUNTIME_SINCE_ENGINE_START, 5100); 291 292 getMockedVehicleHal().injectEvent(mLiveFrameEventBuilder.build(time)); 293 assertTrue(listener.waitForEvent(time)); 294 295 CarDiagnosticEvent liveFrame = listener.getLastEvent(); 296 297 assertEquals( 298 5100, 299 liveFrame 300 .getSystemIntegerSensor(Obd2IntegerSensorIndex.RUNTIME_SINCE_ENGINE_START) 301 .intValue()); 302 } 303 304 public void testMissingSensorRead() throws Exception { 305 if (!isFeatureEnabled()) { 306 Log.i(TAG, "skipping testMissingSensorRead as diagnostics API is not enabled"); 307 return; 308 } 309 310 Listener listener = new Listener(); 311 mCarDiagnosticManager.registerListener( 312 listener, 313 CarDiagnosticManager.FRAME_TYPE_FLAG_LIVE, 314 android.car.hardware.CarSensorManager.SENSOR_RATE_NORMAL); 315 316 getMockedVehicleHal().injectEvent(mLiveFrameEventBuilder.build()); 317 assertTrue(listener.waitForEvent()); 318 319 CarDiagnosticEvent liveFrame = listener.getLastEvent(); 320 assertNotNull(liveFrame); 321 322 assertNull( 323 liveFrame.getSystemIntegerSensor( 324 Obd2IntegerSensorIndex.DRIVER_DEMAND_PERCENT_TORQUE)); 325 assertEquals( 326 -1, 327 liveFrame.getSystemIntegerSensor( 328 Obd2IntegerSensorIndex.DRIVER_DEMAND_PERCENT_TORQUE, -1)); 329 330 assertNull(liveFrame.getSystemFloatSensor(Obd2FloatSensorIndex.OXYGEN_SENSOR6_VOLTAGE)); 331 assertEquals( 332 0.25f, 333 liveFrame.getSystemFloatSensor(Obd2FloatSensorIndex.OXYGEN_SENSOR5_VOLTAGE, 0.25f)); 334 335 assertNull(liveFrame.getVendorIntegerSensor(Obd2IntegerSensorIndex.VENDOR_START)); 336 assertEquals(-1, liveFrame.getVendorIntegerSensor(Obd2IntegerSensorIndex.VENDOR_START, -1)); 337 338 assertNull(liveFrame.getVendorFloatSensor(Obd2FloatSensorIndex.VENDOR_START)); 339 assertEquals( 340 0.25f, liveFrame.getVendorFloatSensor(Obd2FloatSensorIndex.VENDOR_START, 0.25f)); 341 } 342 343 public void testFuelSystemStatus() throws Exception { 344 if (!isFeatureEnabled()) { 345 Log.i(TAG, "skipping testFuelSystemStatus as diagnostics API is not enabled"); 346 return; 347 } 348 349 Listener listener = new Listener(); 350 mCarDiagnosticManager.registerListener( 351 listener, 352 CarDiagnosticManager.FRAME_TYPE_FLAG_LIVE, 353 android.car.hardware.CarSensorManager.SENSOR_RATE_NORMAL); 354 355 getMockedVehicleHal().injectEvent(mLiveFrameEventBuilder.build()); 356 assertTrue(listener.waitForEvent()); 357 358 CarDiagnosticEvent liveFrame = listener.getLastEvent(); 359 assertNotNull(liveFrame); 360 361 assertEquals( 362 FuelSystemStatus.OPEN_ENGINE_LOAD_OR_DECELERATION, 363 liveFrame 364 .getSystemIntegerSensor(Obd2IntegerSensorIndex.FUEL_SYSTEM_STATUS) 365 .intValue()); 366 assertEquals( 367 FuelSystemStatus.OPEN_ENGINE_LOAD_OR_DECELERATION, 368 liveFrame.getFuelSystemStatus().intValue()); 369 } 370 371 public void testSecondaryAirStatus() throws Exception { 372 if (!isFeatureEnabled()) { 373 Log.i(TAG, "skipping testSecondaryAirStatus as diagnostics API is not enabled"); 374 return; 375 } 376 377 Listener listener = new Listener(); 378 mCarDiagnosticManager.registerListener( 379 listener, 380 CarDiagnosticManager.FRAME_TYPE_FLAG_LIVE, 381 android.car.hardware.CarSensorManager.SENSOR_RATE_NORMAL); 382 383 mLiveFrameEventBuilder.addIntSensor( 384 Obd2IntegerSensorIndex.COMMANDED_SECONDARY_AIR_STATUS, 385 SecondaryAirStatus.FROM_OUTSIDE_OR_OFF); 386 long timestamp = SystemClock.elapsedRealtimeNanos(); 387 getMockedVehicleHal().injectEvent(mLiveFrameEventBuilder.build(timestamp)); 388 389 assertTrue(listener.waitForEvent(timestamp)); 390 391 CarDiagnosticEvent liveFrame = listener.getLastEvent(); 392 assertNotNull(liveFrame); 393 394 assertEquals( 395 SecondaryAirStatus.FROM_OUTSIDE_OR_OFF, 396 liveFrame 397 .getSystemIntegerSensor( 398 Obd2IntegerSensorIndex.COMMANDED_SECONDARY_AIR_STATUS) 399 .intValue()); 400 assertEquals( 401 SecondaryAirStatus.FROM_OUTSIDE_OR_OFF, 402 liveFrame.getSecondaryAirStatus().intValue()); 403 } 404 405 public void testIgnitionMonitors() throws Exception { 406 if (!isFeatureEnabled()) { 407 Log.i(TAG, "skipping testIgnitionMonitors as diagnostics API is not enabled"); 408 return; 409 } 410 411 Listener listener = new Listener(); 412 mCarDiagnosticManager.registerListener( 413 listener, 414 CarDiagnosticManager.FRAME_TYPE_FLAG_LIVE, 415 android.car.hardware.CarSensorManager.SENSOR_RATE_NORMAL); 416 417 // cfr. CarDiagnosticEvent for the meaning of the several bits 418 final int sparkMonitorsValue = 419 0x1 | (0x1 << 2) | (0x1 << 3) | (0x1 << 6) | (0x1 << 10) | (0x1 << 11); 420 421 final int compressionMonitorsValue = 422 (0x1 << 2) | (0x1 << 3) | (0x1 << 6) | (0x1 << 12) | (0x1 << 13); 423 424 mLiveFrameEventBuilder.addIntSensor(Obd2IntegerSensorIndex.IGNITION_MONITORS_SUPPORTED, 0); 425 mLiveFrameEventBuilder.addIntSensor( 426 Obd2IntegerSensorIndex.IGNITION_SPECIFIC_MONITORS, sparkMonitorsValue); 427 428 long timestamp = SystemClock.elapsedRealtimeNanos(); 429 getMockedVehicleHal().injectEvent(mLiveFrameEventBuilder.build(timestamp)); 430 431 assertTrue(listener.waitForEvent(timestamp)); 432 433 CarDiagnosticEvent liveFrame = listener.getLastEvent(); 434 assertNotNull(liveFrame); 435 436 CommonIgnitionMonitors commonIgnitionMonitors = liveFrame.getIgnitionMonitors(); 437 assertNotNull(commonIgnitionMonitors); 438 assertTrue(commonIgnitionMonitors.components.available); 439 assertFalse(commonIgnitionMonitors.components.incomplete); 440 assertTrue(commonIgnitionMonitors.fuelSystem.available); 441 assertTrue(commonIgnitionMonitors.fuelSystem.incomplete); 442 assertFalse(commonIgnitionMonitors.misfire.available); 443 assertFalse(commonIgnitionMonitors.misfire.incomplete); 444 445 SparkIgnitionMonitors sparkIgnitionMonitors = 446 commonIgnitionMonitors.asSparkIgnitionMonitors(); 447 assertNotNull(sparkIgnitionMonitors); 448 assertNull(commonIgnitionMonitors.asCompressionIgnitionMonitors()); 449 450 assertTrue(sparkIgnitionMonitors.EGR.available); 451 assertFalse(sparkIgnitionMonitors.EGR.incomplete); 452 assertFalse(sparkIgnitionMonitors.oxygenSensorHeater.available); 453 assertFalse(sparkIgnitionMonitors.oxygenSensorHeater.incomplete); 454 assertTrue(sparkIgnitionMonitors.oxygenSensor.available); 455 assertTrue(sparkIgnitionMonitors.oxygenSensor.incomplete); 456 assertFalse(sparkIgnitionMonitors.ACRefrigerant.available); 457 assertFalse(sparkIgnitionMonitors.ACRefrigerant.incomplete); 458 assertFalse(sparkIgnitionMonitors.secondaryAirSystem.available); 459 assertFalse(sparkIgnitionMonitors.secondaryAirSystem.incomplete); 460 assertFalse(sparkIgnitionMonitors.evaporativeSystem.available); 461 assertFalse(sparkIgnitionMonitors.evaporativeSystem.incomplete); 462 assertFalse(sparkIgnitionMonitors.heatedCatalyst.available); 463 assertFalse(sparkIgnitionMonitors.heatedCatalyst.incomplete); 464 assertFalse(sparkIgnitionMonitors.catalyst.available); 465 assertFalse(sparkIgnitionMonitors.catalyst.incomplete); 466 467 mLiveFrameEventBuilder.addIntSensor(Obd2IntegerSensorIndex.IGNITION_MONITORS_SUPPORTED, 1); 468 mLiveFrameEventBuilder.addIntSensor( 469 Obd2IntegerSensorIndex.IGNITION_SPECIFIC_MONITORS, compressionMonitorsValue); 470 471 timestamp += 1000; 472 getMockedVehicleHal().injectEvent(mLiveFrameEventBuilder.build(timestamp)); 473 474 assertTrue(listener.waitForEvent(timestamp)); 475 476 liveFrame = listener.getLastEvent(); 477 assertNotNull(liveFrame); 478 assertEquals(timestamp, liveFrame.timestamp); 479 480 commonIgnitionMonitors = liveFrame.getIgnitionMonitors(); 481 assertNotNull(commonIgnitionMonitors); 482 assertFalse(commonIgnitionMonitors.components.available); 483 assertFalse(commonIgnitionMonitors.components.incomplete); 484 assertTrue(commonIgnitionMonitors.fuelSystem.available); 485 assertTrue(commonIgnitionMonitors.fuelSystem.incomplete); 486 assertFalse(commonIgnitionMonitors.misfire.available); 487 assertFalse(commonIgnitionMonitors.misfire.incomplete); 488 CompressionIgnitionMonitors compressionIgnitionMonitors = 489 commonIgnitionMonitors.asCompressionIgnitionMonitors(); 490 assertNull(commonIgnitionMonitors.asSparkIgnitionMonitors()); 491 assertNotNull(compressionIgnitionMonitors); 492 493 assertTrue(compressionIgnitionMonitors.EGROrVVT.available); 494 assertFalse(compressionIgnitionMonitors.EGROrVVT.incomplete); 495 assertFalse(compressionIgnitionMonitors.PMFilter.available); 496 assertFalse(compressionIgnitionMonitors.PMFilter.incomplete); 497 assertFalse(compressionIgnitionMonitors.exhaustGasSensor.available); 498 assertFalse(compressionIgnitionMonitors.exhaustGasSensor.incomplete); 499 assertTrue(compressionIgnitionMonitors.boostPressure.available); 500 assertTrue(compressionIgnitionMonitors.boostPressure.incomplete); 501 assertFalse(compressionIgnitionMonitors.NOxSCR.available); 502 assertFalse(compressionIgnitionMonitors.NOxSCR.incomplete); 503 assertFalse(compressionIgnitionMonitors.NMHCCatalyst.available); 504 assertFalse(compressionIgnitionMonitors.NMHCCatalyst.incomplete); 505 } 506 507 public void testFuelType() throws Exception { 508 if (!isFeatureEnabled()) { 509 Log.i(TAG, "skipping testFuelType as diagnostics API is not enabled"); 510 return; 511 } 512 513 Listener listener = new Listener(); 514 mCarDiagnosticManager.registerListener( 515 listener, 516 CarDiagnosticManager.FRAME_TYPE_FLAG_LIVE, 517 android.car.hardware.CarSensorManager.SENSOR_RATE_NORMAL); 518 519 mLiveFrameEventBuilder.addIntSensor( 520 Obd2IntegerSensorIndex.FUEL_TYPE, FuelType.BIFUEL_RUNNING_LPG); 521 long timestamp = SystemClock.elapsedRealtimeNanos(); 522 getMockedVehicleHal().injectEvent(mLiveFrameEventBuilder.build(timestamp)); 523 524 assertTrue(listener.waitForEvent(timestamp)); 525 526 CarDiagnosticEvent liveFrame = listener.getLastEvent(); 527 assertNotNull(liveFrame); 528 529 assertEquals( 530 FuelType.BIFUEL_RUNNING_LPG, 531 liveFrame.getSystemIntegerSensor(Obd2IntegerSensorIndex.FUEL_TYPE).intValue()); 532 assertEquals(FuelType.BIFUEL_RUNNING_LPG, liveFrame.getFuelType().intValue()); 533 } 534 535 public void testMultipleListeners() throws Exception { 536 if (!isFeatureEnabled()) { 537 Log.i(TAG, "skipping testMultipleListeners as diagnostics API is not enabled"); 538 return; 539 } 540 541 Listener listener1 = new Listener(); 542 Listener listener2 = new Listener(); 543 544 mCarDiagnosticManager.registerListener( 545 listener1, 546 CarDiagnosticManager.FRAME_TYPE_FLAG_LIVE, 547 android.car.hardware.CarSensorManager.SENSOR_RATE_NORMAL); 548 mCarDiagnosticManager.registerListener( 549 listener2, 550 CarDiagnosticManager.FRAME_TYPE_FLAG_LIVE, 551 android.car.hardware.CarSensorManager.SENSOR_RATE_NORMAL); 552 553 listener1.reset(); 554 listener2.reset(); 555 556 long time = SystemClock.elapsedRealtimeNanos(); 557 getMockedVehicleHal().injectEvent(mLiveFrameEventBuilder.build(time)); 558 assertTrue(listener1.waitForEvent(time)); 559 assertTrue(listener2.waitForEvent(time)); 560 561 CarDiagnosticEvent event1 = listener1.getLastEvent(); 562 CarDiagnosticEvent event2 = listener2.getLastEvent(); 563 assertEquals( 564 5000, 565 event1.getSystemIntegerSensor(Obd2IntegerSensorIndex.RUNTIME_SINCE_ENGINE_START) 566 .intValue()); 567 assertEquals( 568 5000, 569 event2.getSystemIntegerSensor(Obd2IntegerSensorIndex.RUNTIME_SINCE_ENGINE_START) 570 .intValue()); 571 572 listener1.reset(); 573 listener2.reset(); 574 575 mCarDiagnosticManager.unregisterListener(listener1); 576 577 time += 1000; 578 getMockedVehicleHal().injectEvent(mLiveFrameEventBuilder.build(time)); 579 assertFalse(listener1.waitForEvent(time)); 580 assertTrue(listener2.waitForEvent(time)); 581 582 assertNull(listener1.getLastEvent()); 583 event2 = listener2.getLastEvent(); 584 585 assertTrue(event1.isEarlierThan(event2)); 586 587 assertEquals( 588 5000, 589 event2.getSystemIntegerSensor(Obd2IntegerSensorIndex.RUNTIME_SINCE_ENGINE_START) 590 .intValue()); 591 } 592 593 public void testFreezeFrameEvent() throws Exception { 594 if (!isFeatureEnabled()) { 595 Log.i(TAG, "skipping testFreezeFrameEvent as diagnostics API is not enabled"); 596 return; 597 } 598 599 Listener listener = new Listener(); 600 mCarDiagnosticManager.registerListener( 601 listener, 602 CarDiagnosticManager.FRAME_TYPE_FLAG_FREEZE, 603 android.car.hardware.CarSensorManager.SENSOR_RATE_NORMAL); 604 605 listener.reset(); 606 VehiclePropValue injectedEvent = 607 mFreezeFrameProperties.addNewEvent(mFreezeFrameEventBuilder); 608 getMockedVehicleHal().injectEvent(injectedEvent); 609 assertTrue(listener.waitForEvent(injectedEvent.timestamp)); 610 611 CarDiagnosticEvent freezeFrame = listener.getLastEvent(); 612 613 assertEquals(DTC, freezeFrame.dtc); 614 615 mFreezeFrameEventBuilder.addIntSensor( 616 Obd2IntegerSensorIndex.ABSOLUTE_BAROMETRIC_PRESSURE, 22); 617 injectedEvent = mFreezeFrameProperties.addNewEvent(mFreezeFrameEventBuilder); 618 getMockedVehicleHal().injectEvent(injectedEvent); 619 assertTrue(listener.waitForEvent(injectedEvent.timestamp)); 620 621 freezeFrame = listener.getLastEvent(); 622 623 assertNotNull(freezeFrame); 624 assertFalse(freezeFrame.isLiveFrame()); 625 assertTrue(freezeFrame.isFreezeFrame()); 626 assertFalse(freezeFrame.isEmptyFrame()); 627 628 assertEquals(DTC, freezeFrame.dtc); 629 assertEquals( 630 22, 631 freezeFrame 632 .getSystemIntegerSensor(Obd2IntegerSensorIndex.ABSOLUTE_BAROMETRIC_PRESSURE) 633 .intValue()); 634 } 635 636 public void testFreezeFrameTimestamps() throws Exception { 637 if (!isFeatureEnabled()) { 638 Log.i(TAG, "skipping testFreezeFrameTimestamps as diagnostics API is not enabled"); 639 return; 640 } 641 642 Listener listener = new Listener(); 643 mCarDiagnosticManager.registerListener( 644 listener, 645 CarDiagnosticManager.FRAME_TYPE_FLAG_FREEZE, 646 android.car.hardware.CarSensorManager.SENSOR_RATE_NORMAL); 647 648 Set<Long> generatedTimestamps = new HashSet<>(); 649 650 VehiclePropValue injectedEvent = 651 mFreezeFrameProperties.addNewEvent(mFreezeFrameEventBuilder); 652 getMockedVehicleHal().injectEvent(injectedEvent); 653 generatedTimestamps.add(injectedEvent.timestamp); 654 assertTrue(listener.waitForEvent(injectedEvent.timestamp)); 655 656 injectedEvent = 657 mFreezeFrameProperties.addNewEvent( 658 mFreezeFrameEventBuilder, injectedEvent.timestamp + 1000); 659 getMockedVehicleHal().injectEvent(injectedEvent); 660 generatedTimestamps.add(injectedEvent.timestamp); 661 assertTrue(listener.waitForEvent(injectedEvent.timestamp)); 662 663 long[] acquiredTimestamps = mCarDiagnosticManager.getFreezeFrameTimestamps(); 664 assertEquals(generatedTimestamps.size(), acquiredTimestamps.length); 665 for (long acquiredTimestamp : acquiredTimestamps) { 666 assertTrue(generatedTimestamps.contains(acquiredTimestamp)); 667 } 668 } 669 670 public void testClearFreezeFrameTimestamps() throws Exception { 671 if (!isFeatureEnabled()) { 672 Log.i(TAG, "skipping testClearFreezeFrameTimestamps as diagnostics API is not enabled"); 673 return; 674 } 675 676 Listener listener = new Listener(); 677 mCarDiagnosticManager.registerListener( 678 listener, 679 CarDiagnosticManager.FRAME_TYPE_FLAG_FREEZE, 680 android.car.hardware.CarSensorManager.SENSOR_RATE_NORMAL); 681 682 VehiclePropValue injectedEvent = 683 mFreezeFrameProperties.addNewEvent(mFreezeFrameEventBuilder); 684 getMockedVehicleHal().injectEvent(injectedEvent); 685 assertTrue(listener.waitForEvent(injectedEvent.timestamp)); 686 687 assertNotNull(mCarDiagnosticManager.getFreezeFrame(injectedEvent.timestamp)); 688 mCarDiagnosticManager.clearFreezeFrames(injectedEvent.timestamp); 689 assertNull(mCarDiagnosticManager.getFreezeFrame(injectedEvent.timestamp)); 690 } 691 692 class Listener implements CarDiagnosticManager.OnDiagnosticEventListener { 693 private final Object mSync = new Object(); 694 695 private CarDiagnosticEvent mLastEvent = null; 696 697 CarDiagnosticEvent getLastEvent() { 698 return mLastEvent; 699 } 700 701 void reset() { 702 synchronized (mSync) { 703 mLastEvent = null; 704 } 705 } 706 707 boolean waitForEvent() throws InterruptedException { 708 return waitForEvent(0); 709 } 710 711 boolean waitForEvent(long eventTimeStamp) throws InterruptedException { 712 long start = SystemClock.elapsedRealtime(); 713 boolean matchTimeStamp = eventTimeStamp != 0; 714 synchronized (mSync) { 715 while ((mLastEvent == null 716 || (matchTimeStamp && mLastEvent.timestamp != eventTimeStamp)) 717 && (start + SHORT_WAIT_TIMEOUT_MS > SystemClock.elapsedRealtime())) { 718 mSync.wait(10L); 719 } 720 return mLastEvent != null 721 && (!matchTimeStamp || mLastEvent.timestamp == eventTimeStamp); 722 } 723 } 724 725 @Override 726 public void onDiagnosticEvent(CarDiagnosticEvent event) { 727 synchronized (mSync) { 728 // We're going to hold a reference to this object 729 mLastEvent = event; 730 mSync.notify(); 731 } 732 } 733 } 734} 735