1 /*
2  * Copyright (C) 2018 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 package com.android.car.hal;
17 
18 import static org.junit.Assert.assertArrayEquals;
19 import static org.junit.Assert.assertEquals;
20 import static org.mockito.ArgumentMatchers.any;
21 import static org.mockito.ArgumentMatchers.anyInt;
22 import static org.mockito.Mockito.doThrow;
23 import static org.mockito.Mockito.never;
24 import static org.mockito.Mockito.reset;
25 import static org.mockito.Mockito.verify;
26 import static org.mockito.Mockito.verifyZeroInteractions;
27 import static org.mockito.Mockito.when;
28 
29 import android.car.vms.IVmsPublisherClient;
30 import android.car.vms.IVmsPublisherService;
31 import android.car.vms.IVmsSubscriberClient;
32 import android.car.vms.IVmsSubscriberService;
33 import android.car.vms.VmsAssociatedLayer;
34 import android.car.vms.VmsAvailableLayers;
35 import android.car.vms.VmsLayer;
36 import android.car.vms.VmsLayerDependency;
37 import android.car.vms.VmsLayersOffering;
38 import android.car.vms.VmsSubscriptionState;
39 import android.content.Context;
40 import android.content.res.Resources;
41 import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
42 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
43 import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
44 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyGroup;
45 import android.hardware.automotive.vehicle.V2_0.VmsMessageType;
46 import android.os.Binder;
47 import android.os.IBinder;
48 
49 import com.android.car.R;
50 import com.android.car.test.utils.TemporaryFile;
51 import com.android.car.vms.VmsClientManager;
52 
53 import org.junit.Before;
54 import org.junit.Rule;
55 import org.junit.Test;
56 import org.mockito.ArgumentCaptor;
57 import org.mockito.InOrder;
58 import org.mockito.Mock;
59 import org.mockito.Mockito;
60 import org.mockito.junit.MockitoJUnit;
61 import org.mockito.junit.MockitoRule;
62 
63 import java.io.FileDescriptor;
64 import java.io.FileInputStream;
65 import java.io.FileOutputStream;
66 import java.util.Arrays;
67 import java.util.Collections;
68 import java.util.LinkedHashSet;
69 import java.util.List;
70 import java.util.concurrent.CountDownLatch;
71 import java.util.concurrent.TimeUnit;
72 
73 public class VmsHalServiceTest {
74     private static final int LAYER_TYPE = 1;
75     private static final int LAYER_SUBTYPE = 2;
76     private static final int LAYER_VERSION = 3;
77     private static final VmsLayer LAYER = new VmsLayer(LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION);
78     private static final int PUBLISHER_ID = 12345;
79     private static final byte[] PAYLOAD = new byte[]{1, 2, 3, 4};
80     private static final List<Byte> PAYLOAD_AS_LIST = Arrays.asList(new Byte[]{1, 2, 3, 4});
81     private static final int CORE_ID = 54321;
82     private static final int CLIENT_ID = 98765;
83 
84     @Rule
85     public MockitoRule mockito = MockitoJUnit.rule();
86     @Mock
87     private Context mContext;
88     @Mock
89     private Resources mResources;
90     @Mock
91     private VehicleHal mVehicleHal;
92     @Mock
93     private VmsClientManager mClientManager;
94     @Mock
95     private IVmsPublisherService mPublisherService;
96     @Mock
97     private IVmsSubscriberService mSubscriberService;
98 
99     private IBinder mToken;
100     private VmsHalService mHalService;
101     private IVmsPublisherClient mPublisherClient;
102     private IVmsSubscriberClient mSubscriberClient;
103 
104     @Before
setUp()105     public void setUp() throws Exception {
106         initHalService(true);
107     }
108 
initHalService(boolean propagatePropertyException)109     private void initHalService(boolean propagatePropertyException) throws Exception {
110         when(mContext.getResources()).thenReturn(mResources);
111         mHalService = new VmsHalService(mContext, mVehicleHal, () -> (long) CORE_ID,
112             propagatePropertyException);
113         mHalService.setClientManager(mClientManager);
114         mHalService.setVmsSubscriberService(mSubscriberService);
115 
116         VehiclePropConfig propConfig = new VehiclePropConfig();
117         propConfig.prop = VehicleProperty.VEHICLE_MAP_SERVICE;
118         mHalService.takeSupportedProperties(Collections.singleton(propConfig));
119 
120         when(mSubscriberService.getAvailableLayers()).thenReturn(
121                 new VmsAvailableLayers(Collections.emptySet(), 0));
122         mHalService.init();
123         waitForHandlerCompletion();
124 
125         // Verify START_SESSION message was sent
126         InOrder initOrder =
127                 Mockito.inOrder(mClientManager, mSubscriberService, mVehicleHal);
128         initOrder.verify(mVehicleHal).subscribeProperty(mHalService,
129                 VehicleProperty.VEHICLE_MAP_SERVICE);
130         initOrder.verify(mVehicleHal).set(createHalMessage(
131                 VmsMessageType.START_SESSION, // Message type
132                 CORE_ID,                      // Core ID
133                 -1));                          // Client ID (unknown)
134 
135         // Verify no more interections until handshake received
136         initOrder.verifyNoMoreInteractions();
137 
138         // Send START_SESSION response from client
139         sendHalMessage(createHalMessage(
140                 VmsMessageType.START_SESSION,  // Message type
141                 CORE_ID,                       // Core ID
142                 CLIENT_ID                      // Client ID
143         ));
144         waitForHandlerCompletion();
145 
146         // Verify client is marked as connected
147         ArgumentCaptor<IVmsPublisherClient> publisherCaptor =
148                 ArgumentCaptor.forClass(IVmsPublisherClient.class);
149         ArgumentCaptor<IVmsSubscriberClient> subscriberCaptor =
150                 ArgumentCaptor.forClass(IVmsSubscriberClient.class);
151         initOrder.verify(mClientManager, never()).onHalDisconnected();
152         initOrder.verify(mClientManager)
153                 .onHalConnected(publisherCaptor.capture(), subscriberCaptor.capture());
154         mPublisherClient = publisherCaptor.getValue();
155         mSubscriberClient = subscriberCaptor.getValue();
156 
157         mToken = new Binder();
158         mPublisherClient.setVmsPublisherService(mToken, mPublisherService);
159 
160         initOrder.verify(mSubscriberService).getAvailableLayers();
161         initOrder.verify(mVehicleHal).set(createHalMessage(
162                 VmsMessageType.AVAILABILITY_CHANGE, // Message type
163                 0,                                  // Sequence number
164                 0));                                // # of associated layers
165 
166 
167         waitForHandlerCompletion();
168         initOrder.verifyNoMoreInteractions();
169         reset(mClientManager, mSubscriberService, mVehicleHal);
170     }
171 
172     @Test
testCoreId_IntegerOverflow()173     public void testCoreId_IntegerOverflow() throws Exception {
174         mHalService = new VmsHalService(mContext, mVehicleHal,
175                 () -> (long) Integer.MAX_VALUE + CORE_ID, true);
176 
177         VehiclePropConfig propConfig = new VehiclePropConfig();
178         propConfig.prop = VehicleProperty.VEHICLE_MAP_SERVICE;
179         mHalService.takeSupportedProperties(Collections.singleton(propConfig));
180 
181         when(mSubscriberService.getAvailableLayers()).thenReturn(
182                 new VmsAvailableLayers(Collections.emptySet(), 0));
183         mHalService.init();
184         waitForHandlerCompletion();
185 
186         verify(mVehicleHal).set(createHalMessage(
187                 VmsMessageType.START_SESSION, // Message type
188                 CORE_ID,                      // Core ID
189                 -1));                          // Client ID (unknown)
190     }
191 
192     @Test
testTakeSupportedProperties()193     public void testTakeSupportedProperties() {
194         VehiclePropConfig vmsPropConfig = new VehiclePropConfig();
195         vmsPropConfig.prop = VehicleProperty.VEHICLE_MAP_SERVICE;
196 
197         VehiclePropConfig otherPropConfig = new VehiclePropConfig();
198         otherPropConfig.prop = VehicleProperty.CURRENT_GEAR;
199 
200         assertEquals(Collections.singleton(vmsPropConfig),
201                 mHalService.takeSupportedProperties(Arrays.asList(otherPropConfig, vmsPropConfig)));
202     }
203 
204     /**
205      * DATA message format:
206      * <ul>
207      * <li>Message type
208      * <li>Layer ID
209      * <li>Layer subtype
210      * <li>Layer version
211      * <li>Publisher ID
212      * <li>Payload
213      * </ul>
214      */
215     @Test
testHandleDataEvent()216     public void testHandleDataEvent() throws Exception {
217         VehiclePropValue message = createHalMessage(
218                 VmsMessageType.DATA,                       // Message type
219                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION,  // VmsLayer
220                 PUBLISHER_ID                               // PublisherId
221         );
222         message.value.bytes.addAll(PAYLOAD_AS_LIST);
223 
224         sendHalMessage(message);
225         verify(mPublisherService).publish(mToken, LAYER, PUBLISHER_ID, PAYLOAD);
226     }
227 
228     /**
229      * SUBSCRIBE message format:
230      * <ul>
231      * <li>Message type
232      * <li>Layer ID
233      * <li>Layer subtype
234      * <li>Layer version
235      * </ul>
236      */
237     @Test
testHandleSubscribeEvent()238     public void testHandleSubscribeEvent() throws Exception {
239         VehiclePropValue message = createHalMessage(
240                 VmsMessageType.SUBSCRIBE,                 // Message type
241                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION  // VmsLayer
242         );
243 
244         sendHalMessage(message);
245         verify(mSubscriberService).addVmsSubscriber(mSubscriberClient, LAYER);
246     }
247 
248     /**
249      * SUBSCRIBE_TO_PUBLISHER message format:
250      * <ul>
251      * <li>Message type
252      * <li>Layer ID
253      * <li>Layer subtype
254      * <li>Layer version
255      * <li>Publisher ID
256      * </ul>
257      */
258     @Test
testHandleSubscribeToPublisherEvent()259     public void testHandleSubscribeToPublisherEvent() throws Exception {
260         VehiclePropValue message = createHalMessage(
261                 VmsMessageType.SUBSCRIBE_TO_PUBLISHER,     // Message type
262                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION,  // VmsLayer
263                 PUBLISHER_ID                               // PublisherId
264         );
265 
266         sendHalMessage(message);
267         verify(mSubscriberService).addVmsSubscriberToPublisher(mSubscriberClient, LAYER,
268                 PUBLISHER_ID);
269     }
270 
271     /**
272      * UNSUBSCRIBE message format:
273      * <ul>
274      * <li>Message type
275      * <li>Layer ID
276      * <li>Layer subtype
277      * <li>Layer version
278      * </ul>
279      */
280     @Test
testHandleUnsubscribeEvent()281     public void testHandleUnsubscribeEvent() throws Exception {
282         VehiclePropValue message = createHalMessage(
283                 VmsMessageType.UNSUBSCRIBE,               // Message type
284                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION  // VmsLayer
285         );
286 
287         sendHalMessage(message);
288         verify(mSubscriberService).removeVmsSubscriber(mSubscriberClient, LAYER);
289     }
290 
291     /**
292      * UNSUBSCRIBE_TO_PUBLISHER message format:
293      * <ul>
294      * <li>Message type
295      * <li>Layer ID
296      * <li>Layer subtype
297      * <li>Layer version
298      * <li>Publisher ID
299      * </ul>
300      */
301     @Test
testHandleUnsubscribeFromPublisherEvent()302     public void testHandleUnsubscribeFromPublisherEvent() throws Exception {
303         VehiclePropValue message = createHalMessage(
304                 VmsMessageType.UNSUBSCRIBE_TO_PUBLISHER,   // Message type
305                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION,  // VmsLayer
306                 PUBLISHER_ID                               // PublisherId
307         );
308 
309         sendHalMessage(message);
310         verify(mSubscriberService).removeVmsSubscriberToPublisher(mSubscriberClient, LAYER,
311                 PUBLISHER_ID);
312     }
313 
314     /**
315      * PUBLISHER_ID_REQUEST message format:
316      * <ul>
317      * <li>Message type
318      * <li>Publisher info (bytes)
319      * </ul>
320      *
321      * PUBLISHER_ID_RESPONSE message format:
322      * <ul>
323      * <li>Message type
324      * <li>Publisher ID
325      * </ul>
326      */
327     @Test
testHandlePublisherIdRequestEvent()328     public void testHandlePublisherIdRequestEvent() throws Exception {
329         VehiclePropValue request = createHalMessage(
330                 VmsMessageType.PUBLISHER_ID_REQUEST  // Message type
331         );
332         request.value.bytes.addAll(PAYLOAD_AS_LIST);
333 
334         when(mPublisherService.getPublisherId(PAYLOAD)).thenReturn(PUBLISHER_ID);
335 
336         VehiclePropValue response = createHalMessage(
337                 VmsMessageType.PUBLISHER_ID_RESPONSE,  // Message type
338                 PUBLISHER_ID                           // Publisher ID
339         );
340 
341         sendHalMessage(request);
342         verify(mVehicleHal).set(response);
343     }
344 
345     /**
346      * PUBLISHER_INFORMATION_REQUEST message format:
347      * <ul>
348      * <li>Message type
349      * <li>Publisher ID
350      * </ul>
351      *
352      * PUBLISHER_INFORMATION_RESPONSE message format:
353      * <ul>
354      * <li>Message type
355      * <li>Publisher info (bytes)
356      * </ul>
357      */
358     @Test
testHandlePublisherInformationRequestEvent()359     public void testHandlePublisherInformationRequestEvent() throws Exception {
360         VehiclePropValue request = createHalMessage(
361                 VmsMessageType.PUBLISHER_INFORMATION_REQUEST,  // Message type
362                 PUBLISHER_ID                                   // Publisher ID
363         );
364 
365         when(mSubscriberService.getPublisherInfo(PUBLISHER_ID)).thenReturn(PAYLOAD);
366 
367         VehiclePropValue response = createHalMessage(
368                 VmsMessageType.PUBLISHER_INFORMATION_RESPONSE  // Message type
369         );
370         response.value.bytes.addAll(PAYLOAD_AS_LIST);
371 
372         sendHalMessage(request);
373         verify(mVehicleHal).set(response);
374     }
375 
376     /**
377      * OFFERING message format:
378      * <ul>
379      * <li>Message type
380      * <li>Publisher ID
381      * <li>Number of offerings.
382      * <li>Offerings (x number of offerings)
383      * <ul>
384      * <li>Layer ID
385      * <li>Layer subtype
386      * <li>Layer version
387      * <li>Number of layer dependencies.
388      * <li>Layer dependencies (x number of layer dependencies)
389      * <ul>
390      * <li>Layer ID
391      * <li>Layer subtype
392      * <li>Layer version
393      * </ul>
394      * </ul>
395      * </ul>
396      */
397     @Test
testHandleOfferingEvent_ZeroOfferings()398     public void testHandleOfferingEvent_ZeroOfferings() throws Exception {
399         VehiclePropValue message = createHalMessage(
400                 VmsMessageType.OFFERING,  // Message type
401                 PUBLISHER_ID,             // PublisherId
402                 0                         // # of offerings
403         );
404 
405         sendHalMessage(message);
406         verify(mPublisherService).setLayersOffering(
407                 mToken,
408                 new VmsLayersOffering(Collections.emptySet(), PUBLISHER_ID));
409     }
410 
411     @Test
testHandleOfferingEvent_LayerOnly()412     public void testHandleOfferingEvent_LayerOnly() throws Exception {
413         VehiclePropValue message = createHalMessage(
414                 VmsMessageType.OFFERING,                   // Message type
415                 PUBLISHER_ID,                              // PublisherId
416                 1,                                         // # of offerings
417                 // Offered layer
418                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION,
419                 0                                          // # of dependencies
420         );
421 
422         sendHalMessage(message);
423         verify(mPublisherService).setLayersOffering(
424                 mToken,
425                 new VmsLayersOffering(Collections.singleton(
426                         new VmsLayerDependency(LAYER)),
427                         PUBLISHER_ID));
428     }
429 
430     @Test
testHandleOfferingEvent_LayerAndDependency()431     public void testHandleOfferingEvent_LayerAndDependency() throws Exception {
432         VehiclePropValue message = createHalMessage(
433                 VmsMessageType.OFFERING,                   // Message type
434                 PUBLISHER_ID,                              // PublisherId
435                 1,                                         // # of offerings
436                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION,  // Layer
437                 1,                                         // # of dependencies
438                 4, 5, 6                                    // Dependency layer
439         );
440 
441         sendHalMessage(message);
442         verify(mPublisherService).setLayersOffering(
443                 mToken,
444                 new VmsLayersOffering(Collections.singleton(
445                         new VmsLayerDependency(LAYER, Collections.singleton(
446                                 new VmsLayer(4, 5, 6)))),
447                         PUBLISHER_ID));
448     }
449 
450     @Test
testHandleOfferingEvent_MultipleLayersAndDependencies()451     public void testHandleOfferingEvent_MultipleLayersAndDependencies() throws Exception {
452         VehiclePropValue message = createHalMessage(
453                 VmsMessageType.OFFERING,                   // Message type
454                 PUBLISHER_ID,                              // PublisherId
455                 3,                                         // # of offerings
456                 // Offered layer #1
457                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION,  // Layer
458                 2,                                         // # of dependencies
459                 4, 5, 6,                                   // Dependency layer
460                 7, 8, 9,                                   // Dependency layer
461                 // Offered layer #2
462                 3, 2, 1,                                   // Layer
463                 0,                                         // # of dependencies
464                 // Offered layer #3
465                 6, 5, 4,                                   // Layer
466                 1,                                         // # of dependencies
467                 7, 8, 9                                    // Dependency layer
468         );
469 
470         sendHalMessage(message);
471         verify(mPublisherService).setLayersOffering(
472                 mToken,
473                 new VmsLayersOffering(new LinkedHashSet<>(Arrays.asList(
474                         new VmsLayerDependency(LAYER, new LinkedHashSet<>(Arrays.asList(
475                                 new VmsLayer(4, 5, 6),
476                                 new VmsLayer(7, 8, 9)
477                         ))),
478                         new VmsLayerDependency(new VmsLayer(3, 2, 1), Collections.emptySet()),
479                         new VmsLayerDependency(new VmsLayer(6, 5, 4), Collections.singleton(
480                                 new VmsLayer(7, 8, 9)
481                         )))),
482                         PUBLISHER_ID));
483     }
484 
485     /**
486      * AVAILABILITY_REQUEST message format:
487      * <ul>
488      * <li>Message type
489      * </ul>
490      *
491      * AVAILABILITY_RESPONSE message format:
492      * <ul>
493      * <li>Message type
494      * <li>Sequence number.
495      * <li>Number of associated layers.
496      * <li>Associated layers (x number of associated layers)
497      * <ul>
498      * <li>Layer ID
499      * <li>Layer subtype
500      * <li>Layer version
501      * <li>Number of publishers
502      * <li>Publisher ID (x number of publishers)
503      * </ul>
504      * </ul>
505      */
506     @Test
testHandleAvailabilityRequestEvent_ZeroLayers()507     public void testHandleAvailabilityRequestEvent_ZeroLayers() throws Exception {
508         VehiclePropValue request = createHalMessage(
509                 VmsMessageType.AVAILABILITY_REQUEST  // Message type
510         );
511 
512         when(mSubscriberService.getAvailableLayers()).thenReturn(
513                 new VmsAvailableLayers(Collections.emptySet(), 123));
514 
515         VehiclePropValue response = createHalMessage(
516                 VmsMessageType.AVAILABILITY_RESPONSE,  // Message type
517                 123,                                   // Sequence number
518                 0                                      // # of associated layers
519         );
520 
521         sendHalMessage(request);
522         verify(mVehicleHal).set(response);
523     }
524 
525     @Test
testHandleAvailabilityRequestEvent_OneLayer()526     public void testHandleAvailabilityRequestEvent_OneLayer() throws Exception {
527         VehiclePropValue request = createHalMessage(
528                 VmsMessageType.AVAILABILITY_REQUEST  // Message type
529         );
530 
531         when(mSubscriberService.getAvailableLayers()).thenReturn(
532                 new VmsAvailableLayers(Collections.singleton(
533                         new VmsAssociatedLayer(LAYER, Collections.singleton(PUBLISHER_ID))), 123));
534 
535         VehiclePropValue response = createHalMessage(
536                 VmsMessageType.AVAILABILITY_RESPONSE,      // Message type
537                 123,                                       // Sequence number
538                 1,                                         // # of associated layers
539                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION,  // Layer
540                 1,                                         // # of publisher IDs
541                 PUBLISHER_ID                               // Publisher ID
542         );
543 
544         sendHalMessage(request);
545         verify(mVehicleHal).set(response);
546     }
547 
548 
549     @Test
testHandleAvailabilityRequestEvent_MultipleLayers()550     public void testHandleAvailabilityRequestEvent_MultipleLayers() throws Exception {
551         VehiclePropValue request = createHalMessage(
552                 VmsMessageType.AVAILABILITY_REQUEST  // Message type
553         );
554 
555         when(mSubscriberService.getAvailableLayers()).thenReturn(
556                 new VmsAvailableLayers(new LinkedHashSet<>(Arrays.asList(
557                         new VmsAssociatedLayer(LAYER,
558                                 new LinkedHashSet<>(Arrays.asList(PUBLISHER_ID, 54321))),
559                         new VmsAssociatedLayer(new VmsLayer(3, 2, 1),
560                                 Collections.emptySet()),
561                         new VmsAssociatedLayer(new VmsLayer(6, 5, 4),
562                                 Collections.singleton(99999)))),
563                         123));
564 
565         VehiclePropValue response = createHalMessage(
566                 VmsMessageType.AVAILABILITY_RESPONSE,      // Message type
567                 123,                                       // Sequence number
568                 3,                                         // # of associated layers
569                 // Associated layer #1
570                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION,  // Layer
571                 2,                                         // # of publisher IDs
572                 PUBLISHER_ID,                              // Publisher ID
573                 54321,                                     // Publisher ID #2
574                 // Associated layer #2
575                 3, 2, 1,                                   // Layer
576                 0,                                         // # of publisher IDs
577                 // Associated layer #3
578                 6, 5, 4,                                   // Layer
579                 1,                                         // # of publisher IDs
580                 99999                                      // Publisher ID
581 
582         );
583 
584         sendHalMessage(request);
585         verify(mVehicleHal).set(response);
586     }
587 
588     /**
589      * START_SESSION message format:
590      * <ul>
591      * <li>Message type
592      * <li>Core ID
593      * <li>Client ID
594      * </ul>
595      */
596     @Test
testHandleStartSessionEvent()597     public void testHandleStartSessionEvent() throws Exception {
598         when(mSubscriberService.getAvailableLayers()).thenReturn(
599                 new VmsAvailableLayers(Collections.emptySet(), 5));
600 
601         VehiclePropValue request = createHalMessage(
602                 VmsMessageType.START_SESSION,  // Message type
603                 -1,                            // Core ID (unknown)
604                 CLIENT_ID                      // Client ID
605         );
606 
607         VehiclePropValue response = createHalMessage(
608                 VmsMessageType.START_SESSION,  // Message type
609                 CORE_ID,                               // Core ID
610                 CLIENT_ID                              // Client ID
611         );
612 
613         sendHalMessage(request);
614 
615         InOrder inOrder = Mockito.inOrder(mClientManager, mVehicleHal);
616         inOrder.verify(mClientManager).onHalDisconnected();
617         inOrder.verify(mVehicleHal).set(response);
618         inOrder.verify(mClientManager).onHalConnected(mPublisherClient, mSubscriberClient);
619 
620         waitForHandlerCompletion();
621         inOrder.verify(mVehicleHal).set(createHalMessage(
622                 VmsMessageType.AVAILABILITY_CHANGE, // Message type
623                 5,                                  // Sequence number
624                 0));                                // # of associated layers
625 
626     }
627 
628     /**
629      * AVAILABILITY_CHANGE message format:
630      * <ul>
631      * <li>Message type
632      * <li>Sequence number.
633      * <li>Number of associated layers.
634      * <li>Associated layers (x number of associated layers)
635      * <ul>
636      * <li>Layer ID
637      * <li>Layer subtype
638      * <li>Layer version
639      * <li>Number of publishers
640      * <li>Publisher ID (x number of publishers)
641      * </ul>
642      * </ul>
643      */
644     @Test
testOnLayersAvailabilityChanged_ZeroLayers()645     public void testOnLayersAvailabilityChanged_ZeroLayers() throws Exception {
646         mSubscriberClient.onLayersAvailabilityChanged(
647                 new VmsAvailableLayers(Collections.emptySet(), 123));
648 
649         VehiclePropValue message = createHalMessage(
650                 VmsMessageType.AVAILABILITY_CHANGE,    // Message type
651                 123,                                   // Sequence number
652                 0                                      // # of associated layers
653         );
654 
655         waitForHandlerCompletion();
656         verify(mVehicleHal).set(message);
657     }
658 
659     @Test
testOnLayersAvailabilityChanged_OneLayer()660     public void testOnLayersAvailabilityChanged_OneLayer() throws Exception {
661         mSubscriberClient.onLayersAvailabilityChanged(
662                 new VmsAvailableLayers(Collections.singleton(
663                         new VmsAssociatedLayer(LAYER, Collections.singleton(PUBLISHER_ID))), 123));
664 
665         VehiclePropValue message = createHalMessage(
666                 VmsMessageType.AVAILABILITY_CHANGE,        // Message type
667                 123,                                       // Sequence number
668                 1,                                         // # of associated layers
669                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION,  // Layer
670                 1,                                         // # of publisher IDs
671                 PUBLISHER_ID                               // Publisher ID
672         );
673 
674         waitForHandlerCompletion();
675         verify(mVehicleHal).set(message);
676     }
677 
678 
679     @Test
testOnLayersAvailabilityChanged_MultipleLayers()680     public void testOnLayersAvailabilityChanged_MultipleLayers() throws Exception {
681         mSubscriberClient.onLayersAvailabilityChanged(
682                 new VmsAvailableLayers(new LinkedHashSet<>(Arrays.asList(
683                         new VmsAssociatedLayer(LAYER,
684                                 new LinkedHashSet<>(Arrays.asList(PUBLISHER_ID, 54321))),
685                         new VmsAssociatedLayer(new VmsLayer(3, 2, 1),
686                                 Collections.emptySet()),
687                         new VmsAssociatedLayer(new VmsLayer(6, 5, 4),
688                                 Collections.singleton(99999)))),
689                         123));
690 
691         VehiclePropValue message = createHalMessage(
692                 VmsMessageType.AVAILABILITY_CHANGE,      // Message type
693                 123,                                       // Sequence number
694                 3,                                         // # of associated layers
695                 // Associated layer #1
696                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION,  // Layer
697                 2,                                         // # of publisher IDs
698                 PUBLISHER_ID,                              // Publisher ID
699                 54321,                                     // Publisher ID #2
700                 // Associated layer #2
701                 3, 2, 1,                                   // Layer
702                 0,                                         // # of publisher IDs
703                 // Associated layer #3
704                 6, 5, 4,                                   // Layer
705                 1,                                         // # of publisher IDs
706                 99999                                      // Publisher ID
707 
708         );
709 
710         waitForHandlerCompletion();
711         verify(mVehicleHal).set(message);
712     }
713 
714     /**
715      * SUBSCRIPTION_REQUEST message format:
716      * <ul>
717      * <li>Message type
718      * </ul>
719      *
720      * SUBSCRIPTION_RESPONSE message format:
721      * <ul>
722      * <li>Message type
723      * <li>Sequence number
724      * <li>Number of layers
725      * <li>Number of associated layers
726      * <li>Layers (x number of layers)
727      * <ul>
728      * <li>Layer ID
729      * <li>Layer subtype
730      * <li>Layer version
731      * </ul>
732      * <li>Associated layers (x number of associated layers)
733      * <ul>
734      * <li>Layer ID
735      * <li>Layer subtype
736      * <li>Layer version
737      * <li>Number of publishers
738      * <li>Publisher ID (x number of publishers)
739      * </ul>
740      * </ul>
741      */
742     @Test
testHandleSubscriptionsRequestEvent_ZeroLayers()743     public void testHandleSubscriptionsRequestEvent_ZeroLayers() throws Exception {
744         VehiclePropValue request = createHalMessage(
745                 VmsMessageType.SUBSCRIPTIONS_REQUEST  // Message type
746         );
747 
748         when(mPublisherService.getSubscriptions()).thenReturn(
749                 new VmsSubscriptionState(123, Collections.emptySet(), Collections.emptySet()));
750 
751         VehiclePropValue response = createHalMessage(
752                 VmsMessageType.SUBSCRIPTIONS_RESPONSE,  // Message type
753                 123,                                    // Sequence number
754                 0,                                      // # of layers
755                 0                                       // # of associated layers
756         );
757 
758         sendHalMessage(request);
759         verify(mVehicleHal).set(response);
760     }
761 
762     @Test
testHandleSubscriptionsRequestEvent_OneLayer_ZeroAssociatedLayers()763     public void testHandleSubscriptionsRequestEvent_OneLayer_ZeroAssociatedLayers()
764             throws Exception {
765         VehiclePropValue request = createHalMessage(
766                 VmsMessageType.SUBSCRIPTIONS_REQUEST  // Message type
767         );
768 
769         when(mPublisherService.getSubscriptions()).thenReturn(
770                 new VmsSubscriptionState(123, Collections.singleton(LAYER),
771                         Collections.emptySet()));
772 
773         VehiclePropValue response = createHalMessage(
774                 VmsMessageType.SUBSCRIPTIONS_RESPONSE,     // Message type
775                 123,                                       // Sequence number
776                 1,                                         // # of layers
777                 0,                                         // # of associated layers
778                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION   // Layer
779         );
780 
781         sendHalMessage(request);
782         verify(mVehicleHal).set(response);
783     }
784 
785     @Test
testHandleSubscriptionsRequestEvent_ZeroLayers_OneAssociatedLayer()786     public void testHandleSubscriptionsRequestEvent_ZeroLayers_OneAssociatedLayer()
787             throws Exception {
788         VehiclePropValue request = createHalMessage(
789                 VmsMessageType.SUBSCRIPTIONS_REQUEST  // Message type
790         );
791 
792         when(mPublisherService.getSubscriptions()).thenReturn(
793                 new VmsSubscriptionState(123, Collections.emptySet(), Collections.singleton(
794                         new VmsAssociatedLayer(LAYER, Collections.singleton(PUBLISHER_ID)))));
795 
796         VehiclePropValue response = createHalMessage(
797                 VmsMessageType.SUBSCRIPTIONS_RESPONSE,     // Message type
798                 123,                                       // Sequence number
799                 0,                                         // # of layers
800                 1,                                         // # of associated layers
801                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION,  // Layer
802                 1,                                         // # of publisher IDs
803                 PUBLISHER_ID                               // Publisher ID
804         );
805 
806         sendHalMessage(request);
807         verify(mVehicleHal).set(response);
808     }
809 
810     @Test
testHandleSubscriptionsRequestEvent_MultipleLayersAndAssociatedLayers()811     public void testHandleSubscriptionsRequestEvent_MultipleLayersAndAssociatedLayers()
812             throws Exception {
813         VehiclePropValue request = createHalMessage(
814                 VmsMessageType.SUBSCRIPTIONS_REQUEST  // Message type
815         );
816 
817         when(mPublisherService.getSubscriptions()).thenReturn(
818                 new VmsSubscriptionState(123,
819                         new LinkedHashSet<>(Arrays.asList(
820                                 LAYER,
821                                 new VmsLayer(4, 5, 6),
822                                 new VmsLayer(7, 8, 9)
823                         )),
824                         new LinkedHashSet<>(Arrays.asList(
825                                 new VmsAssociatedLayer(LAYER, Collections.emptySet()),
826                                 new VmsAssociatedLayer(new VmsLayer(6, 5, 4),
827                                         new LinkedHashSet<>(Arrays.asList(
828                                                 PUBLISHER_ID,
829                                                 54321))))))
830         );
831 
832         VehiclePropValue response = createHalMessage(
833                 VmsMessageType.SUBSCRIPTIONS_RESPONSE,     // Message type
834                 123,                                       // Sequence number
835                 3,                                         // # of layers
836                 2,                                         // # of associated layers
837                 // Layer #1
838                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION,  // Layer
839                 // Layer #2
840                 4, 5, 6,                                   // Layer
841                 // Layer #3
842                 7, 8, 9,                                   // Layer
843                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION,  // Layer
844                 0,                                         // # of publisher IDs
845                 6, 5, 4,                                   // Layer
846                 2,                                         // # of publisher IDs
847                 PUBLISHER_ID,                              // Publisher ID
848                 54321                                      // Publisher ID #2
849         );
850 
851         sendHalMessage(request);
852         verify(mVehicleHal).set(response);
853     }
854 
855     /**
856      * SUBSCRIPTIONS_CHANGE message format:
857      * <ul>
858      * <li>Message type
859      * <li>Sequence number
860      * <li>Number of layers
861      * <li>Number of associated layers
862      * <li>Layers (x number of layers)
863      * <ul>
864      * <li>Layer ID
865      * <li>Layer subtype
866      * <li>Layer version
867      * </ul>
868      * <li>Associated layers (x number of associated layers)
869      * <ul>
870      * <li>Layer ID
871      * <li>Layer subtype
872      * <li>Layer version
873      * <li>Number of publishers
874      * <li>Publisher ID (x number of publishers)
875      * </ul>
876      * </ul>
877      */
878     @Test
testOnVmsSubscriptionChange_ZeroLayers()879     public void testOnVmsSubscriptionChange_ZeroLayers() throws Exception {
880         mPublisherClient.onVmsSubscriptionChange(
881                 new VmsSubscriptionState(123, Collections.emptySet(), Collections.emptySet()));
882 
883         VehiclePropValue response = createHalMessage(
884                 VmsMessageType.SUBSCRIPTIONS_CHANGE,    // Message type
885                 123,                                    // Sequence number
886                 0,                                      // # of layers
887                 0                                       // # of associated layers
888         );
889 
890         waitForHandlerCompletion();
891         verify(mVehicleHal).set(response);
892     }
893 
894     @Test
testOnVmsSubscriptionChange_OneLayer_ZeroAssociatedLayers()895     public void testOnVmsSubscriptionChange_OneLayer_ZeroAssociatedLayers()
896             throws Exception {
897         mPublisherClient.onVmsSubscriptionChange(
898                 new VmsSubscriptionState(123, Collections.singleton(LAYER),
899                         Collections.emptySet()));
900 
901         VehiclePropValue response = createHalMessage(
902                 VmsMessageType.SUBSCRIPTIONS_CHANGE,       // Message type
903                 123,                                       // Sequence number
904                 1,                                         // # of layers
905                 0,                                         // # of associated layers
906                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION   // Layer
907         );
908 
909         waitForHandlerCompletion();
910         verify(mVehicleHal).set(response);
911     }
912 
913     @Test
testOnVmsSubscriptionChange_ZeroLayers_OneAssociatedLayer()914     public void testOnVmsSubscriptionChange_ZeroLayers_OneAssociatedLayer()
915             throws Exception {
916         mPublisherClient.onVmsSubscriptionChange(
917                 new VmsSubscriptionState(123, Collections.emptySet(), Collections.singleton(
918                         new VmsAssociatedLayer(LAYER, Collections.singleton(PUBLISHER_ID)))));
919 
920         VehiclePropValue response = createHalMessage(
921                 VmsMessageType.SUBSCRIPTIONS_CHANGE,       // Message type
922                 123,                                       // Sequence number
923                 0,                                         // # of layers
924                 1,                                         // # of associated layers
925                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION,  // Layer
926                 1,                                         // # of publisher IDs
927                 PUBLISHER_ID                               // Publisher ID
928         );
929 
930         waitForHandlerCompletion();
931         verify(mVehicleHal).set(response);
932     }
933 
934     @Test
testOnVmsSubscriptionChange_MultipleLayersAndAssociatedLayers()935     public void testOnVmsSubscriptionChange_MultipleLayersAndAssociatedLayers()
936             throws Exception {
937         mPublisherClient.onVmsSubscriptionChange(
938                 new VmsSubscriptionState(123,
939                         new LinkedHashSet<>(Arrays.asList(
940                                 LAYER,
941                                 new VmsLayer(4, 5, 6),
942                                 new VmsLayer(7, 8, 9)
943                         )),
944                         new LinkedHashSet<>(Arrays.asList(
945                                 new VmsAssociatedLayer(LAYER, Collections.emptySet()),
946                                 new VmsAssociatedLayer(new VmsLayer(6, 5, 4),
947                                         new LinkedHashSet<>(Arrays.asList(
948                                                 PUBLISHER_ID,
949                                                 54321))))))
950         );
951 
952         VehiclePropValue response = createHalMessage(
953                 VmsMessageType.SUBSCRIPTIONS_CHANGE,       // Message type
954                 123,                                       // Sequence number
955                 3,                                         // # of layers
956                 2,                                         // # of associated layers
957                 // Layer #1
958                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION,  // Layer
959                 // Layer #2
960                 4, 5, 6,                                   // Layer
961                 // Layer #3
962                 7, 8, 9,                                   // Layer
963                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION,  // Layer
964                 0,                                         // # of publisher IDs
965                 6, 5, 4,                                   // Layer
966                 2,                                         // # of publisher IDs
967                 PUBLISHER_ID,                              // Publisher ID
968                 54321                                      // Publisher ID #2
969         );
970 
971         waitForHandlerCompletion();
972         verify(mVehicleHal).set(response);
973     }
974 
975     @Test
testPropertySetExceptionNotPropagated_CoreStartSession()976     public void testPropertySetExceptionNotPropagated_CoreStartSession() throws Exception {
977         doThrow(new RuntimeException()).when(mVehicleHal).set(any());
978         initHalService(false);
979 
980         mHalService.init();
981         waitForHandlerCompletion();
982     }
983 
984     @Test
testPropertySetExceptionNotPropagated_ClientStartSession()985     public void testPropertySetExceptionNotPropagated_ClientStartSession() throws Exception {
986         initHalService(false);
987 
988         when(mSubscriberService.getAvailableLayers()).thenReturn(
989                 new VmsAvailableLayers(Collections.emptySet(), 0));
990         doThrow(new RuntimeException()).when(mVehicleHal).set(any());
991 
992         VehiclePropValue request = createHalMessage(
993                 VmsMessageType.START_SESSION,  // Message type
994                 -1,                            // Core ID (unknown)
995                 CLIENT_ID                      // Client ID
996         );
997 
998         sendHalMessage(request);
999         waitForHandlerCompletion();
1000     }
1001 
1002     @Test
testDumpMetrics_DefaultConfig()1003     public void testDumpMetrics_DefaultConfig() {
1004         mHalService.dumpMetrics(new FileDescriptor());
1005         verifyZeroInteractions(mVehicleHal);
1006     }
1007 
1008     @Test
testDumpMetrics_NonVendorProperty()1009     public void testDumpMetrics_NonVendorProperty() throws Exception {
1010         VehiclePropValue vehicleProp = new VehiclePropValue();
1011         vehicleProp.value.bytes.addAll(PAYLOAD_AS_LIST);
1012         when(mVehicleHal.get(anyInt())).thenReturn(vehicleProp);
1013 
1014         when(mResources.getInteger(
1015                 R.integer.vmsHalClientMetricsProperty)).thenReturn(
1016                 VehicleProperty.VEHICLE_MAP_SERVICE);
1017         setUp();
1018 
1019         mHalService.dumpMetrics(new FileDescriptor());
1020         verifyZeroInteractions(mVehicleHal);
1021     }
1022 
1023     @Test
testDumpMetrics_VendorProperty()1024     public void testDumpMetrics_VendorProperty() throws Exception {
1025         int metricsPropertyId = VehiclePropertyGroup.VENDOR | 1;
1026         when(mResources.getInteger(
1027                 R.integer.vmsHalClientMetricsProperty)).thenReturn(
1028                 metricsPropertyId);
1029         setUp();
1030 
1031         VehiclePropValue metricsProperty = new VehiclePropValue();
1032         metricsProperty.value.bytes.addAll(PAYLOAD_AS_LIST);
1033         when(mVehicleHal.get(metricsPropertyId)).thenReturn(metricsProperty);
1034 
1035         try (TemporaryFile dumpsysFile = new TemporaryFile("VmsHalServiceTest")) {
1036             FileOutputStream outputStream = new FileOutputStream(dumpsysFile.getFile());
1037             mHalService.dumpMetrics(outputStream.getFD());
1038 
1039             verify(mVehicleHal).get(metricsPropertyId);
1040             FileInputStream inputStream = new FileInputStream(dumpsysFile.getFile());
1041             byte[] dumpsysOutput = new byte[PAYLOAD.length];
1042             assertEquals(PAYLOAD.length, inputStream.read(dumpsysOutput));
1043             assertArrayEquals(PAYLOAD, dumpsysOutput);
1044         }
1045     }
1046 
1047     @Test
testDumpMetrics_VendorProperty_Timeout()1048     public void testDumpMetrics_VendorProperty_Timeout() throws Exception {
1049         int metricsPropertyId = VehiclePropertyGroup.VENDOR | 1;
1050         when(mResources.getInteger(
1051                 R.integer.vmsHalClientMetricsProperty)).thenReturn(
1052                 metricsPropertyId);
1053         setUp();
1054 
1055         when(mVehicleHal.get(metricsPropertyId))
1056                 .thenThrow(new PropertyTimeoutException(metricsPropertyId));
1057 
1058         mHalService.dumpMetrics(new FileDescriptor());
1059         verify(mVehicleHal).get(metricsPropertyId);
1060     }
1061 
1062     @Test
testDumpMetrics_VendorProperty_Unavailable()1063     public void testDumpMetrics_VendorProperty_Unavailable() throws Exception {
1064         int metricsPropertyId = VehiclePropertyGroup.VENDOR | 1;
1065         when(mResources.getInteger(
1066                 R.integer.vmsHalClientMetricsProperty)).thenReturn(
1067                 metricsPropertyId);
1068         setUp();
1069 
1070         when(mVehicleHal.get(metricsPropertyId)).thenReturn(null);
1071 
1072         mHalService.dumpMetrics(new FileDescriptor());
1073         verify(mVehicleHal).get(metricsPropertyId);
1074     }
1075 
createHalMessage(Integer... message)1076     private static VehiclePropValue createHalMessage(Integer... message) {
1077         VehiclePropValue result = new VehiclePropValue();
1078         result.prop = VehicleProperty.VEHICLE_MAP_SERVICE;
1079         result.value.int32Values.addAll(Arrays.asList(message));
1080         return result;
1081     }
1082 
sendHalMessage(VehiclePropValue message)1083     private void sendHalMessage(VehiclePropValue message) {
1084         mHalService.handleHalEvents(Collections.singletonList(message));
1085     }
1086 
waitForHandlerCompletion()1087     private void waitForHandlerCompletion() throws Exception {
1088         final CountDownLatch latch = new CountDownLatch(1);
1089         mHalService.getHandler().post(latch::countDown);
1090         latch.await(5, TimeUnit.SECONDS);
1091     }
1092 }
1093