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 17 package com.android.bedstead.testapp; 18 19 import android.accounts.AccountManager; 20 import android.accounts.RemoteAccountManager; 21 import android.accounts.RemoteAccountManagerWrapper; 22 import android.app.NotificationManager; 23 import android.app.RemoteNotificationManager; 24 import android.app.RemoteNotificationManagerWrapper; 25 import android.app.RemoteWallpaperManager; 26 import android.app.RemoteWallpaperManagerWrapper; 27 import android.app.WallpaperManager; 28 import android.app.admin.DevicePolicyManager; 29 import android.app.admin.RemoteDevicePolicyManager; 30 import android.app.admin.RemoteDevicePolicyManagerWrapper; 31 import android.bluetooth.BluetoothManager; 32 import android.bluetooth.RemoteBluetoothManager; 33 import android.bluetooth.RemoteBluetoothManagerWrapper; 34 import android.content.BroadcastReceiver; 35 import android.content.Context; 36 import android.content.IntentFilter; 37 import android.content.RemoteContext; 38 import android.content.RemoteContextWrapper; 39 import android.content.RemoteRestrictionsManager; 40 import android.content.RemoteRestrictionsManagerWrapper; 41 import android.content.pm.CrossProfileApps; 42 import android.content.pm.PackageManager; 43 import android.content.pm.RemoteCrossProfileApps; 44 import android.content.pm.RemoteCrossProfileAppsWrapper; 45 import android.content.pm.RemoteLauncherApps; 46 import android.content.pm.RemoteLauncherAppsWrapper; 47 import android.content.pm.RemotePackageManager; 48 import android.content.pm.RemotePackageManagerWrapper; 49 import android.media.projection.RemoteMediaProjectionManager; 50 import android.media.projection.RemoteMediaProjectionManagerWrapper; 51 import android.net.wifi.RemoteWifiManager; 52 import android.net.wifi.RemoteWifiManagerWrapper; 53 import android.net.wifi.WifiManager; 54 import android.os.HardwarePropertiesManager; 55 import android.os.RemoteHardwarePropertiesManager; 56 import android.os.RemoteHardwarePropertiesManagerWrapper; 57 import android.os.RemoteUserManager; 58 import android.os.RemoteUserManagerWrapper; 59 import android.os.UserManager; 60 import android.security.KeyChain; 61 import android.security.RemoteKeyChain; 62 import android.security.RemoteKeyChainWrapper; 63 import android.telecom.RemoteTelecomManager; 64 import android.telecom.RemoteTelecomManagerWrapper; 65 import android.telephony.RemoteSmsManager; 66 import android.telephony.RemoteSmsManagerWrapper; 67 import android.telephony.RemoteTelephonyManager; 68 import android.telephony.RemoteTelephonyManagerWrapper; 69 import android.telephony.euicc.RemoteEuiccManager; 70 import android.telephony.euicc.RemoteEuiccManagerWrapper; 71 72 import com.android.bedstead.nene.TestApis; 73 import com.android.bedstead.nene.appops.AppOps; 74 import com.android.bedstead.nene.exceptions.NeneException; 75 import com.android.bedstead.nene.packages.Package; 76 import com.android.bedstead.nene.packages.ProcessReference; 77 import com.android.bedstead.nene.users.UserReference; 78 79 import com.google.android.enterprise.connectedapps.ConnectionListener; 80 import com.google.android.enterprise.connectedapps.ProfileConnectionHolder; 81 import com.google.android.enterprise.connectedapps.exceptions.UnavailableProfileException; 82 import com.google.errorprone.annotations.CanIgnoreReturnValue; 83 84 import java.util.HashMap; 85 import java.util.Map; 86 import java.util.Objects; 87 import java.util.UUID; 88 89 import javax.annotation.Nullable; 90 91 /** 92 * A reference to a specific instance of a {@link TestApp} on a given user. 93 * 94 * <p>The user may not exist, or the test app may not be installed on the user. 95 */ 96 public class TestAppInstance implements AutoCloseable, ConnectionListener { 97 98 private final TestApp mTestApp; 99 private final UserReference mUser; 100 private final TestAppConnector mConnector; 101 private final Map<IntentFilter, Long> mRegisteredBroadcastReceivers = new HashMap<>(); 102 private final ProfileTestAppController mTestAppController; 103 private final TestAppActivities mTestAppActivities; 104 private boolean mKeepAliveManually = false; 105 private ProfileConnectionHolder mConnectionHolder = null; 106 private final TestAppInstancePermissions mTestAppInstancePermissions = 107 new TestAppInstancePermissions(this); 108 109 /** 110 * Use {@link TestApp#install} or {@link TestApp#instance} to get an instance of 111 * {@link TestAppInstance}. 112 */ TestAppInstance(TestApp testApp, UserReference user)113 public TestAppInstance(TestApp testApp, UserReference user) { 114 if (testApp == null || user == null) { 115 throw new NullPointerException(); 116 } 117 mTestApp = testApp; 118 mUser = user; 119 mConnector = TestAppConnector.create(TestApis.context().instrumentedContext(), 120 new TestAppBinder(this)); 121 mConnector.addConnectionListener(this); 122 mTestAppController = 123 ProfileTestAppController.create(mConnector); 124 mTestAppActivities = TestAppActivities.create(this); 125 } 126 connector()127 TestAppConnector connector() { 128 return mConnector; 129 } 130 131 /** 132 * Access activities on the test app. 133 */ activities()134 public TestAppActivities activities() { 135 return mTestAppActivities; 136 } 137 138 /** 139 * The {@link TestApp} this instance refers to. 140 */ testApp()141 public TestApp testApp() { 142 return mTestApp; 143 } 144 145 /** 146 * See {@link TestApp#packageName()}. 147 */ packageName()148 public String packageName() { 149 return testApp().packageName(); 150 } 151 152 /** 153 * The {@link UserReference} this instance refers to. 154 */ user()155 public UserReference user() { 156 return mUser; 157 } 158 159 /** 160 * The {@link Package} of the {@link TestApp} this instance refers to. 161 */ pkg()162 public Package pkg() { 163 return Package.of(packageName()); 164 } 165 166 /** 167 * Uninstall the {@link TestApp} from the user referenced by 168 * this {@link TestAppInstance}. 169 */ uninstall()170 public void uninstall() { 171 mTestApp.uninstall(mUser); 172 } 173 174 /** 175 * Register a {@link BroadcastReceiver} for a given {@link IntentFilter}. 176 * 177 * <p>A new {@link BroadcastReceiver} instance will be created for each {@link IntentFilter}. 178 * 179 * <p>Note that {@link IntentFilter} does not override {@code equals} and one broadcast receiver 180 * will be registered for each instance of {@link IntentFilter} regardless of the content of the 181 * {@link IntentFilter}. 182 * 183 * <p>As registered receivers are only active while the application is open, calling this method 184 * will have the same effect as calling {@link #keepAlive()}. 185 */ registerReceiver(IntentFilter intentFilter)186 public void registerReceiver(IntentFilter intentFilter) { 187 registerReceiver(intentFilter, 0); 188 } 189 190 /** 191 * See {@link registerReceiver(IntentFilter)}. 192 */ registerReceiver(IntentFilter intentFilter, int flags)193 public void registerReceiver(IntentFilter intentFilter, int flags) { 194 if (mRegisteredBroadcastReceivers.containsKey(intentFilter)) { 195 return; 196 } 197 198 long receiverId = UUID.randomUUID().getMostSignificantBits(); 199 registerReceiver(intentFilter, receiverId, flags); 200 keepAlive(/* manualKeepAlive= */ false); 201 } 202 registerReceiver(IntentFilter intentFilter, long receiverId)203 private void registerReceiver(IntentFilter intentFilter, long receiverId) { 204 registerReceiver(intentFilter, receiverId, 0); 205 } 206 registerReceiver(IntentFilter intentFilter, long receiverId, int flags)207 private void registerReceiver(IntentFilter intentFilter, long receiverId, int flags) { 208 try (ProfileConnectionHolder h = mConnector.connect()){ 209 mTestAppController.other().registerReceiver(receiverId, intentFilter, flags); 210 mRegisteredBroadcastReceivers.put(intentFilter, receiverId); 211 } catch (UnavailableProfileException e) { 212 throw new IllegalStateException("Could not connect to test app", e); 213 } 214 } 215 216 /** 217 * Unregister the receiver 218 */ unregisterReceiver(IntentFilter intentFilter)219 public TestAppInstance unregisterReceiver(IntentFilter intentFilter) { 220 if (!mRegisteredBroadcastReceivers.containsKey(intentFilter)) { 221 return this; 222 } 223 224 long receiverId = mRegisteredBroadcastReceivers.remove(intentFilter); 225 226 try (ProfileConnectionHolder h = mConnector.connect()){ 227 mTestAppController.other().unregisterReceiver(receiverId); 228 mRegisteredBroadcastReceivers.put(intentFilter, receiverId); 229 } catch (UnavailableProfileException e) { 230 throw new IllegalStateException("Could not connect to test app", e); 231 } 232 233 if (mRegisteredBroadcastReceivers.isEmpty() && !mKeepAliveManually) { 234 stopKeepAlive(); 235 } 236 237 return this; 238 } 239 240 /** 241 * Starts keeping the test app process alive. 242 * 243 * <p>This ensures that it will receive broadcasts using registered broadcast receivers. 244 * 245 * @see {@link #stopKeepAlive()}. 246 */ keepAlive()247 public TestAppInstance keepAlive() { 248 keepAlive(/* manualKeepAlive=*/ true); 249 return this; 250 } 251 252 /** 253 * Starts keep alive mode and marks it as manual so that it won't be automatically ended if 254 * the last broadcast receiver is unregistered. 255 */ keepAlive(boolean manualKeepAlive)256 private void keepAlive(boolean manualKeepAlive) { 257 mKeepAliveManually = manualKeepAlive; 258 try { 259 if (mConnectionHolder != null) { 260 mConnectionHolder.close(); 261 mConnectionHolder = null; 262 } 263 264 mConnectionHolder = connector().connect(); 265 } catch (UnavailableProfileException e) { 266 throw new IllegalStateException("Could not connect to test app. Is it installed?", e); 267 } 268 } 269 270 /** 271 * Stops keeping the target app alive. 272 * 273 * <p>This will not kill the app immediately. To do that see {@link #stop()}. 274 */ 275 @CanIgnoreReturnValue stopKeepAlive()276 public TestAppInstance stopKeepAlive() { 277 mKeepAliveManually = false; 278 if (mConnectionHolder != null) { 279 mConnectionHolder.close(); 280 mConnectionHolder = null; 281 } 282 return this; 283 } 284 285 /** 286 * Immediately force stops the app. 287 * 288 * <p>This will also stop keeping the target app alive (see {@link #stopKeepAlive()}. 289 */ 290 @CanIgnoreReturnValue stop()291 public TestAppInstance stop() { 292 stopKeepAlive(); 293 294 ProcessReference process = mTestApp.pkg().runningProcess(mUser); 295 if (process != null) { 296 try { 297 process.kill(); 298 } catch (NeneException e) { 299 throw new NeneException("Error killing process... process is " + process(), e); 300 } 301 } 302 303 return this; 304 } 305 306 /** 307 * Gets the {@link ProcessReference} of the app, if any. 308 */ 309 @Nullable process()310 public ProcessReference process() { 311 return mTestApp.pkg().runningProcess(mUser); 312 } 313 314 @Override close()315 public void close() { 316 stopKeepAlive(); 317 uninstall(); 318 } 319 320 @Override connectionChanged()321 public void connectionChanged() { 322 if (mConnector.isConnected()) { 323 // re-register broadcast receivers when re-connected 324 for (Map.Entry<IntentFilter, Long> entry : mRegisteredBroadcastReceivers.entrySet()) { 325 registerReceiver(entry.getKey(), entry.getValue()); 326 } 327 } 328 } 329 330 /** Access events related to this test app. */ events()331 public TestAppEvents events() { 332 return new TestAppEvents(this); 333 } 334 335 /** 336 * Access {@link DevicePolicyManager} using this test app. 337 * 338 * <p>Almost all methods are available. Those that are not will be missing from the interface. 339 */ devicePolicyManager()340 public RemoteDevicePolicyManager devicePolicyManager() { 341 return new RemoteDevicePolicyManagerWrapper(mConnector, mUser, mTestApp.pkg()); 342 } 343 344 /** 345 * Access {@link UserManager} using this test app. 346 * 347 * <p>Almost all methods are available. Those that are not will be missing from the interface. 348 */ userManager()349 public RemoteUserManager userManager() { 350 return new RemoteUserManagerWrapper(mConnector, mUser, mTestApp.pkg()); 351 } 352 353 /** 354 * Access {@link WifiManager} using this test app. 355 * 356 * <p>Almost all methods are available. Those that are not will be missing from the interface. 357 */ wifiManager()358 public RemoteWifiManager wifiManager() { 359 return new RemoteWifiManagerWrapper(mConnector, mUser, mTestApp.pkg()); 360 } 361 362 /** 363 * Access {@link HardwarePropertiesManager} using this test app. 364 * 365 * <p>Almost all methods are available. Those that are not will be missing from the interface. 366 */ hardwarePropertiesManager()367 public RemoteHardwarePropertiesManager hardwarePropertiesManager() { 368 return new RemoteHardwarePropertiesManagerWrapper(mConnector, mUser, mTestApp.pkg()); 369 } 370 371 /** 372 * Access {@link PackageManager} using this test app. 373 * 374 * <p>Almost all methods are available. Those that are not will be missing from the interface. 375 */ packageManager()376 public RemotePackageManager packageManager() { 377 return new RemotePackageManagerWrapper(mConnector, mUser, mTestApp.pkg()); 378 } 379 380 /** 381 * Access {@link CrossProfileApps} using this test app. 382 * 383 * <p>Almost all methods are available. Those that are not will be missing from the interface. 384 */ crossProfileApps()385 public RemoteCrossProfileApps crossProfileApps() { 386 return new RemoteCrossProfileAppsWrapper(mConnector, mUser, mTestApp.pkg()); 387 } 388 389 /** 390 * Access {@link android.content.pm.LauncherApps} using this test app. 391 * 392 * <p>Almost all methods are available. Those that are not will be missing from the interface. 393 */ launcherApps()394 public RemoteLauncherApps launcherApps() { 395 return new RemoteLauncherAppsWrapper(mConnector, mUser, mTestApp.pkg()); 396 } 397 398 /** 399 * Access {@link AccountManager} using this test app. 400 * 401 * <p>Almost all methods are available. Those that are not will be missing from the interface. 402 */ accountManager()403 public RemoteAccountManager accountManager() { 404 return new RemoteAccountManagerWrapper(mConnector, mUser, mTestApp.pkg()); 405 } 406 407 /** 408 * Access the application {@link Context} using this test app. 409 * 410 * <p>Almost all methods are available. Those that are not will be missing from the interface. 411 */ context()412 public RemoteContext context() { 413 return new RemoteContextWrapper(mConnector, mUser, mTestApp.pkg()); 414 } 415 416 /** 417 * Access the {@link KeyChain} using this test app. 418 * 419 * <p>Almost all methods are available. Those that are not will be missing from the interface. 420 */ keyChain()421 public RemoteKeyChain keyChain() { 422 return new RemoteKeyChainWrapper(mConnector, mUser, mTestApp.pkg()); 423 } 424 425 /** 426 * Access the {@link BluetoothManager} using this test app. 427 * 428 * <p>Almost all methods are available. Those that are not will be missing from the interface. 429 */ bluetoothManager()430 public RemoteBluetoothManager bluetoothManager() { 431 return new RemoteBluetoothManagerWrapper(mConnector, mUser, mTestApp.pkg()); 432 } 433 434 /** 435 * Access the {@link NotificationManager} using this test app. 436 * 437 * <p>Almost all methods are available. Those that are not will be missing from the interface. 438 */ notificationManager()439 public RemoteNotificationManager notificationManager() { 440 return new RemoteNotificationManagerWrapper(mConnector, mUser, mTestApp.pkg()); 441 } 442 443 /** 444 * Access the {@link android.telephony.SmsManager} using this test app. 445 * 446 * <p>Almost all methods are available. Those that are not will be missing from the interface. 447 */ smsManager()448 public RemoteSmsManager smsManager() { 449 return new RemoteSmsManagerWrapper(mConnector, mUser, mTestApp.pkg()); 450 } 451 452 /** 453 * Access the {@link TelecomManager} using this test app. 454 * 455 * <p>Almost all methods are available. Those that are not will be missing from the interface. 456 */ telecomManager()457 public RemoteTelecomManager telecomManager() { 458 return new RemoteTelecomManagerWrapper(mConnector, mUser, mTestApp.pkg()); 459 } 460 461 /** 462 * Access the {@link android.content.RestrictionsManager} using this test app. 463 * 464 * <p>Almost all methods are available. Those that are not will be missing from the interface. 465 */ restrictionsManager()466 public RemoteRestrictionsManager restrictionsManager() { 467 return new RemoteRestrictionsManagerWrapper(mConnector, mUser, mTestApp.pkg()); 468 } 469 470 /** 471 * Access {@link WallpaperManager} using this test app. 472 * 473 * <p>Almost all methods are available. Those that are not will be missing from the interface. 474 */ wallpaperManager()475 public RemoteWallpaperManager wallpaperManager() { 476 return new RemoteWallpaperManagerWrapper(mConnector, mUser, mTestApp.pkg()); 477 } 478 479 /** 480 * Access the {@link android.telephony.TelephonyManager} using this test app. 481 * 482 * <p>Almost all methods are available. Those that are not will be missing from the interface. 483 */ telephonyManager()484 public RemoteTelephonyManager telephonyManager() { 485 return new RemoteTelephonyManagerWrapper(mConnector, mUser, mTestApp.pkg()); 486 } 487 488 /** 489 * Access the {@link android.telephony.euicc.EuiccManager} using this test app. 490 * 491 * <p> Almost all methods are available. Those that are not will be missing from the interface. 492 */ euiccManager()493 public RemoteEuiccManager euiccManager() { 494 return new RemoteEuiccManagerWrapper(mConnector, mUser, mTestApp.pkg()); 495 } 496 497 /** 498 * Access the {@link android.media.projection.MediaProjectionManager} using this test app. 499 * 500 * <p>Almost all methods are available. Those that are not will be missing from the interface. 501 */ mediaProjectionManager()502 public RemoteMediaProjectionManager mediaProjectionManager() { 503 return new RemoteMediaProjectionManagerWrapper(mConnector, mUser, mTestApp.pkg()); 504 } 505 506 /** 507 * Access permissions for this test app. 508 */ permissions()509 public TestAppInstancePermissions permissions() { 510 return mTestAppInstancePermissions; 511 } 512 513 /** 514 * Access AppOps for this test app. 515 */ appOps()516 public AppOps appOps() { 517 return testApp().pkg().appOps(mUser); 518 } 519 520 @Override toString()521 public String toString() { 522 return "TestAppInstance{" 523 + "testApp=" + mTestApp 524 + ", user=" + mUser 525 + ", registeredBroadcastReceivers=" + mRegisteredBroadcastReceivers 526 + ", keepAliveManually=" + mKeepAliveManually 527 + '}'; 528 } 529 530 @Override equals(Object o)531 public boolean equals(Object o) { 532 if (this == o) return true; 533 if (!(o instanceof TestAppInstance)) return false; 534 TestAppInstance that = (TestAppInstance) o; 535 return mTestApp.equals(that.mTestApp) && mUser.equals(that.mUser); 536 } 537 538 @Override hashCode()539 public int hashCode() { 540 return Objects.hash(mTestApp, mUser); 541 } 542 } 543