1 /* 2 * Copyright (C) 2021 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 package com.android.bedstead.dpmwrapper; 17 18 import static android.Manifest.permission.INTERACT_ACROSS_USERS; 19 20 import static com.android.bedstead.dpmwrapper.DataFormatter.addArg; 21 import static com.android.bedstead.dpmwrapper.DataFormatter.getArg; 22 import static com.android.bedstead.dpmwrapper.Utils.ACTION_WRAPPED_MANAGER_CALL; 23 import static com.android.bedstead.dpmwrapper.Utils.EXTRA_CLASS; 24 import static com.android.bedstead.dpmwrapper.Utils.EXTRA_METHOD; 25 import static com.android.bedstead.dpmwrapper.Utils.EXTRA_NUMBER_ARGS; 26 import static com.android.bedstead.dpmwrapper.Utils.VERBOSE; 27 import static com.android.bedstead.dpmwrapper.Utils.getHandler; 28 29 import android.annotation.Nullable; 30 import android.app.admin.DevicePolicyManager; 31 import android.content.BroadcastReceiver; 32 import android.content.Context; 33 import android.content.Intent; 34 import android.content.pm.ActivityInfo; 35 import android.content.pm.PackageInfo; 36 import android.content.pm.PackageManager; 37 import android.content.pm.PackageManager.NameNotFoundException; 38 import android.net.wifi.WifiManager; 39 import android.os.Bundle; 40 import android.os.HardwarePropertiesManager; 41 import android.os.UserHandle; 42 import android.os.UserManager; 43 import android.util.Log; 44 45 import org.mockito.stubbing.Answer; 46 47 import java.lang.reflect.InvocationTargetException; 48 import java.util.HashMap; 49 import java.util.Locale; 50 import java.util.concurrent.CountDownLatch; 51 import java.util.concurrent.TimeUnit; 52 import java.util.concurrent.atomic.AtomicReference; 53 54 //TODO(b/176993670): STOPSHIP - it currently uses ordered broadcasts and a Mockito spy to implement 55 //the IPC between users, but before S is shipped it should be changed to use the connected apps SDK 56 //or the new CTS infrastructure. 57 /** 58 * Class used to create to provide a {@link DevicePolicyManager} implementation (and other managers 59 * that must be run by the device owner user) that automatically funnels calls between the user 60 * running the tests and the user that is the device owner. 61 */ 62 public final class TestAppSystemServiceFactory { 63 64 private static final String TAG = TestAppSystemServiceFactory.class.getSimpleName(); 65 66 private static final int RESULT_NOT_SENT_TO_ANY_RECEIVER = 108; 67 static final int RESULT_OK = 42; 68 static final int RESULT_EXCEPTION = 666; 69 70 // Must be high enough to outlast long tests like NetworkLoggingTest, which waits up to 71 // 6 minutes for network monitoring events. 72 private static final long TIMEOUT_MS = TimeUnit.MINUTES.toMillis(10); 73 74 // Caches whether the package declares the required receiver (otherwise each test would be 75 // querying package manager, which is expensive) 76 private static final HashMap<String, Boolean> sHasRequiredReceiver = new HashMap<>(); 77 78 /** 79 * Gets the proper {@link DevicePolicyManager} instance to be used by the test. 80 */ getDevicePolicyManager(Context context, Class<? extends BroadcastReceiver> receiverClass)81 public static DevicePolicyManager getDevicePolicyManager(Context context, 82 Class<? extends BroadcastReceiver> receiverClass) { 83 return getSystemService(context, DevicePolicyManager.class, receiverClass); 84 } 85 86 /** 87 * Gets the proper {@link WifiManager} instance to be used by the test. 88 */ getWifiManager(Context context, Class<? extends BroadcastReceiver> receiverClass)89 public static WifiManager getWifiManager(Context context, 90 Class<? extends BroadcastReceiver> receiverClass) { 91 return getSystemService(context, WifiManager.class, receiverClass); 92 } 93 94 /** 95 * Gets the proper {@link HardwarePropertiesManager} instance to be used by the test. 96 */ getHardwarePropertiesManager(Context context, Class<? extends BroadcastReceiver> receiverClass)97 public static HardwarePropertiesManager getHardwarePropertiesManager(Context context, 98 Class<? extends BroadcastReceiver> receiverClass) { 99 return getSystemService(context, HardwarePropertiesManager.class, receiverClass); 100 } 101 102 /** 103 * Gets the proper {@link UserManager} instance to be used by the test. 104 */ getUserManager(Context context, Class<? extends BroadcastReceiver> receiverClass)105 public static UserManager getUserManager(Context context, 106 Class<? extends BroadcastReceiver> receiverClass) { 107 return getSystemService(context, UserManager.class, receiverClass); 108 } 109 assertHasRequiredReceiver(Context context)110 private static void assertHasRequiredReceiver(Context context) { 111 if (!UserManager.isHeadlessSystemUserMode()) return; 112 113 String packageName = context.getPackageName(); 114 Boolean hasIt = sHasRequiredReceiver.get(packageName); 115 if (hasIt != null && hasIt) { 116 return; 117 } 118 PackageManager pm = context.getPackageManager(); 119 Class<?> targetClass = TestAppCallbacksReceiver.class; 120 PackageInfo packageInfo; 121 try { 122 packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_RECEIVERS); 123 } catch (NameNotFoundException e) { 124 Log.wtf(TAG, "Could not get receivers for " + packageName); 125 return; 126 } 127 128 if (packageInfo.receivers != null) { 129 for (ActivityInfo receiver : packageInfo.receivers) { 130 Class<?> receiverClass = null; 131 try { 132 receiverClass = Class.forName(receiver.name); 133 } catch (ClassNotFoundException e) { 134 Log.e(TAG, "Invalid receiver class on manifest: " + receiver.name); 135 continue; 136 } 137 if (TestAppCallbacksReceiver.class.isAssignableFrom(receiverClass)) { 138 Log.d(TAG, "Found " + receiverClass + " on " + packageName); 139 sHasRequiredReceiver.put(packageName, Boolean.TRUE); 140 return; 141 } 142 } 143 } 144 fail("Package " + packageName + " doesn't have a " + TestAppCallbacksReceiver.class 145 + " receiver - did you add it to the manifest?"); 146 } 147 getSystemService(Context context, Class<T> serviceClass, Class<? extends BroadcastReceiver> receiverClass)148 private static <T> T getSystemService(Context context, Class<T> serviceClass, 149 Class<? extends BroadcastReceiver> receiverClass) { 150 assertHasRequiredReceiver(context); 151 152 ServiceManagerWrapper<T> wrapper = null; 153 Class<?> wrappedClass; 154 155 if (serviceClass.equals(DevicePolicyManager.class)) { 156 wrappedClass = DevicePolicyManager.class; 157 @SuppressWarnings("unchecked") 158 ServiceManagerWrapper<T> safeCastWrapper = 159 (ServiceManagerWrapper<T>) new DevicePolicyManagerWrapper(); 160 wrapper = safeCastWrapper; 161 } else if (serviceClass.equals(WifiManager.class)) { 162 @SuppressWarnings("unchecked") 163 ServiceManagerWrapper<T> safeCastWrapper = 164 (ServiceManagerWrapper<T>) new WifiManagerWrapper(); 165 wrapper = safeCastWrapper; 166 wrappedClass = WifiManager.class; 167 } else if (serviceClass.equals(HardwarePropertiesManager.class)) { 168 @SuppressWarnings("unchecked") 169 ServiceManagerWrapper<T> safeCastWrapper = 170 (ServiceManagerWrapper<T>) new HardwarePropertiesManagerWrapper(); 171 wrapper = safeCastWrapper; 172 wrappedClass = HardwarePropertiesManager.class; 173 } else if (serviceClass.equals(UserManager.class)) { 174 @SuppressWarnings("unchecked") 175 ServiceManagerWrapper<T> safeCastWrapper = 176 (ServiceManagerWrapper<T>) new UserManagerWrapper(); 177 wrapper = safeCastWrapper; 178 wrappedClass = UserManager.class; 179 } else { 180 throw new IllegalArgumentException("invalid service class: " + serviceClass); 181 } 182 183 @SuppressWarnings("unchecked") 184 T manager = (T) context.getSystemService(wrappedClass); 185 186 int userId = context.getUserId(); 187 if (userId == UserHandle.USER_SYSTEM || !UserManager.isHeadlessSystemUserMode()) { 188 Log.i(TAG, "get(): returning 'pure' DevicePolicyManager for user " + userId); 189 return manager; 190 } 191 192 String receiverClassName = receiverClass.getName(); 193 final String wrappedClassName = wrappedClass.getName(); 194 if (VERBOSE) { 195 Log.v(TAG, "get(): receiverClassName: " + receiverClassName 196 + ", wrappedClassName: " + wrappedClassName); 197 } 198 199 Answer<?> answer = (inv) -> { 200 Object[] args = inv.getArguments(); 201 if (VERBOSE) { 202 Log.v(TAG, "spying " + inv + " method: " + inv.getMethod()); 203 } else { 204 Log.i(TAG, "spying " + inv.getMethod()); 205 } 206 String methodName = inv.getMethod().getName(); 207 Intent intent = new Intent(ACTION_WRAPPED_MANAGER_CALL) 208 .setClassName(context, receiverClassName) 209 .putExtra(EXTRA_CLASS, wrappedClassName) 210 .putExtra(EXTRA_METHOD, methodName) 211 .putExtra(EXTRA_NUMBER_ARGS, args.length); 212 for (int i = 0; i < args.length; i++) { 213 addArg(intent, args, i); 214 } 215 216 final CountDownLatch latch = new CountDownLatch(1); 217 final AtomicReference<Result> resultRef = new AtomicReference<>(); 218 BroadcastReceiver myReceiver = new BroadcastReceiver() { 219 public void onReceive(Context context, Intent intent) { 220 String action = intent.getAction(); 221 if (VERBOSE) { 222 Log.v(TAG, "spy received intent " + action + " for user " 223 + context.getUserId()); 224 } 225 Result result = new Result(this); 226 if (VERBOSE) Log.v(TAG, "result:" + result); 227 resultRef.set(result); 228 latch.countDown(); 229 }; 230 231 }; 232 if (VERBOSE) { 233 Log.v(TAG, "Sending ordered broadcast (" + Utils.toString(intent) + ") from user " 234 + userId + " to user " + UserHandle.SYSTEM); 235 } 236 237 // NOTE: method below used to be wrapped under runWithShellPermissionIdentity() to get 238 // INTERACT_ACROSS_USERS permission, but that's not needed anymore (as the permission 239 // is granted by the test. Besides, this class is now also used by DO apps that are not 240 // instrumented, so it was removed 241 if (context.checkSelfPermission(INTERACT_ACROSS_USERS) 242 != PackageManager.PERMISSION_GRANTED) { 243 fail("Package " + context.getPackageName() + " doesn't have " 244 + INTERACT_ACROSS_USERS + " - did you add it to the manifest and called " 245 + "grantDpmWrapper() (for user " + userId + ") in the host-side test?"); 246 } 247 context.sendOrderedBroadcastAsUser(intent, 248 UserHandle.SYSTEM, /* permission= */ null, myReceiver, getHandler(), 249 RESULT_NOT_SENT_TO_ANY_RECEIVER, /* initialData= */ null, 250 /* initialExtras= */ null); 251 252 if (VERBOSE) { 253 Log.d(TAG, "Waiting up to " + TIMEOUT_MS + "ms for response on " 254 + Thread.currentThread()); 255 } 256 if (!latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 257 fail("Ordered broadcast for %s() not received in %dms", methodName, TIMEOUT_MS); 258 } 259 260 Result result = resultRef.get(); 261 Log.d(TAG, "Received result on user " + userId + ". Code: " 262 + resultCodeToString(result.code)); 263 264 if (VERBOSE) { 265 // Some results - like network logging events - are quite large 266 Log.v(TAG, "Result: " + result); 267 } 268 269 switch (result.code) { 270 case RESULT_OK: 271 return result.value; 272 case RESULT_EXCEPTION: 273 Exception e = (Exception) result.value; 274 throw (e instanceof InvocationTargetException) ? e.getCause() : e; 275 case RESULT_NOT_SENT_TO_ANY_RECEIVER: 276 fail("Didn't receive result from ordered broadcast - did you override " 277 + receiverClassName + ".onReceive() to call " 278 + "DeviceOwnerHelper.runManagerMethod()?"); 279 return null; 280 default: 281 fail("Received invalid result for method %s: %s", methodName, result); 282 return null; 283 } 284 }; 285 286 T spy = wrapper.getWrapper(context, manager, answer); 287 288 return spy; 289 290 } 291 resultCodeToString(int code)292 static String resultCodeToString(int code) { 293 // Can't use DebugUtils.constantToString() because some valus are private 294 switch (code) { 295 case RESULT_NOT_SENT_TO_ANY_RECEIVER: 296 return "RESULT_NOT_SENT_TO_ANY_RECEIVER"; 297 case RESULT_OK: 298 return "RESULT_OK"; 299 case RESULT_EXCEPTION: 300 return "RESULT_EXCEPTION"; 301 default: 302 return "RESULT_UNKNOWN:" + code; 303 } 304 } 305 fail(String template, Object... args)306 private static void fail(String template, Object... args) { 307 throw new AssertionError(String.format(Locale.ENGLISH, template, args)); 308 } 309 310 private static final class Result { 311 public final int code; 312 @Nullable public final String error; 313 @Nullable public final Bundle extras; 314 @Nullable public final Object value; 315 Result(BroadcastReceiver receiver)316 Result(BroadcastReceiver receiver) { 317 int resultCode = receiver.getResultCode(); 318 String data = receiver.getResultData(); 319 extras = receiver.getResultExtras(/* makeMap= */ true); 320 Object parsedValue = null; 321 try { 322 if (extras != null && !extras.isEmpty()) { 323 Object[] result = new Object[1]; 324 int index = 0; 325 getArg(extras, result, /* parameterTypes= */ null, index); 326 parsedValue = result[index]; 327 } 328 } catch (Exception e) { 329 Log.e(TAG, "error parsing extras (code=" + resultCode + ", data=" + data, e); 330 data = "error parsing extras"; 331 resultCode = RESULT_EXCEPTION; 332 } 333 code = resultCode; 334 error = data; 335 value = parsedValue; 336 } 337 338 @Override toString()339 public String toString() { 340 return "Result[code=" + resultCodeToString(code) + ", error=" + error 341 + ", extras=" + extras + ", value=" + value + "]"; 342 } 343 } 344 345 abstract static class ServiceManagerWrapper<T> { getWrapper(Context context, T manager, Answer<?> answer)346 abstract T getWrapper(Context context, T manager, Answer<?> answer); 347 } 348 TestAppSystemServiceFactory()349 private TestAppSystemServiceFactory() { 350 throw new UnsupportedOperationException("contains only static methods"); 351 } 352 } 353