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