MockedCarTestBase.java revision 9c1f27227f843f10a2d286ded886464b60854e08
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 android.car.test.CarTestManager; 19import android.car.test.CarTestManagerBinderWrapper; 20import android.content.ComponentName; 21import android.content.Context; 22import android.content.ServiceConnection; 23import android.content.pm.PackageManager.NameNotFoundException; 24import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; 25import android.hardware.automotive.vehicle.V2_0.VehiclePropertyAccess; 26import android.hardware.automotive.vehicle.V2_0.VehiclePropertyChangeMode; 27import android.os.Binder; 28import android.os.Handler; 29import android.os.IBinder; 30import android.os.Looper; 31import android.os.SystemClock; 32import android.test.AndroidTestCase; 33import android.util.Log; 34 35import com.android.car.MockedCarTestBase.FakeSystemInterface.UptimeProvider; 36import com.android.car.storagemonitoring.WearInformation; 37import com.android.car.storagemonitoring.WearInformationProvider; 38import com.android.car.test.utils.TemporaryDirectory; 39import com.android.car.vehiclehal.test.MockedVehicleHal; 40import com.android.car.vehiclehal.test.MockedVehicleHal.DefaultPropertyHandler; 41import com.android.car.vehiclehal.test.MockedVehicleHal.StaticPropertyHandler; 42import com.android.car.vehiclehal.test.MockedVehicleHal.VehicleHalPropertyHandler; 43import com.android.car.vehiclehal.test.VehiclePropConfigBuilder; 44 45import java.io.File; 46import java.io.IOException; 47import java.util.Arrays; 48import java.util.HashMap; 49import java.util.Map; 50import java.util.concurrent.Semaphore; 51import java.util.concurrent.TimeUnit; 52 53/** 54 * Base class for testing with mocked vehicle HAL (=car). 55 * It is up to each app to start emulation by getMockedVehicleHal().start() as there will be 56 * per test set up that should be done before starting. 57 */ 58public class MockedCarTestBase extends AndroidTestCase { 59 private static final String TAG = MockedCarTestBase.class.getSimpleName(); 60 static final long DEFAULT_WAIT_TIMEOUT_MS = 3000; 61 static final long SHORT_WAIT_TIMEOUT_MS = 500; 62 63 private android.car.Car mCar; 64 private ICarImpl mCarImpl; 65 private MockedVehicleHal mMockedVehicleHal; 66 private FakeSystemInterface mFakeSystemInterface; 67 68 private final Semaphore mWaitForMain = new Semaphore(0); 69 private final Handler mMainHandler = new Handler(Looper.getMainLooper()); 70 71 private static final IBinder mCarServiceToken = new Binder(); 72 private static boolean mRealCarServiceReleased = false; 73 74 protected synchronized MockedVehicleHal createMockedVehicleHal() { 75 return new MockedVehicleHal(); 76 } 77 78 protected synchronized MockedVehicleHal getMockedVehicleHal() { 79 return mMockedVehicleHal; 80 } 81 82 protected synchronized FakeSystemInterface getFakeSystemInterface() { 83 return mFakeSystemInterface; 84 } 85 86 protected synchronized void configureMockedHal() { 87 } 88 89 protected synchronized void configureFakeSystemInterface() { 90 } 91 92 protected synchronized void setFlashWearInformation(WearInformation wearInformation) { 93 mFakeSystemInterface.mWearInformationProvider.setWearInformation(wearInformation); 94 } 95 96 protected synchronized void setUptimeProvider(UptimeProvider uptimeProvider) { 97 mFakeSystemInterface.mUptimeProvider = uptimeProvider; 98 } 99 100 @Override 101 protected synchronized void setUp() throws Exception { 102 super.setUp(); 103 104 releaseRealCarService(getContext()); 105 106 mMockedVehicleHal = createMockedVehicleHal(); 107 configureMockedHal(); 108 109 mFakeSystemInterface = new FakeSystemInterface(); 110 configureFakeSystemInterface(); 111 112 Context context = getCarServiceContext(); 113 mCarImpl = new ICarImpl(context, mMockedVehicleHal, mFakeSystemInterface, 114 null /* error notifier */); 115 116 initMockedHal(false /* no need to release */); 117 118 mCar = new android.car.Car(context, mCarImpl, null /* handler */); 119 } 120 121 @Override 122 protected synchronized void tearDown() throws Exception { 123 super.tearDown(); 124 125 mCar.disconnect(); 126 mCarImpl.release(); 127 128 mFakeSystemInterface.tearDown(); 129 } 130 131 protected Context getCarServiceContext() throws NameNotFoundException { 132 return getContext() 133 .createPackageContext("com.android.car", Context.CONTEXT_IGNORE_SECURITY); 134 } 135 136 protected synchronized void reinitializeMockedHal() { 137 initMockedHal(true /* release */); 138 } 139 140 private synchronized void initMockedHal(boolean release) { 141 if (release) { 142 mCarImpl.release(); 143 } 144 145 for (Map.Entry<VehiclePropConfigBuilder, VehicleHalPropertyHandler> entry 146 : mHalConfig.entrySet()) { 147 mMockedVehicleHal.addProperty(entry.getKey().build(), entry.getValue()); 148 } 149 mHalConfig.clear(); 150 mCarImpl.init(); 151 } 152 153 private final Map<VehiclePropConfigBuilder, VehicleHalPropertyHandler> mHalConfig = 154 new HashMap<>(); 155 156 protected synchronized VehiclePropConfigBuilder addProperty(int propertyId, 157 VehicleHalPropertyHandler propertyHandler) { 158 VehiclePropConfigBuilder builder = VehiclePropConfigBuilder.newBuilder(propertyId); 159 mHalConfig.put(builder, propertyHandler); 160 return builder; 161 } 162 163 protected synchronized VehiclePropConfigBuilder addProperty(int propertyId) { 164 VehiclePropConfigBuilder builder = VehiclePropConfigBuilder.newBuilder(propertyId); 165 mHalConfig.put(builder, new DefaultPropertyHandler(builder.build(), null)); 166 return builder; 167 } 168 169 protected synchronized VehiclePropConfigBuilder addProperty(int propertyId, 170 VehiclePropValue value) { 171 VehiclePropConfigBuilder builder = VehiclePropConfigBuilder.newBuilder(propertyId); 172 mHalConfig.put(builder, new DefaultPropertyHandler(builder.build(), value)); 173 return builder; 174 } 175 176 protected synchronized VehiclePropConfigBuilder addStaticProperty(int propertyId, 177 VehiclePropValue value) { 178 VehiclePropConfigBuilder builder = VehiclePropConfigBuilder.newBuilder(propertyId) 179 .setChangeMode(VehiclePropertyChangeMode.STATIC) 180 .setAccess(VehiclePropertyAccess.READ); 181 182 mHalConfig.put(builder, new StaticPropertyHandler(value)); 183 return builder; 184 } 185 186 protected synchronized android.car.Car getCar() { 187 return mCar; 188 } 189 190 protected void runOnMain(final Runnable r) { 191 mMainHandler.post(r); 192 } 193 194 protected void runOnMainSync(final Runnable r) throws Exception { 195 mMainHandler.post(new Runnable() { 196 @Override 197 public void run() { 198 r.run(); 199 mWaitForMain.release(); 200 } 201 }); 202 mWaitForMain.acquire(); 203 } 204 205 protected boolean waitForFakeDisplayState(boolean expectedState) throws Exception { 206 return mFakeSystemInterface.waitForDisplayState(expectedState, SHORT_WAIT_TIMEOUT_MS); 207 } 208 209 public static <T> void assertArrayEquals(T[] expected, T[] actual) { 210 if (!Arrays.equals(expected, actual)) { 211 fail("expected:<" + Arrays.toString(expected) + 212 "> but was:<" + Arrays.toString(actual) + ">"); 213 } 214 } 215 216 public static void assertArrayEquals(int[] expected, int[] actual) { 217 if (!Arrays.equals(expected, actual)) { 218 fail("expected:<" + Arrays.toString(expected) + 219 "> but was:<" + Arrays.toString(actual) + ">"); 220 } 221 } 222 223 /* 224 * In order to eliminate interfering with real car service we will disable it. It will be 225 * enabled back in CarTestService when mCarServiceToken will go away (tests finish). 226 */ 227 private synchronized static void releaseRealCarService(Context context) throws Exception { 228 if (mRealCarServiceReleased) { 229 return; // We just want to release it once. 230 } 231 232 mRealCarServiceReleased = true; // To make sure it was called once. 233 234 Object waitForConnection = new Object(); 235 android.car.Car car = android.car.Car.createCar(context, new ServiceConnection() { 236 @Override 237 public void onServiceConnected(ComponentName name, IBinder service) { 238 synchronized (waitForConnection) { 239 waitForConnection.notify(); 240 } 241 } 242 243 @Override 244 public void onServiceDisconnected(ComponentName name) { } 245 }); 246 247 car.connect(); 248 synchronized (waitForConnection) { 249 if (!car.isConnected()) { 250 waitForConnection.wait(DEFAULT_WAIT_TIMEOUT_MS); 251 } 252 } 253 254 if (car.isConnected()) { 255 Log.i(TAG, "Connected to real car service"); 256 CarTestManagerBinderWrapper binderWrapper = 257 (CarTestManagerBinderWrapper) car.getCarManager(android.car.Car.TEST_SERVICE); 258 assertNotNull(binderWrapper); 259 260 CarTestManager mgr = new CarTestManager(binderWrapper.binder); 261 mgr.stopCarService(mCarServiceToken); 262 } 263 } 264 265 static class FakeSystemInterface extends SystemInterface { 266 interface UptimeProvider { 267 long getUptime(boolean includeDeepSleepTime); 268 } 269 270 private boolean mDisplayOn = true; 271 private final Semaphore mDisplayStateWait = new Semaphore(0); 272 private final class FakeWearInformationProvider implements WearInformationProvider { 273 private WearInformation mWearInformation = null; 274 public void setWearInformation(WearInformation wearInformation) { 275 mWearInformation = wearInformation; 276 } 277 278 @Override 279 public WearInformation load() { 280 return mWearInformation; 281 } 282 } 283 private final FakeWearInformationProvider mWearInformationProvider = 284 new FakeWearInformationProvider(); 285 private TemporaryDirectory mFilesDir = null; 286 private UptimeProvider mUptimeProvider = null; 287 288 @Override 289 public synchronized void setDisplayState(boolean on) { 290 mDisplayOn = on; 291 mDisplayStateWait.release(); 292 } 293 294 boolean waitForDisplayState(boolean expectedState, long timeoutMs) 295 throws Exception { 296 if (expectedState == mDisplayOn) { 297 return true; 298 } 299 mDisplayStateWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS); 300 return expectedState == mDisplayOn; 301 } 302 303 @Override 304 public void releaseAllWakeLocks() { 305 } 306 307 @Override 308 public void shutdown() { } 309 310 @Override 311 public void enterDeepSleep(int wakeupTimeSec) { } 312 313 @Override 314 public boolean isSystemSupportingDeepSleep() { 315 return false; 316 } 317 318 @Override 319 public void switchToPartialWakeLock() { 320 } 321 322 @Override 323 public void switchToFullWakeLock() { 324 } 325 326 @Override 327 public void startDisplayStateMonitoring(CarPowerManagementService service) { 328 } 329 330 @Override 331 public void stopDisplayStateMonitoring() { 332 } 333 334 @Override 335 public boolean isWakeupCausedByTimer() { return false; } 336 337 @Override 338 public WearInformationProvider[] getFlashWearInformationProviders() { 339 return new WearInformationProvider[] { mWearInformationProvider }; 340 } 341 342 @Override 343 public File getFilesDir() { 344 if (mFilesDir == null) { 345 try { 346 mFilesDir = new TemporaryDirectory(TAG); 347 } catch (IOException e) { 348 Log.e(TAG, "failed to create temporary directory", e); 349 fail("failed to create temporary directory. exception was: " + e); 350 } 351 } 352 return mFilesDir.getDirectory(); 353 } 354 355 @Override 356 public long getUptime(boolean includeDeepSleepTime) { 357 if (mUptimeProvider != null) { 358 return mUptimeProvider.getUptime(includeDeepSleepTime); 359 } 360 return super.getUptime(includeDeepSleepTime); 361 } 362 363 void tearDown() { 364 if (mFilesDir != null) { 365 try { 366 mFilesDir.close(); 367 } catch (Exception e) { 368 Log.w(TAG, "could not remove temporary directory", e); 369 } 370 } 371 } 372 } 373} 374