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