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