MockedCarTestBase.java revision cfe93105f637c2822da113308f113ed418d0b319
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.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.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                null /* error notifier */);
94
95        initMockedHal(false /* no need to release */);
96
97        mCar = new android.car.Car(context, mCarImpl, null /* handler */);
98    }
99
100    @Override
101    protected synchronized void tearDown() throws Exception {
102        super.tearDown();
103
104        mCar.disconnect();
105        mCarImpl.release();
106    }
107
108    private Context getCarServiceContext() throws NameNotFoundException {
109        return getContext()
110                .createPackageContext("com.android.car", Context.CONTEXT_IGNORE_SECURITY);
111    }
112
113    protected synchronized void reinitializeMockedHal() {
114        initMockedHal(true /* release */);
115    }
116
117    private synchronized void initMockedHal(boolean release) {
118        if (release) {
119            mCarImpl.release();
120        }
121
122        for (Map.Entry<VehiclePropConfigBuilder, VehicleHalPropertyHandler> entry
123                : mHalConfig.entrySet()) {
124            mMockedVehicleHal.addProperty(entry.getKey().build(), entry.getValue());
125        }
126        mHalConfig.clear();
127        mCarImpl.init();
128    }
129
130    private final Map<VehiclePropConfigBuilder, VehicleHalPropertyHandler> mHalConfig =
131            new HashMap<>();
132
133    protected synchronized VehiclePropConfigBuilder addProperty(int propertyId,
134            VehicleHalPropertyHandler propertyHandler) {
135        VehiclePropConfigBuilder builder = VehiclePropConfigBuilder.newBuilder(propertyId);
136        mHalConfig.put(builder, propertyHandler);
137        return builder;
138    }
139
140    protected synchronized VehiclePropConfigBuilder addProperty(int propertyId) {
141        VehiclePropConfigBuilder builder = VehiclePropConfigBuilder.newBuilder(propertyId);
142        mHalConfig.put(builder, new DefaultPropertyHandler(builder.build(), null));
143        return builder;
144    }
145
146    protected synchronized VehiclePropConfigBuilder addProperty(int propertyId,
147            VehiclePropValue value) {
148        VehiclePropConfigBuilder builder = VehiclePropConfigBuilder.newBuilder(propertyId);
149        mHalConfig.put(builder, new DefaultPropertyHandler(builder.build(), value));
150        return builder;
151    }
152
153    protected synchronized VehiclePropConfigBuilder addStaticProperty(int propertyId,
154            VehiclePropValue value) {
155        VehiclePropConfigBuilder builder = VehiclePropConfigBuilder.newBuilder(propertyId)
156                .setChangeMode(VehiclePropertyChangeMode.STATIC)
157                .setAccess(VehiclePropertyAccess.READ);
158
159        mHalConfig.put(builder, new StaticPropertyHandler(value));
160        return builder;
161    }
162
163    protected synchronized android.car.Car getCar() {
164        return mCar;
165    }
166
167    protected void runOnMain(final Runnable r) {
168        mMainHandler.post(r);
169    }
170
171    protected void runOnMainSync(final Runnable r) throws Exception {
172        mMainHandler.post(new Runnable() {
173            @Override
174            public void run() {
175                r.run();
176                mWaitForMain.release();
177            }
178        });
179        mWaitForMain.acquire();
180    }
181
182    protected boolean waitForFakeDisplayState(boolean expectedState) throws Exception {
183        return mFakeSystemInterface.waitForDisplayState(expectedState, SHORT_WAIT_TIMEOUT_MS);
184    }
185
186    public static <T> void assertArrayEquals(T[] expected, T[] actual) {
187        if (!Arrays.equals(expected, actual)) {
188            fail("expected:<" + Arrays.toString(expected) +
189                    "> but was:<" + Arrays.toString(actual) + ">");
190        }
191    }
192
193    public static void assertArrayEquals(int[] expected, int[] actual) {
194        if (!Arrays.equals(expected, actual)) {
195            fail("expected:<" + Arrays.toString(expected) +
196                    "> but was:<" + Arrays.toString(actual) + ">");
197        }
198    }
199
200    /*
201     * In order to eliminate interfering with real car service we will disable it. It will be
202     * enabled back in CarTestService when mCarServiceToken will go away (tests finish).
203     */
204    private synchronized static void releaseRealCarService(Context context) throws Exception {
205        if (mRealCarServiceReleased) {
206            return;  // We just want to release it once.
207        }
208
209        mRealCarServiceReleased = true;  // To make sure it was called once.
210
211        Object waitForConnection = new Object();
212        android.car.Car car = android.car.Car.createCar(context, new ServiceConnection() {
213            @Override
214            public void onServiceConnected(ComponentName name, IBinder service) {
215                synchronized (waitForConnection) {
216                    waitForConnection.notify();
217                }
218            }
219
220            @Override
221            public void onServiceDisconnected(ComponentName name) { }
222        });
223
224        car.connect();
225        synchronized (waitForConnection) {
226            if (!car.isConnected()) {
227                waitForConnection.wait(DEFAULT_WAIT_TIMEOUT_MS);
228            }
229        }
230
231        if (car.isConnected()) {
232            Log.i(TAG, "Connected to real car service");
233            CarTestManagerBinderWrapper binderWrapper =
234                    (CarTestManagerBinderWrapper) car.getCarManager(android.car.Car.TEST_SERVICE);
235            assertNotNull(binderWrapper);
236
237            CarTestManager mgr = new CarTestManager(binderWrapper.binder);
238            mgr.stopCarService(mCarServiceToken);
239        }
240    }
241
242    private static class FakeSystemInterface extends SystemInterface {
243
244        private boolean mDisplayOn = true;
245        private final Semaphore mDisplayStateWait = new Semaphore(0);
246
247        @Override
248        public synchronized void setDisplayState(boolean on) {
249            mDisplayOn = on;
250            mDisplayStateWait.release();
251        }
252
253        boolean waitForDisplayState(boolean expectedState, long timeoutMs)
254                throws Exception {
255            if (expectedState == mDisplayOn) {
256                return true;
257            }
258            mDisplayStateWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS);
259            return expectedState == mDisplayOn;
260        }
261
262        @Override
263        public void releaseAllWakeLocks() {
264        }
265
266        @Override
267        public void shutdown() { }
268
269        @Override
270        public void enterDeepSleep(int wakeupTimeSec) { }
271
272        @Override
273        public boolean isSystemSupportingDeepSleep() {
274            return false;
275        }
276
277        @Override
278        public void switchToPartialWakeLock() {
279        }
280
281        @Override
282        public void switchToFullWakeLock() {
283        }
284
285        @Override
286        public void startDisplayStateMonitoring(CarPowerManagementService service) {
287        }
288
289        @Override
290        public void stopDisplayStateMonitoring() {
291        }
292
293        @Override
294        public boolean isWakeupCausedByTimer() { return false; }
295    }
296}
297