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  */
16 
17 package android.car.apitest;
18 
19 import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
20 import static com.android.compatibility.common.util.TestUtils.BooleanSupplierWithThrow;
21 
22 import static com.google.common.truth.Truth.assertThat;
23 
24 import static org.junit.Assert.fail;
25 
26 import android.car.Car;
27 import android.content.ComponentName;
28 import android.content.Context;
29 import android.content.ServiceConnection;
30 import android.os.IBinder;
31 import android.os.Looper;
32 import android.os.PowerManager;
33 import android.os.SystemClock;
34 import android.util.Log;
35 
36 import androidx.test.platform.app.InstrumentationRegistry;
37 
38 import org.junit.After;
39 import org.junit.Before;
40 
41 import java.util.concurrent.Semaphore;
42 import java.util.concurrent.TimeUnit;
43 
44 abstract class CarApiTestBase {
45 
46     private static final String TAG = CarApiTestBase.class.getSimpleName();
47 
48     protected static final long DEFAULT_WAIT_TIMEOUT_MS = 1_000;
49 
50     /**
51      * Constant used to wait blindly, when there is no condition that can be checked.
52      */
53     private static final int SUSPEND_TIMEOUT_MS = 5_000;
54     /**
55      * How long to sleep (multiple times) while waiting for a condition.
56      */
57     private static final int SMALL_NAP_MS = 100;
58 
59     protected static final Context sContext = InstrumentationRegistry.getInstrumentation()
60             .getTargetContext();
61 
62     private Car mCar;
63 
64     protected final DefaultServiceConnectionListener mConnectionListener =
65             new DefaultServiceConnectionListener();
66 
67     @Before
connectToCar()68     public final void connectToCar() throws Exception {
69         mCar = Car.createCar(getContext(), mConnectionListener);
70         mCar.connect();
71         mConnectionListener.waitForConnection(DEFAULT_WAIT_TIMEOUT_MS);
72     }
73 
74     @After
disconnectFromCar()75     public final void disconnectFromCar() throws Exception {
76         mCar.disconnect();
77     }
78 
getCar()79     protected Car getCar() {
80         return mCar;
81     }
82 
getContext()83     protected final Context getContext() {
84         return sContext;
85     }
86 
assertMainThread()87     protected static void assertMainThread() {
88         assertThat(Looper.getMainLooper().isCurrentThread()).isTrue();
89     }
90 
91     protected static final class DefaultServiceConnectionListener implements ServiceConnection {
92         private final Semaphore mConnectionWait = new Semaphore(0);
93 
waitForConnection(long timeoutMs)94         public void waitForConnection(long timeoutMs) throws InterruptedException {
95             mConnectionWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS);
96         }
97 
98         @Override
onServiceConnected(ComponentName name, IBinder service)99         public void onServiceConnected(ComponentName name, IBinder service) {
100             assertMainThread();
101             mConnectionWait.release();
102         }
103 
104         @Override
onServiceDisconnected(ComponentName name)105         public void onServiceDisconnected(ComponentName name) {
106             assertMainThread();
107         }
108     }
109 
suspendToRamAndResume()110     protected static void suspendToRamAndResume() throws Exception {
111         Log.d(TAG, "Emulate suspend to RAM and resume");
112         PowerManager powerManager = sContext.getSystemService(PowerManager.class);
113         runShellCommand("cmd car_service suspend");
114         // Check for suspend success
115         waitUntil("Suspsend is not successful",
116                 SUSPEND_TIMEOUT_MS, () -> !powerManager.isScreenOn());
117 
118         // Force turn off garage mode
119         runShellCommand("cmd car_service garage-mode off");
120         runShellCommand("cmd car_service resume");
121     }
122 
waitUntil(String msg, long timeoutMs, BooleanSupplierWithThrow condition)123     protected static boolean waitUntil(String msg, long timeoutMs,
124             BooleanSupplierWithThrow condition) {
125         long deadline = SystemClock.elapsedRealtime() + timeoutMs;
126         do {
127             try {
128                 if (condition.getAsBoolean()) {
129                     return true;
130                 }
131             } catch (Exception e) {
132                 Log.e(TAG, "Exception in waitUntil: " + msg);
133                 throw new RuntimeException(e);
134             }
135             SystemClock.sleep(SMALL_NAP_MS);
136         } while (SystemClock.elapsedRealtime() < deadline);
137 
138         fail(msg + " after: " + timeoutMs + "ms");
139         return false;
140     }
141 }
142