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 android.alarmmanager.cts; 18 19 import static android.alarmmanager.cts.AlarmReceiver.getAlarmSender; 20 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertFalse; 23 import static org.junit.Assert.assertNotNull; 24 import static org.junit.Assert.assertTrue; 25 import static org.junit.Assume.assumeFalse; 26 import static org.junit.Assume.assumeTrue; 27 28 import android.alarmmanager.alarmtestapp.cts.TestAlarmReceiver; 29 import android.alarmmanager.alarmtestapp.cts.TestAlarmScheduler; 30 import android.alarmmanager.alarmtestapp.cts.common.FgsTester; 31 import android.alarmmanager.alarmtestapp.cts.common.PermissionStateChangedReceiver; 32 import android.alarmmanager.alarmtestapp.cts.common.RequestReceiver; 33 import android.alarmmanager.util.AlarmManagerDeviceConfigHelper; 34 import android.alarmmanager.util.Utils; 35 import android.app.Activity; 36 import android.app.AlarmManager; 37 import android.app.AppOpsManager; 38 import android.content.BroadcastReceiver; 39 import android.content.ComponentName; 40 import android.content.Context; 41 import android.content.Intent; 42 import android.content.IntentFilter; 43 import android.content.pm.PackageManager; 44 import android.net.Uri; 45 import android.os.PowerWhitelistManager; 46 import android.os.Process; 47 import android.os.SystemClock; 48 import android.os.UserHandle; 49 import android.platform.test.annotations.AppModeFull; 50 import android.provider.Settings; 51 import android.util.Log; 52 53 import androidx.test.InstrumentationRegistry; 54 import androidx.test.runner.AndroidJUnit4; 55 56 import com.android.compatibility.common.util.AppOpsUtils; 57 import com.android.compatibility.common.util.FeatureUtil; 58 import com.android.compatibility.common.util.ShellUtils; 59 import com.android.compatibility.common.util.SystemUtil; 60 import com.android.compatibility.common.util.TestUtils; 61 62 import org.junit.After; 63 import org.junit.Before; 64 import org.junit.Rule; 65 import org.junit.Test; 66 import org.junit.runner.Description; 67 import org.junit.runner.RunWith; 68 69 import java.io.IOException; 70 import java.util.Random; 71 import java.util.concurrent.CountDownLatch; 72 import java.util.concurrent.TimeUnit; 73 import java.util.concurrent.atomic.AtomicInteger; 74 import java.util.concurrent.atomic.AtomicReference; 75 76 @AppModeFull 77 @RunWith(AndroidJUnit4.class) 78 public class ExactAlarmsTest { 79 /** 80 * TODO (b/182835530): Add more tests for the following: 81 * 82 * Pre-S apps can: 83 * - use setAlarmClock freely -- no temp-allowlist 84 * - use setExactAndAWI with 7 / hr quota with standby and temp-allowlist 85 * - use setInexactAndAWI with 7 / hr quota with standby-bucket "ACTIVE" and temp-allowlist 86 * 87 * S+ apps with permission can: 88 * - use setInexactAWI with low quota + standby and *no* temp-allowlist. 89 */ 90 private static final String TAG = ExactAlarmsTest.class.getSimpleName(); 91 92 private static final String TEST_APP_30 = "android.alarmmanager.alarmtestapp.cts.sdk30"; 93 private static final String TEST_APP_WITH_SCHEDULE_EXACT_ALARM_32 = 94 "android.alarmmanager.alarmtestapp.cts.user_permission_32"; 95 private static final String TEST_APP_WITH_USE_EXACT_ALARM_32 = 96 "android.alarmmanager.alarmtestapp.cts.policy_permission_32"; 97 98 private static final int ALLOW_WHILE_IDLE_QUOTA = 5; 99 private static final long ALLOW_WHILE_IDLE_WINDOW = 10_000; 100 private static final int ALLOW_WHILE_IDLE_COMPAT_QUOTA = 3; 101 private static final long ALLOW_WHILE_IDLE_COMPAT_WINDOW = 10_000; 102 103 /** 104 * Waiting generously long for success because the system can sometimes be slow to 105 * provide expected behavior. 106 * A different and shorter duration should be used while waiting for no-failure, because 107 * even if the system is slow to fail in some cases, it would still cause some 108 * flakiness and get flagged for investigation. 109 */ 110 private static final long DEFAULT_WAIT_FOR_SUCCESS = 30_000; 111 112 private static final String TEST_APP_PACKAGE = "android.alarmmanager.alarmtestapp.cts"; 113 114 private static final Context sContext = InstrumentationRegistry.getTargetContext(); 115 private final AlarmManager mAlarmManager = sContext.getSystemService(AlarmManager.class); 116 private final PowerWhitelistManager mWhitelistManager = sContext.getSystemService( 117 PowerWhitelistManager.class); 118 private final PackageManager mPackageManager = sContext.getPackageManager(); 119 private final ComponentName mPermissionChangeReceiver = new ComponentName(TEST_APP_PACKAGE, 120 PermissionStateChangedReceiver.class.getName()); 121 private final ComponentName mPermissionChangeReceiver32 = new ComponentName( 122 TEST_APP_WITH_SCHEDULE_EXACT_ALARM_32, 123 PermissionStateChangedReceiver.class.getName()); 124 125 private final AlarmManagerDeviceConfigHelper mDeviceConfigHelper = 126 new AlarmManagerDeviceConfigHelper(); 127 private final Random mIdGenerator = new Random(6789); 128 129 @Rule 130 public DumpLoggerRule mFailLoggerRule = new DumpLoggerRule(TAG) { 131 @Override 132 protected void failed(Throwable e, Description description) { 133 super.failed(e, description); 134 AlarmReceiver.dumpState(); 135 } 136 }; 137 138 @Before updateAlarmManagerConstants()139 public void updateAlarmManagerConstants() { 140 mDeviceConfigHelper.with("min_futurity", 0L) 141 .with("allow_while_idle_quota", ALLOW_WHILE_IDLE_QUOTA) 142 .with("allow_while_idle_compat_quota", ALLOW_WHILE_IDLE_COMPAT_QUOTA) 143 .with("allow_while_idle_window", ALLOW_WHILE_IDLE_WINDOW) 144 .with("allow_while_idle_compat_window", ALLOW_WHILE_IDLE_COMPAT_WINDOW) 145 .commitAndAwaitPropagation(); 146 } 147 148 @Before enableChanges()149 public void enableChanges() { 150 Utils.enableChangeForSelf(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION); 151 Utils.enableChangeForSelf(AlarmManager.ENABLE_USE_EXACT_ALARM); 152 Utils.enableChange(AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, TEST_APP_PACKAGE, 153 sContext.getUserId()); 154 } 155 156 @After resetChanges()157 public void resetChanges() { 158 Utils.resetChange(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, sContext.getOpPackageName()); 159 Utils.resetChange(AlarmManager.ENABLE_USE_EXACT_ALARM, sContext.getOpPackageName()); 160 Utils.resetChange(AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, TEST_APP_PACKAGE); 161 } 162 163 @After removeFromWhitelists()164 public void removeFromWhitelists() { 165 removeFromWhitelists(sContext.getOpPackageName()); 166 removeFromWhitelists(TEST_APP_PACKAGE); 167 } 168 removeFromWhitelists(String packageName)169 private void removeFromWhitelists(String packageName) { 170 SystemUtil.runWithShellPermissionIdentity( 171 () -> mWhitelistManager.removeFromWhitelist(packageName)); 172 SystemUtil.runShellCommand("cmd deviceidle tempwhitelist -r " + packageName); 173 } 174 175 @After restoreBatteryState()176 public void restoreBatteryState() { 177 SystemUtil.runShellCommand("cmd deviceidle unforce"); 178 SystemUtil.runShellCommandForNoOutput("dumpsys battery reset"); 179 } 180 181 @After restorePermissionReceiverState()182 public void restorePermissionReceiverState() { 183 SystemUtil.runWithShellPermissionIdentity( 184 () -> mPackageManager.setComponentEnabledSetting(mPermissionChangeReceiver, 185 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, 186 PackageManager.DONT_KILL_APP)); 187 } 188 189 @After resetAppOps()190 public void resetAppOps() throws IOException { 191 AppOpsUtils.reset(TEST_APP_PACKAGE); 192 AppOpsUtils.reset(TEST_APP_30); 193 } 194 195 @After restoreAlarmManagerConstants()196 public void restoreAlarmManagerConstants() throws IOException { 197 mDeviceConfigHelper.restoreAll(); 198 } 199 revokeAppOp(String packageName)200 private void revokeAppOp(String packageName) { 201 setAppOp(packageName, AppOpsManager.MODE_IGNORED); 202 } 203 setAppOp(String packageName, int mode)204 static void setAppOp(String packageName, int mode) { 205 final int uid = Utils.getPackageUid(packageName); 206 AppOpsUtils.setUidMode(uid, AppOpsManager.OPSTR_SCHEDULE_EXACT_ALARM, mode); 207 } 208 getCanScheduleExactAlarmFromTestApp(String testAppName)209 private boolean getCanScheduleExactAlarmFromTestApp(String testAppName) throws Exception { 210 final String apiResult = assertResultFromTestApp( 211 RequestReceiver.ACTION_GET_CAN_SCHEDULE_EXACT_ALARM, testAppName, 212 Activity.RESULT_OK); 213 return Boolean.parseBoolean(apiResult); 214 } 215 216 @Test noPermissionByDefault()217 public void noPermissionByDefault() throws Exception { 218 setAppOp(TEST_APP_PACKAGE, AppOpsManager.MODE_DEFAULT); 219 assertFalse(getCanScheduleExactAlarmFromTestApp(TEST_APP_PACKAGE)); 220 } 221 222 @Test noPermissionWhenIgnored()223 public void noPermissionWhenIgnored() throws Exception { 224 revokeAppOp(TEST_APP_PACKAGE); 225 assertFalse(getCanScheduleExactAlarmFromTestApp(TEST_APP_PACKAGE)); 226 } 227 228 @Test hasPermissionWhenAllowed()229 public void hasPermissionWhenAllowed() throws Exception { 230 setAppOp(TEST_APP_PACKAGE, AppOpsManager.MODE_ALLOWED); 231 assertTrue(getCanScheduleExactAlarmFromTestApp(TEST_APP_PACKAGE)); 232 } 233 234 @Test canScheduleExactAlarmWithPolicyPermission()235 public void canScheduleExactAlarmWithPolicyPermission() { 236 assertTrue(mAlarmManager.canScheduleExactAlarms()); 237 } 238 239 @Test canScheduleExactAlarmWithPolicyPermissionSdk32()240 public void canScheduleExactAlarmWithPolicyPermissionSdk32() throws Exception { 241 // Policy permission is not enabled at SDK 32. 242 assertFalse(getCanScheduleExactAlarmFromTestApp(TEST_APP_WITH_USE_EXACT_ALARM_32)); 243 } 244 245 @Test canScheduleExactAlarmWithUserPermissionSdk32()246 public void canScheduleExactAlarmWithUserPermissionSdk32() throws Exception { 247 // Should be allowed by default. 248 assertTrue(getCanScheduleExactAlarmFromTestApp(TEST_APP_WITH_SCHEDULE_EXACT_ALARM_32)); 249 } 250 251 @Test canScheduleExactAlarmSdk30()252 public void canScheduleExactAlarmSdk30() throws Exception { 253 revokeAppOp(TEST_APP_30); 254 assertTrue(getCanScheduleExactAlarmFromTestApp(TEST_APP_30)); 255 } 256 assertResultFromTestApp(String requestAction, String testAppName, int expectedResult)257 private static String assertResultFromTestApp(String requestAction, String testAppName, 258 int expectedResult) throws InterruptedException { 259 final CountDownLatch resultLatch = new CountDownLatch(1); 260 final AtomicInteger result = new AtomicInteger(-1); 261 final AtomicReference<String> resultData = new AtomicReference<>(null); 262 263 final Intent requestToTestApp = new Intent(requestAction) 264 .setClassName(testAppName, RequestReceiver.class.getName()) 265 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 266 sContext.sendOrderedBroadcast(requestToTestApp, null, new BroadcastReceiver() { 267 @Override 268 public void onReceive(Context context, Intent intent) { 269 result.set(getResultCode()); 270 resultData.set(getResultData()); 271 resultLatch.countDown(); 272 } 273 }, null, Activity.RESULT_CANCELED, null, null); 274 275 assertTrue("Timed out waiting for response from helper app " + testAppName, 276 resultLatch.await(10, TimeUnit.SECONDS)); 277 assertEquals(expectedResult, result.get()); 278 return resultData.get(); 279 } 280 whitelistTestApp()281 private void whitelistTestApp() { 282 SystemUtil.runWithShellPermissionIdentity( 283 () -> mWhitelistManager.addToWhitelist(sContext.getOpPackageName())); 284 } 285 setAlarmClockForFgs(long triggerRTC, String testAppName)286 private void setAlarmClockForFgs(long triggerRTC, String testAppName) throws Exception { 287 final CountDownLatch resultLatch = new CountDownLatch(1); 288 final AtomicInteger result = new AtomicInteger(-1); 289 290 AlarmManager.AlarmClockInfo alarmInfo = new AlarmManager.AlarmClockInfo(triggerRTC, null); 291 292 final Intent requestToTestApp = new Intent(TestAlarmScheduler.ACTION_SET_ALARM_CLOCK) 293 .setClassName(testAppName, TestAlarmScheduler.class.getName()) 294 .putExtra(TestAlarmScheduler.EXTRA_ALARM_CLOCK_INFO, alarmInfo) 295 .putExtra(TestAlarmScheduler.EXTRA_TEST_FGS, true) 296 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 297 298 sContext.sendOrderedBroadcast(requestToTestApp, null, new BroadcastReceiver() { 299 @Override 300 public void onReceive(Context context, Intent intent) { 301 result.set(getResultCode()); 302 resultLatch.countDown(); 303 } 304 }, null, Activity.RESULT_CANCELED, null, null); 305 306 assertTrue("Timed out waiting for response from helper app " + testAppName, 307 resultLatch.await(10, TimeUnit.SECONDS)); 308 assertEquals(Activity.RESULT_OK, result.get()); 309 } 310 311 @Test alarmClockAllowsFGS()312 public void alarmClockAllowsFGS() throws Exception { 313 setAppOp(TEST_APP_PACKAGE, AppOpsManager.MODE_ALLOWED); 314 315 final long triggerRtc = System.currentTimeMillis() + 5_000; 316 setAlarmClockForFgs(triggerRtc, TEST_APP_PACKAGE); 317 318 final AtomicReference<String> resultHolder = new AtomicReference<>(); 319 final CountDownLatch alarmLatch = new CountDownLatch(1); 320 321 final IntentFilter filter = new IntentFilter(TestAlarmReceiver.ACTION_REPORT_ALARM_EXPIRED); 322 final BroadcastReceiver receiver = new BroadcastReceiver() { 323 @Override 324 public void onReceive(Context context, Intent intent) { 325 Log.d(TAG, "Received response intent: " + intent); 326 resultHolder.set(intent.getStringExtra(FgsTester.EXTRA_FGS_START_RESULT)); 327 alarmLatch.countDown(); 328 } 329 }; 330 sContext.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED); 331 try { 332 Thread.sleep(5_000); 333 assertTrue("AlarmClock expiration not reported", 334 alarmLatch.await(30, TimeUnit.SECONDS)); 335 assertEquals("FGS result should be empty", "", resultHolder.get()); 336 } finally { 337 sContext.unregisterReceiver(receiver); 338 } 339 } 340 341 @Test setAlarmClockWithPermission()342 public void setAlarmClockWithPermission() throws Exception { 343 final long now = System.currentTimeMillis(); 344 final int numAlarms = 100; // Number much higher than any quota. 345 for (int i = 0; i < numAlarms; i++) { 346 final int id = mIdGenerator.nextInt(); 347 final AlarmManager.AlarmClockInfo alarmClock = new AlarmManager.AlarmClockInfo(now, 348 null); 349 mAlarmManager.setAlarmClock(alarmClock, getAlarmSender(id, false)); 350 assertTrue("Alarm " + id + " not received", 351 AlarmReceiver.waitForAlarm(id, DEFAULT_WAIT_FOR_SUCCESS)); 352 } 353 } 354 355 @Test setAlarmClockWithoutPermissionOrWhitelist()356 public void setAlarmClockWithoutPermissionOrWhitelist() throws Exception { 357 revokeAppOp(TEST_APP_PACKAGE); 358 assertResultFromTestApp(RequestReceiver.ACTION_SET_ALARM_CLOCK, TEST_APP_PACKAGE, 359 RequestReceiver.RESULT_SECURITY_EXCEPTION); 360 } 361 362 @Test setExactAwiWithoutPermissionOrWhitelist()363 public void setExactAwiWithoutPermissionOrWhitelist() throws Exception { 364 revokeAppOp(TEST_APP_PACKAGE); 365 assertResultFromTestApp(RequestReceiver.ACTION_SET_EXACT_AND_AWI, TEST_APP_PACKAGE, 366 RequestReceiver.RESULT_SECURITY_EXCEPTION); 367 } 368 369 @Test setExactPiWithoutPermissionOrWhitelist()370 public void setExactPiWithoutPermissionOrWhitelist() throws Exception { 371 revokeAppOp(TEST_APP_PACKAGE); 372 assertResultFromTestApp(RequestReceiver.ACTION_SET_EXACT_PI, TEST_APP_PACKAGE, 373 RequestReceiver.RESULT_SECURITY_EXCEPTION); 374 } 375 376 @Test setExactCallbackWithoutPermissionOrWhitelist()377 public void setExactCallbackWithoutPermissionOrWhitelist() throws Exception { 378 revokeAppOp(TEST_APP_PACKAGE); 379 assertResultFromTestApp(RequestReceiver.ACTION_SET_EXACT_CALLBACK, TEST_APP_PACKAGE, 380 Activity.RESULT_OK); 381 } 382 isDeviceIdleEnabled()383 private static boolean isDeviceIdleEnabled() { 384 final String output = SystemUtil.runShellCommand("cmd deviceidle enabled deep").trim(); 385 return Integer.parseInt(output) != 0; 386 } 387 putDeviceToIdle()388 private void putDeviceToIdle() { 389 SystemUtil.runShellCommandForNoOutput("dumpsys battery unplug"); 390 SystemUtil.runShellCommand("cmd deviceidle force-idle deep"); 391 } 392 393 @Test setExactAwiCallbackQuota()394 public void setExactAwiCallbackQuota() throws Exception { 395 assumeTrue(isDeviceIdleEnabled()); 396 putDeviceToIdle(); 397 398 sleepUninterruptiblyUntil(getNextEligibleAwiCompatTime(ALLOW_WHILE_IDLE_COMPAT_QUOTA)); 399 400 int alarmId; 401 for (int i = 0; i < ALLOW_WHILE_IDLE_COMPAT_QUOTA; i++) { 402 final long trigger = SystemClock.elapsedRealtime() + 500; 403 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, trigger, 404 "test-tag", Runnable::run, null, 405 AlarmReceiver.createListener(alarmId = mIdGenerator.nextInt(), true)); 406 Thread.sleep(500); 407 assertTrue("Alarm " + alarmId + " not received", 408 AlarmReceiver.waitForAlarm(alarmId, DEFAULT_WAIT_FOR_SUCCESS)); 409 } 410 411 final long nextSet = SystemClock.elapsedRealtime(); 412 final long nextTrigger = getNextEligibleAwiCompatTime(1); 413 assertTrue("Not enough margin to test reliably", nextTrigger > nextSet + 5000); 414 415 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextSet, 416 "test-tag", Runnable::run, null, 417 AlarmReceiver.createListener(alarmId = mIdGenerator.nextInt(), true)); 418 assertFalse("Alarm received when no quota", AlarmReceiver.waitForAlarm(alarmId, 5000)); 419 420 sleepUninterruptiblyUntil(nextTrigger); 421 assertTrue("Alarm " + alarmId + " not received when back in quota", 422 AlarmReceiver.waitForAlarm(alarmId, DEFAULT_WAIT_FOR_SUCCESS)); 423 } 424 425 @Test setExactAwiWithPermissionAndWhitelist()426 public void setExactAwiWithPermissionAndWhitelist() throws Exception { 427 whitelistTestApp(); 428 final long now = SystemClock.elapsedRealtime(); 429 // The user whitelist takes precedence, so the app should get unrestricted alarms. 430 final int numAlarms = 100; // Number much higher than any quota. 431 for (int i = 0; i < numAlarms; i++) { 432 final int id = mIdGenerator.nextInt(); 433 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, now, 434 getAlarmSender(id, false)); 435 assertTrue("Alarm " + id + " not received", 436 AlarmReceiver.waitForAlarm(id, DEFAULT_WAIT_FOR_SUCCESS)); 437 } 438 } 439 440 @Test setExactAwiExecutorWithPermissionAndWhitelist()441 public void setExactAwiExecutorWithPermissionAndWhitelist() throws Exception { 442 whitelistTestApp(); 443 final long now = SystemClock.elapsedRealtime(); 444 // The user whitelist takes precedence, so the app should get unrestricted alarms. 445 final int numAlarms = 100; // Number much higher than any quota. 446 for (int i = 0; i < numAlarms; i++) { 447 final int id = mIdGenerator.nextInt(); 448 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, now, 449 "test-tag", Runnable::run, null, AlarmReceiver.createListener(id, false)); 450 assertTrue("Alarm " + id + " not received", 451 AlarmReceiver.waitForAlarm(id, DEFAULT_WAIT_FOR_SUCCESS)); 452 } 453 } 454 getNextEligibleAwiTime(int alarmsNeeded)455 private static long getNextEligibleAwiTime(int alarmsNeeded) { 456 assertTrue("Alarms needed exceed max quota", alarmsNeeded <= ALLOW_WHILE_IDLE_QUOTA); 457 final long t = AlarmReceiver.getNthLastAlarmTime(ALLOW_WHILE_IDLE_QUOTA - alarmsNeeded + 1); 458 return t + ALLOW_WHILE_IDLE_WINDOW; 459 } 460 getNextEligibleAwiCompatTime(int alarmsNeeded)461 private static long getNextEligibleAwiCompatTime(int alarmsNeeded) { 462 assertTrue("Alarms needed exceed max quota", alarmsNeeded <= ALLOW_WHILE_IDLE_COMPAT_QUOTA); 463 final long t = AlarmReceiver.getNthLastCompatAlarmTime( 464 ALLOW_WHILE_IDLE_COMPAT_QUOTA - alarmsNeeded + 1); 465 return t + ALLOW_WHILE_IDLE_COMPAT_WINDOW; 466 } 467 sleepUninterruptiblyUntil(long untilElapsed)468 private static void sleepUninterruptiblyUntil(long untilElapsed) { 469 long now; 470 while ((now = SystemClock.elapsedRealtime()) < untilElapsed) { 471 try { 472 Thread.sleep(untilElapsed - now); 473 } catch (InterruptedException e) { 474 Log.e(TAG, "Thread interrupted while reclaiming quota!", e); 475 } 476 } 477 } 478 479 @Test setExactAwiWithPermissionWithoutWhitelist()480 public void setExactAwiWithPermissionWithoutWhitelist() throws Exception { 481 assumeTrue(isDeviceIdleEnabled()); 482 putDeviceToIdle(); 483 484 sleepUninterruptiblyUntil(getNextEligibleAwiTime(ALLOW_WHILE_IDLE_QUOTA)); 485 486 int alarmId; 487 for (int i = 0; i < ALLOW_WHILE_IDLE_QUOTA; i++) { 488 final long trigger = SystemClock.elapsedRealtime() + 500; 489 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, trigger, 490 getAlarmSender(alarmId = mIdGenerator.nextInt(), true)); 491 Thread.sleep(500); 492 assertTrue("Alarm " + alarmId + " not received", 493 AlarmReceiver.waitForAlarm(alarmId, DEFAULT_WAIT_FOR_SUCCESS)); 494 } 495 long nextSet = SystemClock.elapsedRealtime(); 496 final long nextTrigger = getNextEligibleAwiTime(1); 497 assertTrue("Not enough margin to test reliably", nextTrigger > nextSet + 5000); 498 499 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextSet, 500 getAlarmSender(alarmId = mIdGenerator.nextInt(), true)); 501 assertFalse("Alarm received when no quota", AlarmReceiver.waitForAlarm(alarmId, 5000)); 502 503 sleepUninterruptiblyUntil(nextTrigger); 504 assertTrue("Alarm " + alarmId + " not received when back in quota", 505 AlarmReceiver.waitForAlarm(alarmId, DEFAULT_WAIT_FOR_SUCCESS)); 506 } 507 assertTempWhitelistState(boolean whitelisted)508 private static void assertTempWhitelistState(boolean whitelisted) { 509 final String selfAppId = String.valueOf(UserHandle.getAppId(Process.myUid())); 510 SystemUtil.runShellCommand("cmd deviceidle tempwhitelist", 511 output -> (output.contains(selfAppId) == whitelisted)); 512 } 513 514 @Test alarmClockGrantsWhitelist()515 public void alarmClockGrantsWhitelist() throws Exception { 516 // no device idle in auto 517 assumeFalse(FeatureUtil.isAutomotive()); 518 519 final int id = mIdGenerator.nextInt(); 520 final AlarmManager.AlarmClockInfo alarmClock = new AlarmManager.AlarmClockInfo( 521 System.currentTimeMillis() + 100, null); 522 mAlarmManager.setAlarmClock(alarmClock, getAlarmSender(id, false)); 523 Thread.sleep(100); 524 assertTrue("Alarm " + id + " not received", AlarmReceiver.waitForAlarm(id, 525 DEFAULT_WAIT_FOR_SUCCESS)); 526 assertTempWhitelistState(true); 527 } 528 529 @Test exactAwiGrantsWhitelist()530 public void exactAwiGrantsWhitelist() throws Exception { 531 // no device idle in auto 532 assumeFalse(FeatureUtil.isAutomotive()); 533 534 sleepUninterruptiblyUntil(getNextEligibleAwiTime(1)); 535 536 final int id = mIdGenerator.nextInt(); 537 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, 538 SystemClock.elapsedRealtime() + 100, getAlarmSender(id, false)); 539 Thread.sleep(100); 540 assertTrue("Alarm " + id + " not received", AlarmReceiver.waitForAlarm(id, 541 DEFAULT_WAIT_FOR_SUCCESS)); 542 assertTempWhitelistState(true); 543 } 544 545 @Test activityToRequestPermissionExists()546 public void activityToRequestPermissionExists() { 547 final Intent request = new Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM); 548 final PackageManager pm = sContext.getPackageManager(); 549 550 assertNotNull("No activity found for " + Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM, 551 pm.resolveActivity(request, 0)); 552 553 request.setData(Uri.fromParts("package", sContext.getOpPackageName(), null)); 554 555 assertNotNull("No app specific activity found for " 556 + Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM, pm.resolveActivity(request, 0)); 557 } 558 559 /** 560 * Check if a given UID is in the "can start FGS" allowlist. 561 */ checkThisAppTempAllowListed(int uid)562 private boolean checkThisAppTempAllowListed(int uid) { 563 // The allowlist used internally is ActivityManagerService.mFgsStartTempAllowList. We 564 // don't use the device-idle allowlist directly. 565 566 // Run "dumpsys activity processes", and remove everything until "mFgsStartTempAllowList:". 567 String output = ShellUtils.runShellCommand("dumpsys activity processes"); 568 output = output.replaceFirst("^.*? mFgsStartTempAllowList:$", ""); 569 570 final String uidStr = UserHandle.formatUid(uid); 571 final String expected = "^\\s*" + uidStr + ":"; 572 for (String line : output.split("\n")) { 573 if (line.matches(expected)) { 574 return true; 575 } 576 } 577 return false; 578 } 579 prepareTestAppForBroadcast(ComponentName receiver)580 private void prepareTestAppForBroadcast(ComponentName receiver) { 581 // Just send an explicit foreground broadcast to the test app to make sure 582 // the app is out of force-stop. 583 SystemUtil.runWithShellPermissionIdentity( 584 () -> mPackageManager.setComponentEnabledSetting(receiver, 585 PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 586 PackageManager.DONT_KILL_APP)); 587 Log.d(TAG, "Un-force-stoppping the test app"); 588 Intent i = new Intent("android.app.action.cts.ACTION_PING"); 589 i.setComponent(receiver); 590 i.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); 591 sContext.sendBroadcast(i); 592 } 593 594 @Test scheduleExactAlarmPermissionStateChangedSentAppOp()595 public void scheduleExactAlarmPermissionStateChangedSentAppOp() throws Exception { 596 // Revoke the permission, and remove it from the temp-allowlist. 597 prepareTestAppForBroadcast(mPermissionChangeReceiver); 598 Log.d(TAG, "Revoking the appop"); 599 revokeAppOp(TEST_APP_PACKAGE); 600 removeFromWhitelists(TEST_APP_PACKAGE); 601 602 final int uid = Utils.getPackageUid(TEST_APP_PACKAGE); 603 TestUtils.waitUntil("Package still allowlisted", 604 () -> !checkThisAppTempAllowListed(uid)); 605 606 Thread.sleep(1000); // Give the system a little time to settle down. 607 608 final IntentFilter filter = new IntentFilter( 609 PermissionStateChangedReceiver.ACTION_FGS_START_RESULT); 610 final AtomicReference<String> resultHolder = new AtomicReference<>(); 611 final CountDownLatch latch = new CountDownLatch(1); 612 final BroadcastReceiver receiver = new BroadcastReceiver() { 613 @Override 614 public void onReceive(Context context, Intent intent) { 615 Log.d(TAG, "Received response intent: " + intent); 616 resultHolder.set(intent.getStringExtra( 617 FgsTester.EXTRA_FGS_START_RESULT)); 618 latch.countDown(); 619 } 620 }; 621 sContext.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED); 622 try { 623 Log.d(TAG, "Granting the appop"); 624 setAppOp(TEST_APP_PACKAGE, AppOpsManager.MODE_ALLOWED); 625 626 assertTrue("Didn't receive response", 627 latch.await(30, TimeUnit.SECONDS)); 628 assertEquals("Failure message should be empty", "", resultHolder.get()); 629 } finally { 630 sContext.unregisterReceiver(receiver); 631 } 632 } 633 } 634