MockedCarTestBase.java revision ed2c864d177dcdfd8fde7ada9728b665fc058a13
1/* 2 * Copyright (C) 2015 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 */ 16package com.android.car; 17 18import static org.junit.Assert.assertNotNull; 19import static org.junit.Assert.fail; 20 21import android.car.test.CarTestManager; 22import android.car.test.CarTestManagerBinderWrapper; 23import android.content.ComponentName; 24import android.content.Context; 25import android.content.ContextWrapper; 26import android.content.ServiceConnection; 27import android.content.pm.PackageManager.NameNotFoundException; 28import android.content.res.Resources; 29import android.hardware.automotive.vehicle.V2_0.VehicleDrivingStatus; 30import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; 31import android.hardware.automotive.vehicle.V2_0.VehicleProperty; 32import android.hardware.automotive.vehicle.V2_0.VehiclePropertyAccess; 33import android.hardware.automotive.vehicle.V2_0.VehiclePropertyChangeMode; 34import android.os.Binder; 35import android.os.Handler; 36import android.os.IBinder; 37import android.os.Looper; 38import android.support.test.InstrumentationRegistry; 39import android.support.test.annotation.UiThreadTest; 40import android.util.Log; 41import android.util.SparseArray; 42 43import com.android.car.systeminterface.DisplayInterface; 44import com.android.car.systeminterface.IOInterface; 45import com.android.car.systeminterface.StorageMonitoringInterface; 46import com.android.car.systeminterface.SystemInterface; 47import com.android.car.systeminterface.SystemInterface.Builder; 48import com.android.car.systeminterface.SystemStateInterface; 49import com.android.car.systeminterface.TimeInterface; 50import com.android.car.systeminterface.WakeLockInterface; 51import com.android.car.test.utils.TemporaryDirectory; 52import com.android.car.vehiclehal.VehiclePropValueBuilder; 53import com.android.car.vehiclehal.test.MockedVehicleHal; 54import com.android.car.vehiclehal.test.MockedVehicleHal.DefaultPropertyHandler; 55import com.android.car.vehiclehal.test.MockedVehicleHal.StaticPropertyHandler; 56import com.android.car.vehiclehal.test.MockedVehicleHal.VehicleHalPropertyHandler; 57import com.android.car.vehiclehal.test.VehiclePropConfigBuilder; 58 59import org.junit.After; 60import org.junit.Before; 61 62import java.io.File; 63import java.io.IOException; 64import java.time.Duration; 65import java.util.Arrays; 66import java.util.HashMap; 67import java.util.Map; 68import java.util.concurrent.Semaphore; 69 70/** 71 * Base class for testing with mocked vehicle HAL (=car). 72 * It is up to each app to start emulation by getMockedVehicleHal().start() as there will be 73 * per test set up that should be done before starting. 74 */ 75public class MockedCarTestBase { 76 private static final String TAG = MockedCarTestBase.class.getSimpleName(); 77 static final long DEFAULT_WAIT_TIMEOUT_MS = 3000; 78 static final long SHORT_WAIT_TIMEOUT_MS = 500; 79 80 private android.car.Car mCar; 81 private ICarImpl mCarImpl; 82 private MockedVehicleHal mMockedVehicleHal; 83 private SystemInterface mFakeSystemInterface; 84 private MockContext mMockContext; 85 private final MockIOInterface mMockIOInterface = new MockIOInterface(); 86 87 private final Handler mMainHandler = new Handler(Looper.getMainLooper()); 88 89 private final Map<VehiclePropConfigBuilder, VehicleHalPropertyHandler> mHalConfig = 90 new HashMap<>(); 91 private final SparseArray<VehiclePropConfigBuilder> mPropToConfigBuilder = new SparseArray<>(); 92 93 private static final IBinder mCarServiceToken = new Binder(); 94 private static boolean mRealCarServiceReleased = false; 95 96 protected synchronized MockedVehicleHal createMockedVehicleHal() { 97 return new MockedVehicleHal(); 98 } 99 100 protected synchronized MockedVehicleHal getMockedVehicleHal() { 101 return mMockedVehicleHal; 102 } 103 104 protected synchronized SystemInterface getFakeSystemInterface() { 105 return mFakeSystemInterface; 106 } 107 108 protected synchronized void configureMockedHal() { 109 } 110 111 protected synchronized SystemInterface.Builder getSystemInterfaceBuilder() { 112 return Builder.newSystemInterface() 113 .withSystemStateInterface(new MockSystemStateInterface()) 114 .withDisplayInterface(new MockDisplayInterface()) 115 .withIOInterface(mMockIOInterface) 116 .withStorageMonitoringInterface(new MockStorageMonitoringInterface()) 117 .withTimeInterface(new MockTimeInterface()) 118 .withWakeLockInterface(new MockWakeLockInterface()); 119 } 120 121 protected synchronized void configureFakeSystemInterface() {} 122 123 protected synchronized void configureResourceOverrides(MockResources resources) { 124 resources.overrideResource(com.android.car.R.string.instrumentClusterRendererService, ""); 125 } 126 127 protected Context getContext() { 128 return InstrumentationRegistry.getTargetContext(); 129 } 130 131 protected Context getTestContext() { 132 return InstrumentationRegistry.getContext(); 133 } 134 135 protected String getFlattenComponent(Class cls) { 136 ComponentName cn = new ComponentName(getTestContext(), cls); 137 return cn.flattenToString(); 138 } 139 140 @Before 141 @UiThreadTest 142 public void setUp() throws Exception { 143 Log.i(TAG, "setUp"); 144 releaseRealCarService(getContext()); 145 146 mMockedVehicleHal = createMockedVehicleHal(); 147 addProperty(VehicleProperty.DRIVING_STATUS, 148 VehiclePropValueBuilder.newBuilder(VehicleProperty.DRIVING_STATUS) 149 .addIntValue(VehicleDrivingStatus.UNRESTRICTED) 150 .build()); 151 configureMockedHal(); 152 153 mFakeSystemInterface = getSystemInterfaceBuilder().build(); 154 configureFakeSystemInterface(); 155 156 MockContext context = getCarServiceContext(); 157 configureResourceOverrides(context.getResources()); 158 159 mCarImpl = new ICarImpl(context, mMockedVehicleHal, mFakeSystemInterface, 160 null /* error notifier */); 161 162 initMockedHal(false /* no need to release */); 163 164 mCar = new android.car.Car(context, mCarImpl, null /* handler */); 165 } 166 167 @After 168 public void tearDown() throws Exception { 169 mCar.disconnect(); 170 mCarImpl.release(); 171 172 mMockIOInterface.tearDown(); 173 } 174 175 protected MockContext getCarServiceContext() throws NameNotFoundException { 176 if (mMockContext == null) { 177 mMockContext = new MockContext(getContext() 178 .createPackageContext("com.android.car", Context.CONTEXT_IGNORE_SECURITY)); 179 } 180 return mMockContext; 181 } 182 183 protected synchronized void reinitializeMockedHal() throws Exception { 184 initMockedHal(true /* release */); 185 } 186 187 private synchronized void initMockedHal(boolean release) throws Exception { 188 if (release) { 189 mCarImpl.release(); 190 } 191 192 for (Map.Entry<VehiclePropConfigBuilder, VehicleHalPropertyHandler> entry 193 : mHalConfig.entrySet()) { 194 mMockedVehicleHal.addProperty(entry.getKey().build(), entry.getValue()); 195 } 196 mHalConfig.clear(); 197 mCarImpl.init(); 198 } 199 200 protected synchronized VehiclePropConfigBuilder addProperty(int propertyId, 201 VehicleHalPropertyHandler propertyHandler) { 202 VehiclePropConfigBuilder builder = VehiclePropConfigBuilder.newBuilder(propertyId); 203 setConfigBuilder(builder, propertyHandler); 204 return builder; 205 } 206 207 protected synchronized VehiclePropConfigBuilder addProperty(int propertyId) { 208 VehiclePropConfigBuilder builder = VehiclePropConfigBuilder.newBuilder(propertyId); 209 setConfigBuilder(builder, new DefaultPropertyHandler(builder.build(), null)); 210 return builder; 211 } 212 213 protected synchronized VehiclePropConfigBuilder addProperty(int propertyId, 214 VehiclePropValue value) { 215 VehiclePropConfigBuilder builder = VehiclePropConfigBuilder.newBuilder(propertyId); 216 setConfigBuilder(builder, new DefaultPropertyHandler(builder.build(), value)); 217 return builder; 218 } 219 220 protected synchronized VehiclePropConfigBuilder addStaticProperty(int propertyId, 221 VehiclePropValue value) { 222 VehiclePropConfigBuilder builder = VehiclePropConfigBuilder.newBuilder(propertyId) 223 .setChangeMode(VehiclePropertyChangeMode.STATIC) 224 .setAccess(VehiclePropertyAccess.READ); 225 226 setConfigBuilder(builder, new StaticPropertyHandler(value)); 227 return builder; 228 } 229 230 private void setConfigBuilder(VehiclePropConfigBuilder builder, 231 VehicleHalPropertyHandler propertyHandler) { 232 int propId = builder.build().prop; 233 234 // Override previous property config if exists. 235 VehiclePropConfigBuilder prevBuilder = mPropToConfigBuilder.get(propId); 236 if (prevBuilder != null) { 237 mHalConfig.remove(prevBuilder); 238 } 239 mPropToConfigBuilder.put(propId, builder); 240 mHalConfig.put(builder, propertyHandler); 241 } 242 243 protected synchronized android.car.Car getCar() { 244 return mCar; 245 } 246 247 /* 248 * In order to eliminate interfering with real car service we will disable it. It will be 249 * enabled back in CarTestService when mCarServiceToken will go away (tests finish). 250 */ 251 private synchronized static void releaseRealCarService(Context context) throws Exception { 252 if (mRealCarServiceReleased) { 253 return; // We just want to release it once. 254 } 255 256 mRealCarServiceReleased = true; // To make sure it was called once. 257 258 Object waitForConnection = new Object(); 259 android.car.Car car = android.car.Car.createCar(context, new ServiceConnection() { 260 @Override 261 public void onServiceConnected(ComponentName name, IBinder service) { 262 synchronized (waitForConnection) { 263 waitForConnection.notify(); 264 } 265 } 266 267 @Override 268 public void onServiceDisconnected(ComponentName name) { } 269 }); 270 271 car.connect(); 272 synchronized (waitForConnection) { 273 if (!car.isConnected()) { 274 waitForConnection.wait(DEFAULT_WAIT_TIMEOUT_MS); 275 } 276 } 277 278 if (car.isConnected()) { 279 Log.i(TAG, "Connected to real car service"); 280 CarTestManagerBinderWrapper binderWrapper = 281 (CarTestManagerBinderWrapper) car.getCarManager(android.car.Car.TEST_SERVICE); 282 assertNotNull(binderWrapper); 283 284 CarTestManager mgr = new CarTestManager(binderWrapper.binder); 285 mgr.stopCarService(mCarServiceToken); 286 } 287 } 288 289 static final class MockDisplayInterface implements DisplayInterface { 290 291 @Override 292 public void setDisplayState(boolean on) {} 293 294 @Override 295 public void startDisplayStateMonitoring(CarPowerManagementService service) {} 296 297 @Override 298 public void stopDisplayStateMonitoring() {} 299 } 300 301 static final class MockIOInterface implements IOInterface { 302 private TemporaryDirectory mFilesDir = null; 303 304 @Override 305 public File getFilesDir() { 306 if (mFilesDir == null) { 307 try { 308 mFilesDir = new TemporaryDirectory(TAG); 309 } catch (IOException e) { 310 Log.e(TAG, "failed to create temporary directory", e); 311 fail("failed to create temporary directory. exception was: " + e); 312 } 313 } 314 return mFilesDir.getDirectory(); 315 } 316 317 public void tearDown() { 318 if (mFilesDir != null) { 319 try { 320 mFilesDir.close(); 321 } catch (Exception e) { 322 Log.w(TAG, "could not remove temporary directory", e); 323 } 324 } 325 } 326 } 327 328 static final class MockResources extends Resources { 329 private final HashMap<Integer, Integer> mIntegerOverrides = new HashMap<>(); 330 private final HashMap<Integer, String> mStringOverrides = new HashMap<>(); 331 private final HashMap<Integer, String[]> mStringArrayOverrides = new HashMap<>(); 332 333 MockResources(Resources resources) { 334 super(resources.getAssets(), 335 resources.getDisplayMetrics(), 336 resources.getConfiguration()); 337 } 338 339 @Override 340 public int getInteger(int id) { 341 return mIntegerOverrides.getOrDefault(id, 342 super.getInteger(id)); 343 } 344 345 @Override 346 public String getString(int id) { 347 return mStringOverrides.getOrDefault(id, 348 super.getString(id)); 349 } 350 351 @Override 352 public String[] getStringArray(int id) { 353 return mStringArrayOverrides.getOrDefault(id, 354 super.getStringArray(id)); 355 } 356 357 MockResources overrideResource(int id, int value) { 358 mIntegerOverrides.put(id, value); 359 return this; 360 } 361 362 MockResources overrideResource(int id, String value) { 363 mStringOverrides.put(id, value); 364 return this; 365 } 366 367 MockResources overrideResource(int id, String[] value) { 368 mStringArrayOverrides.put(id, value); 369 return this; 370 } 371 } 372 373 static final class MockContext extends ContextWrapper { 374 private final MockResources mResources; 375 376 MockContext(Context base) { 377 super(base); 378 mResources = new MockResources(super.getResources()); 379 } 380 381 @Override 382 public MockResources getResources() { 383 return mResources; 384 } 385 } 386 387 static final class MockStorageMonitoringInterface implements StorageMonitoringInterface {} 388 389 static final class MockSystemStateInterface implements SystemStateInterface { 390 @Override 391 public void shutdown() {} 392 393 @Override 394 public void enterDeepSleep(int wakeupTimeSec) {} 395 396 @Override 397 public void scheduleActionForBootCompleted(Runnable action, Duration delay) {} 398 } 399 400 static final class MockTimeInterface implements TimeInterface { 401 402 @Override 403 public void scheduleAction(Runnable r, long delayMs) {} 404 405 @Override 406 public void cancelAllActions() {} 407 } 408 409 static final class MockWakeLockInterface implements WakeLockInterface { 410 411 @Override 412 public void releaseAllWakeLocks() {} 413 414 @Override 415 public void switchToPartialWakeLock() {} 416 417 @Override 418 public void switchToFullWakeLock() {} 419 } 420 421} 422