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