1 /* 2 * Copyright (C) 2019 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.server.wm; 18 19 import static android.app.AppOpsManager.MODE_ALLOWED; 20 import static android.app.AppOpsManager.MODE_ERRORED; 21 import static android.server.wm.UiDeviceUtils.pressHomeButton; 22 import static android.server.wm.WindowManagerState.STATE_INITIALIZING; 23 import static android.server.wm.backgroundactivity.appa.Components.APP_A_BACKGROUND_ACTIVITY; 24 import static android.server.wm.backgroundactivity.appa.Components.APP_A_FOREGROUND_ACTIVITY; 25 import static android.server.wm.backgroundactivity.appa.Components.APP_A_SECOND_BACKGROUND_ACTIVITY; 26 import static android.server.wm.backgroundactivity.appa.Components.APP_A_SEND_PENDING_INTENT_RECEIVER; 27 import static android.server.wm.backgroundactivity.appa.Components.APP_A_SIMPLE_ADMIN_RECEIVER; 28 import static android.server.wm.backgroundactivity.appa.Components.APP_A_START_ACTIVITY_RECEIVER; 29 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.ACTION_FINISH_ACTIVITY; 30 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.ACTION_LAUNCH_BACKGROUND_ACTIVITIES; 31 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_BACKGROUND_ACTIVITY_EXTRA; 32 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_INTENTS_EXTRA; 33 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_SECOND_BACKGROUND_ACTIVITY_EXTRA; 34 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.RELAUNCH_FOREGROUND_ACTIVITY_EXTRA; 35 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.START_ACTIVITY_FROM_FG_ACTIVITY_DELAY_MS_EXTRA; 36 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.START_ACTIVITY_FROM_FG_ACTIVITY_NEW_TASK_EXTRA; 37 import static android.server.wm.backgroundactivity.appa.Components.SendPendingIntentReceiver.IS_BROADCAST_EXTRA; 38 import static android.server.wm.backgroundactivity.appa.Components.StartBackgroundActivityReceiver.START_ACTIVITY_DELAY_MS_EXTRA; 39 import static android.server.wm.backgroundactivity.appb.Components.APP_B_FOREGROUND_ACTIVITY; 40 import static android.server.wm.backgroundactivity.common.CommonComponents.EVENT_NOTIFIER_EXTRA; 41 42 import static com.android.compatibility.common.util.SystemUtil.runShellCommand; 43 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; 44 45 import static com.google.common.truth.Truth.assertThat; 46 47 import static org.junit.Assert.assertEquals; 48 import static org.junit.Assert.assertFalse; 49 import static org.junit.Assert.assertNull; 50 import static org.junit.Assert.assertTrue; 51 52 import android.content.ComponentName; 53 import android.content.Intent; 54 import android.content.pm.PackageManager; 55 import android.os.ResultReceiver; 56 import android.platform.test.annotations.Presubmit; 57 import android.platform.test.annotations.SystemUserOnly; 58 import android.server.wm.backgroundactivity.common.CommonComponents.Event; 59 import android.server.wm.backgroundactivity.common.EventReceiver; 60 61 import androidx.annotation.Nullable; 62 import androidx.test.filters.FlakyTest; 63 64 import com.android.compatibility.common.util.AppOpsUtils; 65 66 import org.junit.After; 67 import org.junit.Before; 68 import org.junit.Ignore; 69 import org.junit.Test; 70 71 import java.util.List; 72 import java.util.concurrent.TimeoutException; 73 import java.util.stream.Stream; 74 75 /** 76 * This class covers all test cases for starting/blocking background activities. 77 * As instrumentation tests started by shell are whitelisted to allow starting background activity, 78 * tests can't be done in this app alone. 79 * Hence, there are 2 extra apps, appA and appB. This class will send commands to appA/appB, for 80 * example, send a broadcast to appA and ask it to start a background activity, and we will monitor 81 * the result and see if it starts an activity successfully. 82 */ 83 @Presubmit 84 public class BackgroundActivityLaunchTest extends ActivityManagerTestBase { 85 86 private static final int ACTIVITY_FOCUS_TIMEOUT_MS = 3000; 87 private static final String APP_A_PACKAGE_NAME = APP_A_FOREGROUND_ACTIVITY.getPackageName(); 88 private static final long ACTIVITY_BG_START_GRACE_PERIOD_MS = 10 * 1000; 89 private static final int ACTIVITY_START_TIMEOUT_MS = 5000; 90 private static final int ACTIVITY_NOT_RESUMED_TIMEOUT_MS = 5000; 91 92 private static final String TEST_PACKAGE_APP_A = "android.server.wm.backgroundactivity.appa"; 93 private static final String TEST_PACKAGE_APP_B = "android.server.wm.backgroundactivity.appb"; 94 public static final ComponentName APP_A_RELAUNCHING_ACTIVITY = 95 new ComponentName(TEST_PACKAGE_APP_A, 96 "android.server.wm.backgroundactivity.appa.RelaunchingActivity"); 97 public static final ComponentName APP_A_PIP_ACTIVITY = 98 new ComponentName(TEST_PACKAGE_APP_A, 99 "android.server.wm.backgroundactivity.appa.PipActivity"); 100 private static final String SHELL_PACKAGE = "com.android.shell"; 101 102 /** 103 * Tests can be executed as soon as the device has booted. When that happens the broadcast queue 104 * is long and it takes some time to process the broadcast we just sent. 105 */ 106 private static final int BROADCAST_DELIVERY_TIMEOUT_MS = 60000; 107 108 @Override 109 @Before setUp()110 public void setUp() throws Exception { 111 // disable SAW appopp for AppA (it's granted autonatically when installed in CTS) 112 AppOpsUtils.setOpMode(APP_A_PACKAGE_NAME, "android:system_alert_window", MODE_ERRORED); 113 assertEquals(AppOpsUtils.getOpMode(APP_A_PACKAGE_NAME, "android:system_alert_window"), 114 MODE_ERRORED); 115 116 super.setUp(); 117 assertNull(mWmState.getTaskByActivity(APP_A_BACKGROUND_ACTIVITY)); 118 assertNull(mWmState.getTaskByActivity(APP_A_FOREGROUND_ACTIVITY)); 119 assertNull(mWmState.getTaskByActivity(APP_B_FOREGROUND_ACTIVITY)); 120 121 runShellCommand("cmd deviceidle tempwhitelist -d 100000 " 122 + APP_A_FOREGROUND_ACTIVITY.getPackageName()); 123 runShellCommand("cmd deviceidle tempwhitelist -d 100000 " 124 + APP_B_FOREGROUND_ACTIVITY.getPackageName()); 125 } 126 127 @After tearDown()128 public void tearDown() throws Exception { 129 // We do this before anything else, because having an active device owner can prevent us 130 // from being able to force stop apps. (b/142061276) 131 runWithShellPermissionIdentity(() -> { 132 runShellCommand("dpm remove-active-admin --user current " 133 + APP_A_SIMPLE_ADMIN_RECEIVER.flattenToString()); 134 }); 135 136 stopTestPackage(TEST_PACKAGE_APP_A); 137 stopTestPackage(TEST_PACKAGE_APP_B); 138 AppOpsUtils.reset(APP_A_PACKAGE_NAME); 139 AppOpsUtils.reset(SHELL_PACKAGE); 140 } 141 142 @Test testBackgroundActivityBlocked()143 public void testBackgroundActivityBlocked() throws Exception { 144 // Start AppA background activity and blocked 145 Intent intent = new Intent(); 146 intent.setComponent(APP_A_START_ACTIVITY_RECEIVER); 147 mContext.sendBroadcast(intent); 148 boolean result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY); 149 assertFalse("Should not able to launch background activity", result); 150 assertTaskStack(null, APP_A_BACKGROUND_ACTIVITY); 151 } 152 153 @Test testStartBgActivity_usingStartActivitiesFromBackgroundPermission()154 public void testStartBgActivity_usingStartActivitiesFromBackgroundPermission() 155 throws Exception { 156 // Disable SAW app op for shell, since that can also allow starting activities from bg. 157 AppOpsUtils.setOpMode(SHELL_PACKAGE, "android:system_alert_window", MODE_ERRORED); 158 159 // Launch the activity via a shell command, this way the system doesn't have info on which 160 // app launched the activity and thus won't use instrumentation privileges to launch it. But 161 // the shell has the START_ACTIVITIES_FROM_BACKGROUND permission, so we expect it to 162 // succeed. 163 // See testBackgroundActivityBlocked() for a case where an app without the 164 // START_ACTIVITIES_FROM_BACKGROUND permission is blocked from launching the activity from 165 // the background. 166 launchActivity(APP_A_BACKGROUND_ACTIVITY); 167 168 // If the activity launches, it means the START_ACTIVITIES_FROM_BACKGROUND permission works. 169 assertEquals("Launched activity should be at the top", 170 ComponentNameUtils.getActivityName(APP_A_BACKGROUND_ACTIVITY), 171 mWmState.getTopActivityName(0)); 172 } 173 174 @Test 175 @FlakyTest(bugId = 155454710) testBackgroundActivityNotBlockedWithinGracePeriod()176 public void testBackgroundActivityNotBlockedWithinGracePeriod() throws Exception { 177 // Start AppA foreground activity 178 Intent firstIntent = new Intent(); 179 firstIntent.setComponent(APP_A_FOREGROUND_ACTIVITY); 180 firstIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 181 mContext.startActivity(firstIntent); 182 boolean firstResult = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY); 183 assertTrue("Not able to start foreground activity", firstResult); 184 // Don't press home button to avoid stop app switches 185 mContext.sendBroadcast(new Intent(ACTION_FINISH_ACTIVITY)); 186 mWmState.waitAndAssertActivityRemoved(APP_A_FOREGROUND_ACTIVITY); 187 Intent secondIntent = new Intent(); 188 secondIntent.setComponent(APP_A_START_ACTIVITY_RECEIVER); 189 190 mContext.sendBroadcast(secondIntent); 191 boolean secondResult = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY); 192 assertTrue("Should be able to launch background activity", secondResult); 193 } 194 195 @Test testBackgroundActivityNotBlockedWhenSystemAlertWindowGranted()196 public void testBackgroundActivityNotBlockedWhenSystemAlertWindowGranted() throws Exception { 197 // enable appopp for SAW for this test 198 AppOpsUtils.setOpMode(APP_A_PACKAGE_NAME, "android:system_alert_window", MODE_ALLOWED); 199 assertEquals(AppOpsUtils.getOpMode(APP_A_PACKAGE_NAME, "android:system_alert_window"), 200 MODE_ALLOWED); 201 202 // Start AppA background activity successfully as the package has SAW 203 Intent intent = new Intent(); 204 intent.setComponent(APP_A_START_ACTIVITY_RECEIVER); 205 mContext.sendBroadcast(intent); 206 boolean result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY); 207 assertTrue("Not able to start foreground activity", result); 208 } 209 210 @Test testBackgroundActivityNotBlockedWhenForegroundActivityExists()211 public void testBackgroundActivityNotBlockedWhenForegroundActivityExists() throws Exception { 212 // Start AppA foreground activity 213 Intent intent = new Intent(); 214 intent.setComponent(APP_A_FOREGROUND_ACTIVITY); 215 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 216 mContext.startActivity(intent); 217 boolean result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY); 218 assertTrue("Not able to start foreground activity", result); 219 assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY); 220 221 // Start AppA background activity successfully as there's a foreground activity 222 intent = new Intent(); 223 intent.setComponent(APP_A_START_ACTIVITY_RECEIVER); 224 mContext.sendBroadcast(intent); 225 result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY); 226 assertTrue("Not able to launch background activity", result); 227 assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY); 228 assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY}, APP_A_BACKGROUND_ACTIVITY); 229 } 230 231 @Test testActivityNotBlockedWhenForegroundActivityLaunch()232 public void testActivityNotBlockedWhenForegroundActivityLaunch() throws Exception { 233 // Start foreground activity, and foreground activity able to launch background activity 234 // successfully 235 Intent intent = new Intent(); 236 intent.setComponent(APP_A_FOREGROUND_ACTIVITY); 237 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 238 intent.putExtra(LAUNCH_BACKGROUND_ACTIVITY_EXTRA, true); 239 mContext.startActivity(intent); 240 boolean result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY); 241 assertTrue("Not able to launch background activity", result); 242 assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY, APP_A_FOREGROUND_ACTIVITY}, 243 APP_A_FOREGROUND_ACTIVITY); 244 } 245 246 @Test testActivityBroughtToTopOfTaskWhenLaunchedInTheBackground()247 public void testActivityBroughtToTopOfTaskWhenLaunchedInTheBackground() throws Exception { 248 // Start foreground activity, and foreground activity able to launch background activity 249 // successfully 250 Intent intent = new Intent(); 251 intent.setComponent(APP_A_FOREGROUND_ACTIVITY); 252 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 253 mContext.startActivity(intent); 254 boolean result = waitForActivityFocused(ACTIVITY_FOCUS_TIMEOUT_MS, 255 APP_A_FOREGROUND_ACTIVITY); 256 assertTrue("Not able to launch background activity", result); 257 assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY); 258 // We can't resume app switching after pressing home button, otherwise the grace period 259 // will allow the starts. 260 pressHomeAndWaitHomeResumed(); 261 262 mContext.sendBroadcast(getLaunchActivitiesBroadcast(APP_A_BACKGROUND_ACTIVITY)); 263 264 result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY); 265 assertFalse("Previously foreground Activity should not be able to make it focused", result); 266 result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY); 267 assertFalse("Previously background Activity should not be able to make it focused", result); 268 assertTaskStack(new ComponentName[] {APP_A_BACKGROUND_ACTIVITY, APP_A_FOREGROUND_ACTIVITY}, 269 APP_A_FOREGROUND_ACTIVITY); 270 } 271 272 @Test 273 @FlakyTest(bugId = 143522449) testActivityBlockedWhenLaunchedAfterHomePress()274 public void testActivityBlockedWhenLaunchedAfterHomePress() throws Exception { 275 Intent intent = new Intent(); 276 intent.setComponent(APP_A_FOREGROUND_ACTIVITY); 277 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 278 intent.putExtra(LAUNCH_BACKGROUND_ACTIVITY_EXTRA, true); 279 intent.putExtra(START_ACTIVITY_FROM_FG_ACTIVITY_DELAY_MS_EXTRA, 2000); 280 intent.putExtra(START_ACTIVITY_FROM_FG_ACTIVITY_NEW_TASK_EXTRA, true); 281 mContext.startActivity(intent); 282 boolean result = waitForActivityFocused(ACTIVITY_FOCUS_TIMEOUT_MS, 283 APP_A_FOREGROUND_ACTIVITY); 284 assertTrue("Not able to launch background activity", result); 285 assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY); 286 287 // We can't resume app switching after pressing home button, otherwise the grace period 288 // will allow the starts. 289 pressHomeAndWaitHomeResumed(); 290 291 result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY); 292 assertFalse("FG activity shouldn't be visible", result); 293 result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY); 294 assertFalse("BG activity shouldn't be visible", result); 295 assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY); 296 assertTaskStack(null, APP_A_BACKGROUND_ACTIVITY); 297 } 298 299 @Test testActivityNotBlockedFromBgActivityInFgTask()300 public void testActivityNotBlockedFromBgActivityInFgTask() { 301 // Launch Activity A, B in the same task with different processes. 302 final Intent intent = new Intent() 303 .setComponent(APP_A_FOREGROUND_ACTIVITY) 304 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 305 mContext.startActivity(intent); 306 mWmState.waitForValidState(APP_A_FOREGROUND_ACTIVITY); 307 mContext.sendBroadcast(getLaunchActivitiesBroadcast(APP_B_FOREGROUND_ACTIVITY)); 308 mWmState.waitForValidState(APP_B_FOREGROUND_ACTIVITY); 309 assertTaskStack(new ComponentName[]{APP_B_FOREGROUND_ACTIVITY, APP_A_FOREGROUND_ACTIVITY}, 310 APP_A_FOREGROUND_ACTIVITY); 311 312 // Refresh last-stop-app-switch-time by returning to home and then make the task foreground. 313 pressHomeAndResumeAppSwitch(); 314 mContext.startActivity(intent); 315 mWmState.waitForValidState(APP_B_FOREGROUND_ACTIVITY); 316 // Though process A is in background, it is in a visible Task (top is B) so it should be 317 // able to start activity successfully. 318 mContext.sendBroadcast(new Intent(ACTION_LAUNCH_BACKGROUND_ACTIVITIES) 319 .putExtra(LAUNCH_INTENTS_EXTRA, new Intent[]{ new Intent() 320 .setComponent(APP_A_BACKGROUND_ACTIVITY) 321 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) })); 322 mWmState.waitForValidState(APP_A_BACKGROUND_ACTIVITY); 323 mWmState.assertFocusedActivity( 324 "The background activity must be able to launch from a visible task", 325 APP_A_BACKGROUND_ACTIVITY); 326 } 327 328 @Test 329 @FlakyTest(bugId = 130800326) 330 @Ignore // TODO(b/145981637): Make this test work testActivityBlockedWhenForegroundActivityRestartsItself()331 public void testActivityBlockedWhenForegroundActivityRestartsItself() throws Exception { 332 // Start AppA foreground activity 333 Intent intent = new Intent(); 334 intent.setComponent(APP_A_FOREGROUND_ACTIVITY); 335 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 336 intent.putExtra(RELAUNCH_FOREGROUND_ACTIVITY_EXTRA, true); 337 mContext.startActivity(intent); 338 boolean result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY); 339 assertTrue("Not able to start foreground activity", result); 340 assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY); 341 342 // The foreground activity will be paused but will attempt to restart itself in onPause() 343 pressHomeAndResumeAppSwitch(); 344 345 result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY); 346 assertFalse("Previously foreground Activity should not be able to relaunch itself", result); 347 assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY); 348 } 349 350 @Test testSecondActivityNotBlockedWhenForegroundActivityLaunch()351 public void testSecondActivityNotBlockedWhenForegroundActivityLaunch() throws Exception { 352 // Start AppA foreground activity, which will immediately launch one activity 353 // and then the second. 354 Intent intent = new Intent(); 355 intent.setComponent(APP_A_FOREGROUND_ACTIVITY); 356 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 357 intent.putExtra(LAUNCH_BACKGROUND_ACTIVITY_EXTRA, true); 358 intent.putExtra(LAUNCH_SECOND_BACKGROUND_ACTIVITY_EXTRA, true); 359 mContext.startActivity(intent); 360 361 boolean result = waitForActivityFocused(APP_A_SECOND_BACKGROUND_ACTIVITY); 362 assertTrue("Not able to launch second background activity", result); 363 364 waitAndAssertActivityState(APP_A_BACKGROUND_ACTIVITY, STATE_INITIALIZING, 365 "First activity should have been created"); 366 assertTaskStack( 367 new ComponentName[]{APP_A_SECOND_BACKGROUND_ACTIVITY, APP_A_BACKGROUND_ACTIVITY, 368 APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY); 369 } 370 371 @Test 372 @FlakyTest(bugId = 143522449) testSecondActivityBlockedWhenBackgroundActivityLaunch()373 public void testSecondActivityBlockedWhenBackgroundActivityLaunch() throws Exception { 374 Intent baseActivityIntent = new Intent(); 375 baseActivityIntent.setComponent(APP_A_FOREGROUND_ACTIVITY); 376 baseActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 377 mContext.startActivity(baseActivityIntent); 378 boolean result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY); 379 assertTrue("Not able to start foreground activity", result); 380 assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY); 381 // We can't resume app switching after pressing home button, otherwise the grace period 382 // will allow the starts. 383 pressHomeAndWaitHomeResumed(); 384 385 // The activity, now in the background, will attempt to start 2 activities in quick 386 // succession 387 mContext.sendBroadcast(getLaunchActivitiesBroadcast(APP_A_BACKGROUND_ACTIVITY, 388 APP_A_SECOND_BACKGROUND_ACTIVITY)); 389 390 // There should be 2 activities in the background (not focused) INITIALIZING 391 result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY); 392 assertFalse("Activity should not have been launched in the foreground", result); 393 result = waitForActivityFocused(APP_A_SECOND_BACKGROUND_ACTIVITY); 394 assertFalse("Second activity should not have been launched in the foreground", result); 395 assertTaskStack( 396 new ComponentName[]{APP_A_SECOND_BACKGROUND_ACTIVITY, APP_A_BACKGROUND_ACTIVITY, 397 APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY); 398 } 399 400 @Test testPendingIntentActivityBlocked()401 public void testPendingIntentActivityBlocked() throws Exception { 402 // Cannot start activity by pending intent, as both appA and appB are in background 403 sendPendingIntentActivity(); 404 boolean result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY); 405 assertFalse("Should not able to launch background activity", result); 406 assertTaskStack(null, APP_A_BACKGROUND_ACTIVITY); 407 } 408 409 @Test 410 @FlakyTest(bugId = 130800326) testPendingIntentActivityNotBlocked_appAIsForeground()411 public void testPendingIntentActivityNotBlocked_appAIsForeground() throws Exception { 412 // Start AppA foreground activity 413 Intent intent = new Intent(); 414 intent.setComponent(APP_A_FOREGROUND_ACTIVITY); 415 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 416 mContext.startActivity(intent); 417 boolean result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY); 418 assertTrue("Not able to start foreground Activity", result); 419 assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY); 420 421 // Send pendingIntent from AppA to AppB, and the AppB launch the pending intent to start 422 // activity in App A 423 sendPendingIntentActivity(); 424 result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY); 425 assertTrue("Not able to launch background activity", result); 426 assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY); 427 assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY}, APP_A_BACKGROUND_ACTIVITY); 428 } 429 430 @Test testPendingIntentBroadcastActivityNotBlocked_appBIsForeground()431 public void testPendingIntentBroadcastActivityNotBlocked_appBIsForeground() throws Exception { 432 // Start AppB foreground activity 433 Intent intent = new Intent(); 434 intent.setComponent(APP_B_FOREGROUND_ACTIVITY); 435 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 436 mContext.startActivity(intent); 437 boolean result = waitForActivityFocused(APP_B_FOREGROUND_ACTIVITY); 438 assertTrue("Not able to start foreground Activity", result); 439 assertTaskStack(new ComponentName[]{APP_B_FOREGROUND_ACTIVITY}, APP_B_FOREGROUND_ACTIVITY); 440 441 // Send pendingIntent from AppA to AppB, and the AppB launch the pending intent to start 442 // activity in App A 443 sendPendingIntentActivity(); 444 result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY); 445 assertTrue("Not able to launch background activity", result); 446 assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY}, APP_A_BACKGROUND_ACTIVITY); 447 assertTaskStack(new ComponentName[]{APP_B_FOREGROUND_ACTIVITY}, APP_B_FOREGROUND_ACTIVITY); 448 } 449 450 @Test testPendingIntentBroadcastTimeout_noDelay()451 public void testPendingIntentBroadcastTimeout_noDelay() throws Exception { 452 assertPendingIntentBroadcastTimeoutTest(0, true); 453 } 454 455 @Test 456 @FlakyTest(bugId = 141344170) testPendingIntentBroadcastTimeout_delay1s()457 public void testPendingIntentBroadcastTimeout_delay1s() throws Exception { 458 assertPendingIntentBroadcastTimeoutTest(1000, true); 459 } 460 461 @Test testPendingIntentBroadcastTimeout_delay12s()462 public void testPendingIntentBroadcastTimeout_delay12s() throws Exception { 463 assertPendingIntentBroadcastTimeoutTest(12000, false); 464 } 465 466 @Test testPendingIntentBroadcast_appBIsBackground()467 public void testPendingIntentBroadcast_appBIsBackground() throws Exception { 468 EventReceiver receiver = new EventReceiver( 469 Event.APP_A_START_BACKGROUND_ACTIVITY_BROADCAST_RECEIVED); 470 471 // Send pendingIntent from AppA to AppB, and the AppB launch the pending intent to start 472 // activity in App A 473 sendPendingIntentBroadcast(0, receiver.getNotifier()); 474 475 // Waits for final hoop in AppA to start looking for activity, otherwise it could succeed 476 // if the broadcast took long time to get executed (which may happen after boot). 477 receiver.waitForEventOrThrow(BROADCAST_DELIVERY_TIMEOUT_MS); 478 boolean result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY); 479 assertFalse("Should not able to launch background activity", result); 480 assertTaskStack(null, APP_A_BACKGROUND_ACTIVITY); 481 } 482 483 @Test 484 @SystemUserOnly(reason = "Device owner must be SYSTEM user") testDeviceOwner()485 public void testDeviceOwner() throws Exception { 486 // Send pendingIntent from AppA to AppB, and the AppB launch the pending intent to start 487 // activity in App A 488 if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) { 489 return; 490 } 491 492 String cmdResult = runShellCommand("dpm set-device-owner --user 0 " 493 + APP_A_SIMPLE_ADMIN_RECEIVER.flattenToString()); 494 assertThat(cmdResult).contains("Success"); 495 EventReceiver receiver = new EventReceiver( 496 Event.APP_A_START_BACKGROUND_ACTIVITY_BROADCAST_RECEIVED); 497 Intent intent = new Intent(); 498 intent.setComponent(APP_A_START_ACTIVITY_RECEIVER); 499 intent.putExtra(EVENT_NOTIFIER_EXTRA, receiver.getNotifier()); 500 501 mContext.sendBroadcast(intent); 502 503 // Waits for final hoop in AppA to start looking for activity 504 receiver.waitForEventOrThrow(BROADCAST_DELIVERY_TIMEOUT_MS); 505 boolean result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY); 506 assertTrue("Not able to launch background activity", result); 507 assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY}, APP_A_BACKGROUND_ACTIVITY); 508 } 509 510 @Test testAppCannotStartBgActivityAfterHomeButton()511 public void testAppCannotStartBgActivityAfterHomeButton() throws Exception { 512 513 Intent intent = new Intent(); 514 intent.setComponent(APP_A_RELAUNCHING_ACTIVITY); 515 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 516 mContext.startActivity(intent); 517 518 assertTrue("Main activity not started", waitUntilForegroundChanged( 519 TEST_PACKAGE_APP_A, true, ACTIVITY_START_TIMEOUT_MS)); 520 521 // Click home button, and test app activity onPause() will try to start a background 522 // activity, but we expect this will be blocked BAL logic in system, as app cannot start 523 // any background activity even within grace period after pressing home button. 524 pressHomeAndWaitHomeResumed(); 525 526 assertActivityNotResumed(); 527 } 528 529 // Check picture-in-picture(PIP) won't allow to start BAL after pressing home. 530 @Test testPipCannotStartAfterHomeButton()531 public void testPipCannotStartAfterHomeButton() throws Exception { 532 533 Intent intent = new Intent(); 534 intent.setComponent(APP_A_PIP_ACTIVITY); 535 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 536 mContext.startActivity(intent); 537 538 assertTrue("Pip activity not started", waitUntilForegroundChanged( 539 TEST_PACKAGE_APP_A, true, ACTIVITY_START_TIMEOUT_MS)); 540 541 // Click home button, and test app activity onPause() will trigger pip window, 542 // test will will try to start background activity, but we expect the background activity 543 // will be blocked even the app has a visible pip window, as we do not allow background 544 // activity to be started after pressing home button. 545 pressHomeAndWaitHomeResumed(); 546 547 assertActivityNotResumed(); 548 } 549 pressHomeAndWaitHomeResumed()550 private void pressHomeAndWaitHomeResumed() { 551 pressHomeButton(); 552 mWmState.waitForHomeActivityVisible(); 553 } 554 checkPackageResumed(String pkg)555 private boolean checkPackageResumed(String pkg) { 556 WindowManagerStateHelper helper = new WindowManagerStateHelper(); 557 helper.computeState(); 558 return ComponentName.unflattenFromString( 559 helper.getFocusedActivity()).getPackageName().equals(pkg); 560 } 561 562 // Return true if the state of the package is changed to target state. waitUntilForegroundChanged(String targetPkg, boolean toBeResumed, int timeout)563 private boolean waitUntilForegroundChanged(String targetPkg, boolean toBeResumed, int timeout) 564 throws Exception { 565 long startTime = System.currentTimeMillis(); 566 while (checkPackageResumed(targetPkg) != toBeResumed) { 567 if (System.currentTimeMillis() - startTime < timeout) { 568 Thread.sleep(100); 569 } else { 570 return false; 571 } 572 } 573 return true; 574 } 575 assertActivityNotResumed()576 private void assertActivityNotResumed() throws Exception { 577 assertFalse("Test activity is resumed", 578 waitUntilForegroundChanged(TEST_PACKAGE_APP_A, true, 579 ACTIVITY_NOT_RESUMED_TIMEOUT_MS)); 580 } 581 getLaunchActivitiesBroadcast(ComponentName... componentNames)582 private Intent getLaunchActivitiesBroadcast(ComponentName... componentNames) { 583 Intent broadcastIntent = new Intent(ACTION_LAUNCH_BACKGROUND_ACTIVITIES); 584 Intent[] intents = Stream.of(componentNames) 585 .map(c -> { 586 Intent intent = new Intent(); 587 intent.setComponent(c); 588 return intent; 589 }) 590 .toArray(Intent[]::new); 591 broadcastIntent.putExtra(LAUNCH_INTENTS_EXTRA, intents); 592 return broadcastIntent; 593 } 594 pressHomeAndResumeAppSwitch()595 private void pressHomeAndResumeAppSwitch() { 596 // Press home key to ensure stopAppSwitches is called because the last-stop-app-switch-time 597 // is a criteria of allowing background start. 598 pressHomeButton(); 599 // Resume the stopped state (it won't affect last-stop-app-switch-time) so we don't need to 600 // wait extra time to prevent the next launch from being delayed. 601 resumeAppSwitches(); 602 mWmState.waitForHomeActivityVisible(); 603 // Resuming app switches again after home became visible because the previous call might 604 // have raced with pressHomeButton(). 605 // TODO(b/155454710): Remove previous call after making sure all the tests don't depend on 606 // the timing here. 607 resumeAppSwitches(); 608 } 609 assertTaskStack(ComponentName[] expectedComponents, ComponentName sourceComponent)610 private void assertTaskStack(ComponentName[] expectedComponents, 611 ComponentName sourceComponent) { 612 if (expectedComponents == null) { 613 assertNull(mWmState.getTaskByActivity(sourceComponent)); 614 return; 615 } 616 List<WindowManagerState.Activity> actual = mWmState.getTaskByActivity( 617 sourceComponent).mActivities; 618 assertEquals(expectedComponents.length, actual.size()); 619 int size = expectedComponents.length; 620 for (int i = 0; i < size; i++) { 621 assertEquals(expectedComponents[i].flattenToShortString(), actual.get(i).getName()); 622 } 623 } 624 assertPendingIntentBroadcastTimeoutTest(int delayMs, boolean expectedResult)625 private void assertPendingIntentBroadcastTimeoutTest(int delayMs, boolean expectedResult) 626 throws TimeoutException { 627 // Start AppB foreground activity 628 Intent intent = new Intent(); 629 intent.setComponent(APP_B_FOREGROUND_ACTIVITY); 630 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 631 mContext.startActivity(intent); 632 boolean result = waitForActivityFocused(APP_B_FOREGROUND_ACTIVITY); 633 assertTrue("Not able to start foreground Activity", result); 634 assertTaskStack(new ComponentName[]{APP_B_FOREGROUND_ACTIVITY}, APP_B_FOREGROUND_ACTIVITY); 635 EventReceiver receiver = new EventReceiver( 636 Event.APP_A_START_BACKGROUND_ACTIVITY_BROADCAST_RECEIVED); 637 638 // Send pendingIntent from AppA to AppB, and the AppB launch the pending intent to start 639 // activity in App A 640 sendPendingIntentBroadcast(delayMs, receiver.getNotifier()); 641 642 // Waits for final hoop in AppA to start looking for activity 643 receiver.waitForEventOrThrow(BROADCAST_DELIVERY_TIMEOUT_MS); 644 result = waitForActivityFocused(ACTIVITY_FOCUS_TIMEOUT_MS + delayMs, 645 APP_A_BACKGROUND_ACTIVITY); 646 assertEquals(expectedResult, result); 647 if (expectedResult) { 648 assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY}, 649 APP_A_BACKGROUND_ACTIVITY); 650 } else { 651 assertTaskStack(null, APP_A_BACKGROUND_ACTIVITY); 652 } 653 } 654 waitForActivityFocused(ComponentName componentName)655 private boolean waitForActivityFocused(ComponentName componentName) { 656 return waitForActivityFocused(ACTIVITY_FOCUS_TIMEOUT_MS, componentName); 657 } 658 sendPendingIntentActivity()659 private void sendPendingIntentActivity() { 660 Intent intent = new Intent(); 661 intent.setComponent(APP_A_SEND_PENDING_INTENT_RECEIVER); 662 intent.putExtra(IS_BROADCAST_EXTRA, false); 663 mContext.sendBroadcast(intent); 664 } 665 sendPendingIntentBroadcast(int delayMs, @Nullable ResultReceiver eventNotifier)666 private void sendPendingIntentBroadcast(int delayMs, @Nullable ResultReceiver eventNotifier) { 667 Intent intent = new Intent(); 668 intent.setComponent(APP_A_SEND_PENDING_INTENT_RECEIVER); 669 intent.putExtra(IS_BROADCAST_EXTRA, true); 670 if (delayMs > 0) { 671 intent.putExtra(START_ACTIVITY_DELAY_MS_EXTRA, delayMs); 672 } 673 intent.putExtra(EVENT_NOTIFIER_EXTRA, eventNotifier); 674 mContext.sendBroadcast(intent); 675 } 676 } 677