1 /* 2 * Copyright (C) 2014 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.appsecurity.cts; 18 19 import com.android.ddmlib.AdbCommandRejectedException; 20 import com.android.ddmlib.CollectingOutputReceiver; 21 import com.android.ddmlib.Log; 22 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner; 23 import com.android.ddmlib.testrunner.TestResult.TestStatus; 24 import com.android.tradefed.device.DeviceNotAvailableException; 25 import com.android.tradefed.device.ITestDevice; 26 import com.android.tradefed.result.CollectingTestListener; 27 import com.android.tradefed.result.TestDescription; 28 import com.android.tradefed.result.TestResult; 29 import com.android.tradefed.result.TestRunResult; 30 import com.android.tradefed.util.RunUtil; 31 32 import java.util.Arrays; 33 import java.util.HashMap; 34 import java.util.Map; 35 import java.util.Objects; 36 import java.util.concurrent.TimeUnit; 37 38 public class Utils { 39 private static final String LOG_TAG = Utils.class.getSimpleName(); 40 41 public static final int USER_SYSTEM = 0; 42 43 static final String PKG = "com.android.cts.splitapp"; 44 static final String CLASS = PKG + ".SplitAppTest"; 45 46 static final String APK = "CtsSplitApp.apk"; 47 48 static final String APK_mdpi = "CtsSplitApp_mdpi-v4.apk"; 49 static final String APK_hdpi = "CtsSplitApp_hdpi-v4.apk"; 50 static final String APK_xhdpi = "CtsSplitApp_xhdpi-v4.apk"; 51 static final String APK_xxhdpi = "CtsSplitApp_xxhdpi-v4.apk"; 52 53 static final String APK_x86 = "CtsSplitApp_x86.apk"; 54 static final String APK_x86_64 = "CtsSplitApp_x86_64.apk"; 55 static final String APK_armeabi_v7a = "CtsSplitApp_armeabi-v7a.apk"; 56 static final String APK_armeabi = "CtsSplitApp_armeabi.apk"; 57 static final String APK_arm64_v8a = "CtsSplitApp_arm64-v8a.apk"; 58 static final String APK_mips64 = "CtsSplitApp_mips64.apk"; 59 static final String APK_mips = "CtsSplitApp_mips.apk"; 60 61 static final HashMap<String, String> ABI_TO_APK = new HashMap<>(); 62 63 static { 64 ABI_TO_APK.put("x86", APK_x86); 65 ABI_TO_APK.put("x86_64", APK_x86_64); 66 ABI_TO_APK.put("armeabi-v7a", APK_armeabi_v7a); 67 ABI_TO_APK.put("armeabi", APK_armeabi); 68 ABI_TO_APK.put("arm64-v8a", APK_arm64_v8a); 69 ABI_TO_APK.put("mips64", APK_mips64); 70 ABI_TO_APK.put("mips", APK_mips); 71 } 72 runDeviceTestsAsCurrentUser(ITestDevice device, String packageName, String testClassName, String testMethodName)73 public static void runDeviceTestsAsCurrentUser(ITestDevice device, String packageName, 74 String testClassName, String testMethodName) throws DeviceNotAvailableException { 75 runDeviceTests(device, packageName, testClassName, testMethodName, device.getCurrentUser(), 76 null); 77 } 78 runDeviceTestsAsCurrentUser(ITestDevice device, String packageName, String testClassName, String testMethodName, Map<String, String> testArgs)79 public static void runDeviceTestsAsCurrentUser(ITestDevice device, String packageName, 80 String testClassName, String testMethodName, Map<String, String> testArgs) 81 throws DeviceNotAvailableException { 82 runDeviceTests(device, packageName, testClassName, testMethodName, device.getCurrentUser(), 83 testArgs); 84 } 85 runDeviceTests(ITestDevice device, String packageName, String testClassName, String testMethodName)86 public static void runDeviceTests(ITestDevice device, String packageName, String testClassName, 87 String testMethodName) throws DeviceNotAvailableException { 88 runDeviceTests(device, packageName, testClassName, testMethodName, USER_SYSTEM, null); 89 } 90 runDeviceTests(ITestDevice device, String packageName, String testClassName, String testMethodName, Map<String, String> testArgs)91 public static void runDeviceTests(ITestDevice device, String packageName, String testClassName, 92 String testMethodName, Map<String, String> testArgs) 93 throws DeviceNotAvailableException { 94 runDeviceTests(device, packageName, testClassName, testMethodName, USER_SYSTEM, testArgs); 95 } 96 runDeviceTests(ITestDevice device, String packageName, String testClassName, String testMethodName, int userId)97 public static void runDeviceTests(ITestDevice device, String packageName, String testClassName, 98 String testMethodName, int userId) throws DeviceNotAvailableException { 99 runDeviceTests(device, packageName, testClassName, testMethodName, userId, null); 100 } 101 runDeviceTests(ITestDevice device, String packageName, String testClassName, String testMethodName, int userId, Map<String, String> testArgs)102 public static void runDeviceTests(ITestDevice device, String packageName, String testClassName, 103 String testMethodName, int userId, Map<String, String> testArgs) 104 throws DeviceNotAvailableException { 105 // 60 min timeout per test by default 106 runDeviceTests(device, packageName, testClassName, testMethodName, userId, testArgs, 107 60L, TimeUnit.MINUTES); 108 } 109 runDeviceTests(ITestDevice device, String packageName, String testClassName, String testMethodName, int userId, Map<String, String> testArgs, long timeout, TimeUnit unit)110 public static void runDeviceTests(ITestDevice device, String packageName, String testClassName, 111 String testMethodName, int userId, Map<String, String> testArgs, long timeout, 112 TimeUnit unit) 113 throws DeviceNotAvailableException { 114 if (testClassName != null && testClassName.startsWith(".")) { 115 testClassName = packageName + testClassName; 116 } 117 RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(packageName, 118 "androidx.test.runner.AndroidJUnitRunner", device.getIDevice()); 119 // timeout_msec is the timeout per test for instrumentation 120 long testTimeoutMs = unit.toMillis(timeout); 121 testRunner.addInstrumentationArg("timeout_msec", Long.toString(testTimeoutMs)); 122 // Similar logic as InstrumentationTest to ensure on host-side level that no-hanging can happen 123 long maxTimeToOutputMs = testTimeoutMs + testTimeoutMs / 10; 124 testRunner.setMaxTimeToOutputResponse(maxTimeToOutputMs, TimeUnit.MILLISECONDS); 125 126 if (testClassName != null && testMethodName != null) { 127 testRunner.setMethodName(testClassName, testMethodName); 128 } else if (testClassName != null) { 129 testRunner.setClassName(testClassName); 130 } 131 132 if (testArgs != null && testArgs.size() > 0) { 133 for (String name : testArgs.keySet()) { 134 final String value = testArgs.get(name); 135 testRunner.addInstrumentationArg(name, value); 136 } 137 } 138 final CollectingTestListener listener = new CollectingTestListener(); 139 device.runInstrumentationTestsAsUser(testRunner, userId, listener); 140 141 final TestRunResult result = listener.getCurrentRunResults(); 142 if (result.isRunFailure()) { 143 throw new AssertionError("Failed to successfully run device tests for " 144 + result.getName() + ": " + result.getRunFailureMessage()); 145 } 146 if (result.getNumTests() == 0) { 147 throw new AssertionError("No tests were run on the device"); 148 } 149 if (result.hasFailedTests()) { 150 // build a meaningful error message 151 StringBuilder errorBuilder = new StringBuilder("on-device tests failed:\n"); 152 for (Map.Entry<TestDescription, TestResult> resultEntry : 153 result.getTestResults().entrySet()) { 154 if (!resultEntry.getValue().getStatus().equals(TestStatus.PASSED)) { 155 errorBuilder.append(resultEntry.getKey().toString()); 156 errorBuilder.append(":\n"); 157 errorBuilder.append(resultEntry.getValue().getStackTrace()); 158 } 159 } 160 throw new AssertionError(errorBuilder.toString()); 161 } 162 } 163 164 /** 165 * Prepare and return a single user relevant for testing. 166 */ prepareSingleUser(ITestDevice device)167 public static int[] prepareSingleUser(ITestDevice device) 168 throws DeviceNotAvailableException { 169 return prepareMultipleUsers(device, 1); 170 } 171 172 /** 173 * Prepare and return two users relevant for testing. 174 */ prepareMultipleUsers(ITestDevice device)175 public static int[] prepareMultipleUsers(ITestDevice device) 176 throws DeviceNotAvailableException { 177 return prepareMultipleUsers(device, 2); 178 } 179 180 /** 181 * Prepare and return multiple users relevant for testing. 182 */ prepareMultipleUsers(ITestDevice device, int maxUsers)183 public static int[] prepareMultipleUsers(ITestDevice device, int maxUsers) 184 throws DeviceNotAvailableException { 185 final int[] userIds = getAllUsers(device); 186 int currentUserId = device.getCurrentUser(); 187 for (int i = 1; i < userIds.length; i++) { 188 if (i < maxUsers) { 189 device.startUser(userIds[i], true); 190 } else if (userIds[i] != currentUserId) { 191 device.stopUser(userIds[i], true, true); 192 } 193 } 194 if (userIds.length > maxUsers) { 195 return Arrays.copyOf(userIds, maxUsers); 196 } else { 197 return userIds; 198 } 199 } 200 getAllUsers(ITestDevice device)201 public static int[] getAllUsers(ITestDevice device) 202 throws DeviceNotAvailableException { 203 Integer primary = device.getPrimaryUserId(); 204 if (device.isHeadlessSystemUserMode() 205 && primary == USER_SYSTEM 206 && !device.canSwitchToHeadlessSystemUser()) { 207 primary = device.getMainUserId(); 208 } 209 if (primary == null) { 210 primary = USER_SYSTEM; 211 } 212 int[] users = new int[] { primary }; 213 for (Integer user : device.listUsers()) { 214 if ((user != USER_SYSTEM) && !Objects.equals(user, primary)) { 215 users = Arrays.copyOf(users, users.length + 1); 216 users[users.length - 1] = user; 217 } 218 } 219 return users; 220 } 221 waitForBootCompleted(ITestDevice device)222 public static void waitForBootCompleted(ITestDevice device) throws Exception { 223 for (int i = 0; i < 45; i++) { 224 if (isBootCompleted(device)) { 225 Log.d(LOG_TAG, "Yay, system is ready!"); 226 // or is it really ready? 227 // guard against potential USB mode switch weirdness at boot 228 RunUtil.getDefault().sleep(10 * 1000); 229 return; 230 } 231 Log.d(LOG_TAG, "Waiting for system ready..."); 232 // For low performance devices 233 RunUtil.getDefault().sleep(10*1000); 234 } 235 throw new AssertionError("System failed to become ready!"); 236 } 237 isBootCompleted(ITestDevice device)238 private static boolean isBootCompleted(ITestDevice device) throws Exception { 239 CollectingOutputReceiver receiver = new CollectingOutputReceiver(); 240 try { 241 device.getIDevice().executeShellCommand("getprop sys.boot_completed", receiver); 242 } catch (AdbCommandRejectedException e) { 243 // do nothing: device might be temporarily disconnected 244 Log.d(LOG_TAG, "Ignored AdbCommandRejectedException while `getprop sys.boot_completed`"); 245 } 246 String output = receiver.getOutput(); 247 if (output != null) { 248 output = output.trim(); 249 } 250 return "1".equals(output); 251 } 252 253 } 254