MockedCarTestBase.java revision 0d07c76bbc788fba8c77d8e932330ab22ec6ba27
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.test;
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.vehicle.V2_0.VehiclePropValue;
25import android.hardware.vehicle.V2_0.VehiclePropertyAccess;
26import android.hardware.vehicle.V2_0.VehiclePropertyChangeMode;
27import android.os.Binder;
28import android.os.Handler;
29import android.os.IBinder;
30import android.os.Looper;
31import android.test.AndroidTestCase;
32import android.util.Log;
33
34import com.android.car.CarPowerManagementService;
35import com.android.car.ICarImpl;
36import com.android.car.SystemInterface;
37import com.android.car.vehiclehal.test.MockedVehicleHal;
38import com.android.car.vehiclehal.test.MockedVehicleHal.DefaultPropertyHandler;
39import com.android.car.vehiclehal.test.MockedVehicleHal.StaticPropertyHandler;
40import com.android.car.vehiclehal.test.MockedVehicleHal.VehicleHalPropertyHandler;
41import com.android.car.vehiclehal.test.VehiclePropConfigBuilder;
42
43import java.util.Arrays;
44import java.util.HashMap;
45import java.util.Map;
46import java.util.concurrent.Semaphore;
47import java.util.concurrent.TimeUnit;
48
49/**
50 * Base class for testing with mocked vehicle HAL (=car).
51 * It is up to each app to start emulation by getMockedVehicleHal().start() as there will be
52 * per test set up that should be done before starting.
53 */
54public class MockedCarTestBase extends AndroidTestCase {
55    private static final String TAG = MockedCarTestBase.class.getSimpleName();
56    static final long DEFAULT_WAIT_TIMEOUT_MS = 3000;
57    static final long SHORT_WAIT_TIMEOUT_MS = 500;
58
59    private android.car.Car mCar;
60    private ICarImpl mCarImpl;
61    private MockedVehicleHal mMockedVehicleHal;
62    private FakeSystemInterface mFakeSystemInterface;
63
64    private final Semaphore mWaitForMain = new Semaphore(0);
65    private final Handler mMainHandler = new Handler(Looper.getMainLooper());
66
67    private static final IBinder mCarServiceToken = new Binder();
68    private static boolean mRealCarServiceReleased = false;
69
70    protected synchronized MockedVehicleHal createMockedVehicleHal() {
71        return new MockedVehicleHal();
72    }
73
74    protected synchronized MockedVehicleHal getMockedVehicleHal() {
75        return mMockedVehicleHal;
76    }
77
78    protected synchronized void configureMockedHal() {
79    }
80
81    @Override
82    protected synchronized void setUp() throws Exception {
83        super.setUp();
84
85        releaseRealCarService(getContext());
86
87        mMockedVehicleHal = createMockedVehicleHal();
88        configureMockedHal();
89
90        mFakeSystemInterface = new FakeSystemInterface();
91        Context context = getCarServiceContext();
92        mCarImpl = new ICarImpl(context, mMockedVehicleHal, mFakeSystemInterface);
93
94        initMockedHal(false /* no need to release */);
95
96        mCar = new android.car.Car(context, mCarImpl, null /* handler */);
97    }
98
99    @Override
100    protected synchronized void tearDown() throws Exception {
101        super.tearDown();
102
103        mCar.disconnect();
104        mCarImpl.release();
105    }
106
107    private Context getCarServiceContext() throws NameNotFoundException {
108        return getContext()
109                .createPackageContext("com.android.car", Context.CONTEXT_IGNORE_SECURITY);
110    }
111
112    protected synchronized void reinitializeMockedHal() {
113        initMockedHal(true /* release */);
114    }
115
116    private synchronized void initMockedHal(boolean release) {
117        if (release) {
118            mCarImpl.release();
119        }
120
121        for (Map.Entry<VehiclePropConfigBuilder, VehicleHalPropertyHandler> entry
122                : mHalConfig.entrySet()) {
123            mMockedVehicleHal.addProperty(entry.getKey().build(), entry.getValue());
124        }
125        mHalConfig.clear();
126        mCarImpl.init();
127    }
128
129    private final Map<VehiclePropConfigBuilder, VehicleHalPropertyHandler> mHalConfig =
130            new HashMap<>();
131
132    protected synchronized VehiclePropConfigBuilder addProperty(int propertyId,
133            VehicleHalPropertyHandler propertyHandler) {
134        VehiclePropConfigBuilder builder = VehiclePropConfigBuilder.newBuilder(propertyId);
135        mHalConfig.put(builder, propertyHandler);
136        return builder;
137    }
138
139    protected synchronized VehiclePropConfigBuilder addProperty(int propertyId) {
140        VehiclePropConfigBuilder builder = VehiclePropConfigBuilder.newBuilder(propertyId);
141        mHalConfig.put(builder, new DefaultPropertyHandler(builder.build(), null));
142        return builder;
143    }
144
145    protected synchronized VehiclePropConfigBuilder addProperty(int propertyId,
146            VehiclePropValue value) {
147        VehiclePropConfigBuilder builder = VehiclePropConfigBuilder.newBuilder(propertyId);
148        mHalConfig.put(builder, new DefaultPropertyHandler(builder.build(), value));
149        return builder;
150    }
151
152    protected synchronized VehiclePropConfigBuilder addStaticProperty(int propertyId,
153            VehiclePropValue value) {
154        VehiclePropConfigBuilder builder = VehiclePropConfigBuilder.newBuilder(propertyId)
155                .setChangeMode(VehiclePropertyChangeMode.STATIC)
156                .setAccess(VehiclePropertyAccess.READ);
157
158        mHalConfig.put(builder, new StaticPropertyHandler(value));
159        return builder;
160    }
161
162    protected synchronized android.car.Car getCar() {
163        return mCar;
164    }
165
166    protected void runOnMain(final Runnable r) {
167        mMainHandler.post(r);
168    }
169
170    protected void runOnMainSync(final Runnable r) throws Exception {
171        mMainHandler.post(new Runnable() {
172            @Override
173            public void run() {
174                r.run();
175                mWaitForMain.release();
176            }
177        });
178        mWaitForMain.acquire();
179    }
180
181    protected boolean waitForFakeDisplayState(boolean expectedState) throws Exception {
182        return mFakeSystemInterface.waitForDisplayState(expectedState, SHORT_WAIT_TIMEOUT_MS);
183    }
184
185    public static <T> void assertArrayEquals(T[] expected, T[] actual) {
186        if (!Arrays.equals(expected, actual)) {
187            fail("expected:<" + Arrays.toString(expected) +
188                    "> but was:<" + Arrays.toString(actual) + ">");
189        }
190    }
191
192    public static void assertArrayEquals(int[] expected, int[] actual) {
193        if (!Arrays.equals(expected, actual)) {
194            fail("expected:<" + Arrays.toString(expected) +
195                    "> but was:<" + Arrays.toString(actual) + ">");
196        }
197    }
198
199    /*
200     * In order to eliminate interfering with real car service we will disable it. It will be
201     * enabled back in CarTestService when mCarServiceToken will go away (tests finish).
202     */
203    private synchronized static void releaseRealCarService(Context context) throws Exception {
204        if (mRealCarServiceReleased) {
205            return;  // We just want to release it once.
206        }
207
208        mRealCarServiceReleased = true;  // To make sure it was called once.
209
210        Object waitForConnection = new Object();
211        android.car.Car car = android.car.Car.createCar(context, new ServiceConnection() {
212            @Override
213            public void onServiceConnected(ComponentName name, IBinder service) {
214                synchronized (waitForConnection) {
215                    waitForConnection.notify();
216                }
217            }
218
219            @Override
220            public void onServiceDisconnected(ComponentName name) { }
221        });
222
223        car.connect();
224        synchronized (waitForConnection) {
225            if (!car.isConnected()) {
226                waitForConnection.wait(DEFAULT_WAIT_TIMEOUT_MS);
227            }
228        }
229
230        if (car.isConnected()) {
231            Log.i(TAG, "Connected to real car service");
232            CarTestManagerBinderWrapper binderWrapper =
233                    (CarTestManagerBinderWrapper) car.getCarManager(android.car.Car.TEST_SERVICE);
234            assertNotNull(binderWrapper);
235
236            CarTestManager mgr = new CarTestManager(binderWrapper.binder);
237            mgr.stopCarService(mCarServiceToken);
238        }
239    }
240
241    private static class FakeSystemInterface extends SystemInterface {
242
243        private boolean mDisplayOn = true;
244        private final Semaphore mDisplayStateWait = new Semaphore(0);
245
246        @Override
247        public synchronized void setDisplayState(boolean on) {
248            mDisplayOn = on;
249            mDisplayStateWait.release();
250        }
251
252        boolean waitForDisplayState(boolean expectedState, long timeoutMs)
253                throws Exception {
254            if (expectedState == mDisplayOn) {
255                return true;
256            }
257            mDisplayStateWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS);
258            return expectedState == mDisplayOn;
259        }
260
261        @Override
262        public void releaseAllWakeLocks() {
263        }
264
265        @Override
266        public void shutdown() { }
267
268        @Override
269        public void enterDeepSleep(int wakeupTimeSec) { }
270
271        @Override
272        public boolean isSystemSupportingDeepSleep() {
273            return false;
274        }
275
276        @Override
277        public void switchToPartialWakeLock() {
278        }
279
280        @Override
281        public void switchToFullWakeLock() {
282        }
283
284        @Override
285        public void startDisplayStateMonitoring(CarPowerManagementService service) {
286        }
287
288        @Override
289        public void stopDisplayStateMonitoring() {
290        }
291
292        @Override
293        public boolean isWakeupCausedByTimer() { return false; }
294    }
295}
296