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