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