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