1 /*
2  * Copyright (C) 2019 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;
17 
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertTrue;
20 
21 import android.car.Car;
22 import android.car.VehicleAreaType;
23 import android.car.vms.VmsAvailableLayers;
24 import android.car.vms.VmsLayer;
25 import android.car.vms.VmsPublisherClientService;
26 import android.car.vms.VmsSubscriberManager;
27 import android.car.vms.VmsSubscriptionState;
28 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
29 import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
30 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyAccess;
31 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyChangeMode;
32 import android.hardware.automotive.vehicle.V2_0.VmsAvailabilityStateIntegerValuesIndex;
33 import android.hardware.automotive.vehicle.V2_0.VmsBaseMessageIntegerValuesIndex;
34 import android.hardware.automotive.vehicle.V2_0.VmsMessageType;
35 import android.hardware.automotive.vehicle.V2_0.VmsStartSessionMessageIntegerValuesIndex;
36 import android.util.Log;
37 import android.util.Pair;
38 
39 import com.android.car.vehiclehal.VehiclePropValueBuilder;
40 import com.android.car.vehiclehal.test.MockedVehicleHal;
41 
42 import org.junit.Before;
43 
44 import java.util.List;
45 import java.util.concurrent.BlockingQueue;
46 import java.util.concurrent.CountDownLatch;
47 import java.util.concurrent.Executors;
48 import java.util.concurrent.LinkedBlockingQueue;
49 import java.util.concurrent.TimeUnit;
50 
51 public class MockedVmsTestBase extends MockedCarTestBase {
52     public static final long PUBLISHER_CLIENT_TIMEOUT = 500L;
53     public static final long MESSAGE_RECEIVE_TIMEOUT = 500L;
54     private static final String TAG = "MockedVmsTestBase";
55 
56     private MockPublisherClient mPublisherClient;
57     private CountDownLatch mPublisherIsReady = new CountDownLatch(1);
58     private VmsSubscriberManager mVmsSubscriberManager;
59     private MockSubscriberClient mSubscriberClient;
60     private MockHalClient mHalClient;
61 
62     @Override
configureMockedHal()63     protected synchronized void configureMockedHal() {
64         mHalClient = new MockHalClient();
65         addProperty(VehicleProperty.VEHICLE_MAP_SERVICE, mHalClient)
66                 .setChangeMode(VehiclePropertyChangeMode.ON_CHANGE)
67                 .setAccess(VehiclePropertyAccess.READ_WRITE)
68                 .addAreaConfig(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 0, 0);
69     }
70 
71     @Before
setUpVms()72     public void setUpVms() throws Exception {
73         mPublisherClient = new MockPublisherClient();
74         mPublisherClient.setMockCar(getCar());
75         mVmsSubscriberManager = (VmsSubscriberManager) getCar().getCarManager(
76                 Car.VMS_SUBSCRIBER_SERVICE);
77         mSubscriberClient = new MockSubscriberClient();
78         mVmsSubscriberManager.setVmsSubscriberClientCallback(Executors.newSingleThreadExecutor(),
79                 mSubscriberClient);
80 
81         assertTrue(
82                 "Timeout while waiting for publisher client to be ready",
83                 mPublisherIsReady.await(PUBLISHER_CLIENT_TIMEOUT, TimeUnit.MILLISECONDS));
84 
85         // Validate session handshake
86         List<Integer> v = mHalClient.receiveMessage().value.int32Values;
87         assertEquals(VmsMessageType.START_SESSION,
88                 (int) v.get(VmsBaseMessageIntegerValuesIndex.MESSAGE_TYPE));
89         int coreId = v.get(VmsStartSessionMessageIntegerValuesIndex.SERVICE_ID);
90         assertTrue(coreId > 0);
91         assertEquals(-1, (int) v.get(VmsStartSessionMessageIntegerValuesIndex.CLIENT_ID));
92 
93         // Send handshake acknowledgement
94         mHalClient.sendMessage(
95                 VmsMessageType.START_SESSION,
96                 coreId,
97                 12345 // Client ID
98         );
99 
100         // Validate layer availability sent to HAL
101         v = mHalClient.receiveMessage().value.int32Values;
102         assertEquals(VmsMessageType.AVAILABILITY_CHANGE,
103                 (int) v.get(VmsAvailabilityStateIntegerValuesIndex.MESSAGE_TYPE));
104         assertEquals(0,
105                 (int) v.get(VmsAvailabilityStateIntegerValuesIndex.SEQUENCE_NUMBER));
106         assertEquals(0,
107                 (int) v.get(VmsAvailabilityStateIntegerValuesIndex.NUMBER_OF_ASSOCIATED_LAYERS));
108     }
109 
getSubscriberManager()110     VmsSubscriberManager getSubscriberManager() {
111         return mVmsSubscriberManager;
112     }
113 
getMockPublisherClient()114     MockPublisherClient getMockPublisherClient() {
115         return mPublisherClient;
116     }
117 
getMockSubscriberClient()118     MockSubscriberClient getMockSubscriberClient() {
119         return mSubscriberClient;
120     }
121 
getMockHalClient()122     MockHalClient getMockHalClient() {
123         return mHalClient;
124     }
125 
126     class MockPublisherClient extends VmsPublisherClientService {
127         private BlockingQueue<VmsSubscriptionState> mSubscriptionState =
128                 new LinkedBlockingQueue<>();
129 
setMockCar(Car car)130         void setMockCar(Car car) {
131             onCarLifecycleChanged(car, true);
132         }
133 
134         @Override
onVmsPublisherServiceReady()135         protected void onVmsPublisherServiceReady() {
136             Log.d(TAG, "MockPublisherClient.onVmsPublisherServiceReady");
137             mPublisherIsReady.countDown();
138         }
139 
140         @Override
onVmsSubscriptionChange(VmsSubscriptionState subscriptionState)141         public void onVmsSubscriptionChange(VmsSubscriptionState subscriptionState) {
142             Log.d(TAG, "MockPublisherClient.onVmsSubscriptionChange: "
143                     + subscriptionState.getSequenceNumber());
144             mSubscriptionState.add(subscriptionState);
145         }
146 
receiveSubscriptionState()147         VmsSubscriptionState receiveSubscriptionState() {
148             return receiveWithTimeout(mSubscriptionState);
149         }
150     }
151 
152     class MockSubscriberClient implements VmsSubscriberManager.VmsSubscriberClientCallback {
153         private BlockingQueue<Pair<VmsLayer, byte[]>> mMessages = new LinkedBlockingQueue<>();
154         private BlockingQueue<VmsAvailableLayers> mAvailableLayers = new LinkedBlockingQueue<>();
155 
156         @Override
onVmsMessageReceived(VmsLayer layer, byte[] payload)157         public void onVmsMessageReceived(VmsLayer layer, byte[] payload) {
158             Log.d(TAG, "MockSubscriberClient.onVmsMessageReceived");
159             mMessages.add(Pair.create(layer, payload));
160         }
161 
162         @Override
onLayersAvailabilityChanged(VmsAvailableLayers availableLayers)163         public void onLayersAvailabilityChanged(VmsAvailableLayers availableLayers) {
164             Log.d(TAG, "MockSubscriberClient.onVmsMessageReceived");
165             mAvailableLayers.add(availableLayers);
166         }
167 
receiveMessage()168         Pair<VmsLayer, byte[]> receiveMessage() {
169             return receiveWithTimeout(mMessages);
170         }
171 
receiveLayerAvailability()172         VmsAvailableLayers receiveLayerAvailability() {
173             return receiveWithTimeout(mAvailableLayers);
174         }
175     }
176 
177     class MockHalClient implements MockedVehicleHal.VehicleHalPropertyHandler {
178         private BlockingQueue<VehiclePropValue> mMessages = new LinkedBlockingQueue<>();
179 
180         @Override
onPropertySet(VehiclePropValue value)181         public void onPropertySet(VehiclePropValue value) {
182             Log.d(TAG, "MockHalClient.onPropertySet");
183             if (value.prop == VehicleProperty.VEHICLE_MAP_SERVICE) {
184                 mMessages.add(value);
185             }
186         }
187 
sendMessage(int... message)188         void sendMessage(int... message) {
189             getMockedVehicleHal().injectEvent(
190                     VehiclePropValueBuilder.newBuilder(VehicleProperty.VEHICLE_MAP_SERVICE)
191                             .addIntValue(message)
192                             .build());
193         }
194 
sendMessage(int[] message, byte[] payload)195         void sendMessage(int[] message, byte[] payload) {
196             getMockedVehicleHal().injectEvent(
197                     VehiclePropValueBuilder.newBuilder(VehicleProperty.VEHICLE_MAP_SERVICE)
198                             .addIntValue(message)
199                             .addByteValue(payload)
200                             .build());
201         }
202 
receiveMessage()203         VehiclePropValue receiveMessage() {
204             return receiveWithTimeout(mMessages);
205         }
206     }
207 
receiveWithTimeout(BlockingQueue<T> queue)208     private static <T> T receiveWithTimeout(BlockingQueue<T> queue) {
209         try {
210             return queue.poll(MESSAGE_RECEIVE_TIMEOUT, TimeUnit.MILLISECONDS);
211         } catch (InterruptedException e) {
212             throw new RuntimeException(e);
213         }
214     }
215 }
216