Merge "Flip the protection level for SCHEDULE_EXACT_ALARM" into udc-dev

This commit is contained in:
Suprabh Shukla
2023-03-15 18:59:08 +00:00
committed by Android (Google) Code Review
5 changed files with 220 additions and 185 deletions

View File

@@ -30,6 +30,9 @@ import static android.app.AlarmManager.INTERVAL_DAY;
import static android.app.AlarmManager.INTERVAL_HOUR;
import static android.app.AlarmManager.RTC;
import static android.app.AlarmManager.RTC_WAKEUP;
import static android.content.PermissionChecker.PERMISSION_GRANTED;
import static android.content.PermissionChecker.PID_UNKNOWN;
import static android.content.PermissionChecker.checkPermissionForPreflight;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.os.PowerExemptionManager.REASON_ALARM_MANAGER_ALARM_CLOCK;
import static android.os.PowerExemptionManager.REASON_DENIED;
@@ -87,11 +90,9 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.PermissionChecker;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.UserPackage;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.BatteryManager;
import android.os.BatteryStatsInternal;
@@ -182,7 +183,6 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.TimeZone;
@@ -269,7 +269,8 @@ public class AlarmManagerService extends SystemService {
/**
* A map from uid to the last op-mode we have seen for
* {@link AppOpsManager#OP_SCHEDULE_EXACT_ALARM}
* {@link AppOpsManager#OP_SCHEDULE_EXACT_ALARM}. Used for evaluating permission state change
* when the denylist changes.
*/
@VisibleForTesting
@GuardedBy("mLock")
@@ -2097,20 +2098,31 @@ public class AlarmManagerService extends SystemService {
if (oldMode == newMode) {
return;
}
final boolean allowedByDefault =
isScheduleExactAlarmAllowedByDefault(packageName, uid);
final boolean deniedByDefault = isScheduleExactAlarmDeniedByDefault(
packageName, UserHandle.getUserId(uid));
final boolean hadPermission;
if (oldMode != AppOpsManager.MODE_DEFAULT) {
hadPermission = (oldMode == AppOpsManager.MODE_ALLOWED);
} else {
hadPermission = allowedByDefault;
}
final boolean hasPermission;
if (newMode != AppOpsManager.MODE_DEFAULT) {
hasPermission = (newMode == AppOpsManager.MODE_ALLOWED);
if (deniedByDefault) {
final boolean permissionState = getContext().checkPermission(
Manifest.permission.SCHEDULE_EXACT_ALARM, PID_UNKNOWN,
uid) == PackageManager.PERMISSION_GRANTED;
hadPermission = (oldMode == AppOpsManager.MODE_DEFAULT)
? permissionState
: (oldMode == AppOpsManager.MODE_ALLOWED);
hasPermission = (newMode == AppOpsManager.MODE_DEFAULT)
? permissionState
: (newMode == AppOpsManager.MODE_ALLOWED);
} else {
hasPermission = allowedByDefault;
final boolean allowedByDefault =
!mConstants.EXACT_ALARM_DENY_LIST.contains(packageName);
hadPermission = (oldMode == AppOpsManager.MODE_DEFAULT)
? allowedByDefault
: (oldMode == AppOpsManager.MODE_ALLOWED);
hasPermission = (newMode == AppOpsManager.MODE_DEFAULT)
? allowedByDefault
: (newMode == AppOpsManager.MODE_ALLOWED);
}
if (hadPermission && !hasPermission) {
@@ -2754,41 +2766,13 @@ public class AlarmManagerService extends SystemService {
boolean hasUseExactAlarmInternal(String packageName, int uid) {
return isUseExactAlarmEnabled(packageName, UserHandle.getUserId(uid))
&& (PermissionChecker.checkPermissionForPreflight(getContext(),
Manifest.permission.USE_EXACT_ALARM, PermissionChecker.PID_UNKNOWN, uid,
packageName) == PermissionChecker.PERMISSION_GRANTED);
}
/**
* Returns whether SCHEDULE_EXACT_ALARM is allowed by default.
*/
boolean isScheduleExactAlarmAllowedByDefault(String packageName, int uid) {
if (isScheduleExactAlarmDeniedByDefault(packageName, UserHandle.getUserId(uid))) {
// This is essentially like changing the protection level of the permission to
// (privileged|signature|role|appop), but have to implement this logic to maintain
// compatibility for older apps.
if (mPackageManagerInternal.isPlatformSigned(packageName)
|| mPackageManagerInternal.isUidPrivileged(uid)) {
return true;
}
final long token = Binder.clearCallingIdentity();
try {
final List<String> wellbeingHolders = (mRoleManager != null)
? mRoleManager.getRoleHolders(RoleManager.ROLE_SYSTEM_WELLBEING)
: Collections.emptyList();
return wellbeingHolders.contains(packageName);
} finally {
Binder.restoreCallingIdentity(token);
}
}
return !mConstants.EXACT_ALARM_DENY_LIST.contains(packageName);
&& (checkPermissionForPreflight(getContext(), Manifest.permission.USE_EXACT_ALARM,
PID_UNKNOWN, uid, packageName) == PERMISSION_GRANTED);
}
boolean hasScheduleExactAlarmInternal(String packageName, int uid) {
final long start = mStatLogger.getTime();
// Not using getScheduleExactAlarmState as this can avoid some calls to AppOpsService.
// Not using #mLastOpScheduleExactAlarm as it may contain stale values.
// No locking needed as all internal containers being queried are immutable.
final boolean hasPermission;
@@ -2796,11 +2780,16 @@ public class AlarmManagerService extends SystemService {
hasPermission = false;
} else if (!isExactAlarmChangeEnabled(packageName, UserHandle.getUserId(uid))) {
hasPermission = false;
} else if (isScheduleExactAlarmDeniedByDefault(packageName, UserHandle.getUserId(uid))) {
hasPermission = (checkPermissionForPreflight(getContext(),
Manifest.permission.SCHEDULE_EXACT_ALARM, PID_UNKNOWN, uid, packageName)
== PERMISSION_GRANTED);
} else {
// Compatibility permission check for older apps.
final int mode = mAppOps.checkOpNoThrow(AppOpsManager.OP_SCHEDULE_EXACT_ALARM, uid,
packageName);
if (mode == AppOpsManager.MODE_DEFAULT) {
hasPermission = isScheduleExactAlarmAllowedByDefault(packageName, uid);
hasPermission = !mConstants.EXACT_ALARM_DENY_LIST.contains(packageName);
} else {
hasPermission = (mode == AppOpsManager.MODE_ALLOWED);
}
@@ -4685,10 +4674,6 @@ public class AlarmManagerService extends SystemService {
return service.new ClockReceiver();
}
void registerContentObserver(ContentObserver contentObserver, Uri uri) {
mContext.getContentResolver().registerContentObserver(uri, false, contentObserver);
}
void registerDeviceConfigListener(DeviceConfig.OnPropertiesChangedListener listener) {
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ALARM_MANAGER,
AppSchedulingModuleThread.getExecutor(), listener);

View File

@@ -5303,12 +5303,12 @@
{@link android.Manifest.permission#USE_EXACT_ALARM} once it targets API
{@link android.os.Build.VERSION_CODES#TIRAMISU}. All apps using exact alarms for secondary
features (which should still be user facing) should continue using this permission.
<p>Protection level: appop
<p>Protection level: signature|privileged|appop
-->
<permission android:name="android.permission.SCHEDULE_EXACT_ALARM"
android:label="@string/permlab_schedule_exact_alarm"
android:description="@string/permdesc_schedule_exact_alarm"
android:protectionLevel="normal|appop"/>
android:protectionLevel="signature|privileged|appop"/>
<!-- Allows apps to use exact alarms just like with {@link
android.Manifest.permission#SCHEDULE_EXACT_ALARM} but without needing to request this

View File

@@ -20,6 +20,7 @@
<permission name="android.permission.CALL_PRIVILEGED"/>
<permission name="android.permission.MANAGE_USERS"/>
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<permission name="android.permission.SCHEDULE_EXACT_ALARM"/>
<permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"/>
<!-- Required to update emergency gesture settings -->
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>

View File

@@ -321,6 +321,7 @@ applications that come with the platform
<permission name="android.permission.REGISTER_CONNECTION_MANAGER"/>
<permission name="android.permission.REGISTER_SIM_SUBSCRIPTION"/>
<permission name="android.permission.RETRIEVE_WINDOW_CONTENT"/>
<permission name="android.permission.SCHEDULE_EXACT_ALARM"/>
<permission name="android.permission.SET_ALWAYS_FINISH"/>
<permission name="android.permission.SET_ANIMATION_SCALE"/>
<permission name="android.permission.SET_DEBUG_APP"/>

View File

@@ -28,7 +28,6 @@ import static android.app.AlarmManager.FLAG_STANDALONE;
import static android.app.AlarmManager.FLAG_WAKE_FROM_IDLE;
import static android.app.AlarmManager.RTC;
import static android.app.AlarmManager.RTC_WAKEUP;
import static android.app.AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT;
import static android.app.AlarmManager.WINDOW_EXACT;
import static android.app.AlarmManager.WINDOW_HEURISTIC;
import static android.app.AppOpsManager.MODE_ALLOWED;
@@ -126,7 +125,6 @@ import android.app.IAlarmListener;
import android.app.IAlarmManager;
import android.app.PendingIntent;
import android.app.compat.CompatChanges;
import android.app.role.RoleManager;
import android.app.tare.EconomyManager;
import android.app.usage.UsageStatsManagerInternal;
import android.content.ContentResolver;
@@ -134,7 +132,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.PermissionChecker;
import android.content.pm.PackageManagerInternal;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.BatteryManager;
import android.os.Bundle;
@@ -192,7 +189,6 @@ import org.mockito.quality.Strictness;
import org.mockito.stubbing.Answer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@@ -246,8 +242,6 @@ public final class AlarmManagerServiceTest {
@Mock
private PackageManagerInternal mPackageManagerInternal;
@Mock
private RoleManager mRoleManager;
@Mock
private AppStateTrackerImpl mAppStateTracker;
@Mock
private AlarmManagerService.ClockReceiver mClockReceiver;
@@ -392,11 +386,6 @@ public final class AlarmManagerServiceTest {
return mWakeLock;
}
@Override
void registerContentObserver(ContentObserver observer, Uri uri) {
// Do nothing.
}
@Override
void registerDeviceConfigListener(DeviceConfig.OnPropertiesChangedListener listener) {
// Do nothing.
@@ -484,10 +473,12 @@ public final class AlarmManagerServiceTest {
doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
() -> PermissionChecker.checkPermissionForPreflight(any(),
eq(Manifest.permission.USE_EXACT_ALARM), anyInt(), anyInt(), anyString()));
doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
() -> PermissionChecker.checkPermissionForPreflight(any(), eq(SCHEDULE_EXACT_ALARM),
anyInt(), anyInt(), anyString()));
when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);
when(mMockContext.getSystemService(BatteryManager.class)).thenReturn(mBatteryManager);
when(mMockContext.getSystemService(RoleManager.class)).thenReturn(mRoleManager);
registerAppIds(new String[]{TEST_CALLING_PACKAGE},
new Integer[]{UserHandle.getAppId(TEST_CALLING_UID)});
@@ -2181,40 +2172,6 @@ public final class AlarmManagerServiceTest {
}
}
@Test
public void hasScheduleExactAlarmBinderCallNotDenyListed() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockScheduleExactAlarmState(true, false, MODE_DEFAULT);
assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
mockScheduleExactAlarmState(true, false, MODE_ALLOWED);
assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
mockScheduleExactAlarmState(true, false, MODE_IGNORED);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
}
@Test
public void hasScheduleExactAlarmBinderCallDenyListed() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockScheduleExactAlarmState(true, true, MODE_ERRORED);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
mockScheduleExactAlarmState(true, true, MODE_DEFAULT);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
mockScheduleExactAlarmState(true, true, MODE_IGNORED);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
mockScheduleExactAlarmState(true, true, MODE_ALLOWED);
assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
}
private void mockChangeEnabled(long changeId, boolean enabled) {
doReturn(enabled).when(() -> CompatChanges.isChangeEnabled(eq(changeId), anyString(),
any(UserHandle.class)));
@@ -2222,16 +2179,62 @@ public final class AlarmManagerServiceTest {
}
@Test
public void hasScheduleExactAlarmBinderCallNotDeclared() throws RemoteException {
public void hasScheduleExactAlarmBinderCall() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockChangeEnabled(AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, true);
mockScheduleExactAlarmState(true);
assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
mockScheduleExactAlarmState(false);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
}
@Test
public void hasScheduleExactAlarmBinderCallNotDenyListedPreT() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockScheduleExactAlarmState(false, false, MODE_DEFAULT);
mockScheduleExactAlarmStatePreT(true, false, MODE_DEFAULT);
assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
mockScheduleExactAlarmStatePreT(true, false, MODE_ALLOWED);
assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
mockScheduleExactAlarmState(false, false, MODE_ALLOWED);
mockScheduleExactAlarmStatePreT(true, false, MODE_IGNORED);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
}
@Test
public void hasScheduleExactAlarmBinderCallDenyListedPreT() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockScheduleExactAlarmStatePreT(true, true, MODE_ERRORED);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
mockScheduleExactAlarmState(false, true, MODE_ALLOWED);
mockScheduleExactAlarmStatePreT(true, true, MODE_DEFAULT);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
mockScheduleExactAlarmStatePreT(true, true, MODE_IGNORED);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
mockScheduleExactAlarmStatePreT(true, true, MODE_ALLOWED);
assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
}
@Test
public void hasScheduleExactAlarmBinderCallNotDeclaredPreT() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockScheduleExactAlarmStatePreT(false, false, MODE_DEFAULT);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
mockScheduleExactAlarmStatePreT(false, false, MODE_ALLOWED);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
mockScheduleExactAlarmStatePreT(false, true, MODE_ALLOWED);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
}
@@ -2240,61 +2243,94 @@ public final class AlarmManagerServiceTest {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, false);
// canScheduleExactAlarms should be true regardless of any permission state.
mockUseExactAlarmState(true);
// Both SEA and UEA are denied in setUp.
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
mockUseExactAlarmState(false);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
mockScheduleExactAlarmState(false, true, MODE_DEFAULT);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
mockScheduleExactAlarmState(false);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
}
@Test
public void canScheduleExactAlarmsBinderCall() throws RemoteException {
public void canScheduleExactAlarmsBinderCallPreT() throws RemoteException {
// Policy permission is denied in setUp().
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, true);
// No permission, no exemption.
mockScheduleExactAlarmState(true, true, MODE_DEFAULT);
mockScheduleExactAlarmStatePreT(true, true, MODE_DEFAULT);
assertFalse(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
// No permission, no exemption.
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED);
assertFalse(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
// Policy permission only, no exemption.
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED);
mockUseExactAlarmState(true);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
mockUseExactAlarmState(false);
// User permission only, no exemption.
mockScheduleExactAlarmState(true, false, MODE_DEFAULT);
mockScheduleExactAlarmStatePreT(true, false, MODE_DEFAULT);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
// User permission only, no exemption.
mockScheduleExactAlarmState(true, true, MODE_ALLOWED);
mockScheduleExactAlarmStatePreT(true, true, MODE_ALLOWED);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
// No permission, exemption.
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED);
when(mDeviceIdleInternal.isAppOnWhitelist(TEST_CALLING_UID)).thenReturn(true);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
// No permission, exemption.
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED);
when(mDeviceIdleInternal.isAppOnWhitelist(TEST_CALLING_UID)).thenReturn(false);
doReturn(true).when(() -> UserHandle.isCore(TEST_CALLING_UID));
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
// Both permissions and exemption.
mockScheduleExactAlarmState(true, false, MODE_ALLOWED);
mockScheduleExactAlarmStatePreT(true, false, MODE_ALLOWED);
mockUseExactAlarmState(true);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
}
@Test
public void canScheduleExactAlarmsBinderCall() throws RemoteException {
// Both permissions are denied in setUp().
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, true);
mockChangeEnabled(AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, true);
// No permission, no exemption.
assertFalse(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
// Policy permission only, no exemption.
mockUseExactAlarmState(true);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
mockUseExactAlarmState(false);
// User permission only, no exemption.
mockScheduleExactAlarmState(true);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
// No permission, exemption.
mockScheduleExactAlarmState(false);
when(mDeviceIdleInternal.isAppOnWhitelist(TEST_CALLING_UID)).thenReturn(true);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
// No permission, core uid exemption.
when(mDeviceIdleInternal.isAppOnWhitelist(TEST_CALLING_UID)).thenReturn(false);
doReturn(true).when(() -> UserHandle.isCore(TEST_CALLING_UID));
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
// Both permissions and core uid exemption.
mockScheduleExactAlarmState(true);
mockUseExactAlarmState(true);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
}
@@ -2404,8 +2440,9 @@ public final class AlarmManagerServiceTest {
@Test
public void alarmClockBinderCallWithSEAPermission() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockChangeEnabled(AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, true);
mockScheduleExactAlarmState(true, false, MODE_ALLOWED);
mockScheduleExactAlarmState(true);
final PendingIntent alarmPi = getNewMockPendingIntent();
final AlarmManager.AlarmClockInfo alarmClock = mock(AlarmManager.AlarmClockInfo.class);
@@ -2431,9 +2468,10 @@ public final class AlarmManagerServiceTest {
public void alarmClockBinderCallWithUEAPermission() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, true);
mockChangeEnabled(AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, true);
mockUseExactAlarmState(true);
mockScheduleExactAlarmState(false, false, MODE_ERRORED);
mockScheduleExactAlarmState(false);
final PendingIntent alarmPi = getNewMockPendingIntent();
final AlarmManager.AlarmClockInfo alarmClock = mock(AlarmManager.AlarmClockInfo.class);
@@ -2455,7 +2493,7 @@ public final class AlarmManagerServiceTest {
assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, type);
}
private void mockScheduleExactAlarmState(boolean declared, boolean denyList, int mode) {
private void mockScheduleExactAlarmStatePreT(boolean declared, boolean denyList, int mode) {
String[] requesters = declared ? new String[]{TEST_CALLING_PACKAGE} : EmptyArray.STRING;
when(mPermissionManagerInternal.getAppOpPermissionPackages(SCHEDULE_EXACT_ALARM))
.thenReturn(requesters);
@@ -2470,6 +2508,20 @@ public final class AlarmManagerServiceTest {
TEST_CALLING_PACKAGE)).thenReturn(mode);
}
private void mockScheduleExactAlarmState(boolean granted) {
String[] requesters = granted ? new String[]{TEST_CALLING_PACKAGE} : EmptyArray.STRING;
when(mPermissionManagerInternal.getAppOpPermissionPackages(SCHEDULE_EXACT_ALARM))
.thenReturn(requesters);
mService.refreshExactAlarmCandidates();
final int result = granted ? PermissionChecker.PERMISSION_GRANTED
: PermissionChecker.PERMISSION_HARD_DENIED;
doReturn(result).when(
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
eq(SCHEDULE_EXACT_ALARM), anyInt(), eq(TEST_CALLING_UID),
eq(TEST_CALLING_PACKAGE)));
}
private void mockUseExactAlarmState(boolean granted) {
final int result = granted ? PermissionChecker.PERMISSION_GRANTED
: PermissionChecker.PERMISSION_HARD_DENIED;
@@ -2483,7 +2535,7 @@ public final class AlarmManagerServiceTest {
public void alarmClockBinderCallWithoutPermission() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED);
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true);
final PendingIntent alarmPi = getNewMockPendingIntent();
@@ -2504,8 +2556,9 @@ public final class AlarmManagerServiceTest {
@Test
public void exactBinderCallWithSEAPermission() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockChangeEnabled(AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, true);
mockScheduleExactAlarmState(true, false, MODE_ALLOWED);
mockScheduleExactAlarmState(true);
final PendingIntent alarmPi = getNewMockPendingIntent();
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0,
0, alarmPi, null, null, null, null);
@@ -2529,9 +2582,10 @@ public final class AlarmManagerServiceTest {
public void exactBinderCallWithUEAPermission() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, true);
mockChangeEnabled(AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, true);
mockUseExactAlarmState(true);
mockScheduleExactAlarmState(false, false, MODE_ERRORED);
mockScheduleExactAlarmState(false);
final PendingIntent alarmPi = getNewMockPendingIntent();
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0,
0, alarmPi, null, null, null, null);
@@ -2555,7 +2609,7 @@ public final class AlarmManagerServiceTest {
public void exactBinderCallWithAllowlist() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
// If permission is denied, only then allowlist will be checked.
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED);
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true);
final PendingIntent alarmPi = getNewMockPendingIntent();
@@ -2575,7 +2629,7 @@ public final class AlarmManagerServiceTest {
public void exactAllowWhileIdleBinderCallWithSEAPermission() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockScheduleExactAlarmState(true, false, MODE_ALLOWED);
mockScheduleExactAlarmStatePreT(true, false, MODE_ALLOWED);
final PendingIntent alarmPi = getNewMockPendingIntent();
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0,
FLAG_ALLOW_WHILE_IDLE, alarmPi, null, null, null, null);
@@ -2601,7 +2655,7 @@ public final class AlarmManagerServiceTest {
mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, true);
mockUseExactAlarmState(true);
mockScheduleExactAlarmState(false, false, MODE_ERRORED);
mockScheduleExactAlarmStatePreT(false, false, MODE_ERRORED);
final PendingIntent alarmPi = getNewMockPendingIntent();
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0,
FLAG_ALLOW_WHILE_IDLE, alarmPi, null, null, null, null);
@@ -2625,7 +2679,7 @@ public final class AlarmManagerServiceTest {
public void exactAllowWhileIdleBinderCallWithAllowlist() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
// If permission is denied, only then allowlist will be checked.
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED);
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true);
final PendingIntent alarmPi = getNewMockPendingIntent();
@@ -2651,7 +2705,7 @@ public final class AlarmManagerServiceTest {
public void exactBinderCallsWithoutPermissionWithoutAllowlist() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED);
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(false);
final PendingIntent alarmPi = getNewMockPendingIntent();
@@ -2701,7 +2755,7 @@ public final class AlarmManagerServiceTest {
public void binderCallWithUserAllowlist() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED);
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true);
when(mAppStateTracker.isUidPowerSaveUserExempt(TEST_CALLING_UID)).thenReturn(true);
@@ -3026,7 +3080,7 @@ public final class AlarmManagerServiceTest {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mService.mLastOpScheduleExactAlarm.put(TEST_CALLING_UID, MODE_ALLOWED);
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED);
mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
assertAndHandleMessageSync(REMOVE_EXACT_ALARMS);
@@ -3039,7 +3093,7 @@ public final class AlarmManagerServiceTest {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, false);
mService.mLastOpScheduleExactAlarm.put(TEST_CALLING_UID, MODE_ALLOWED);
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED);
mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
@@ -3052,7 +3106,7 @@ public final class AlarmManagerServiceTest {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, false);
mService.mLastOpScheduleExactAlarm.put(TEST_CALLING_UID, MODE_ERRORED);
mockScheduleExactAlarmState(true, true, MODE_DEFAULT);
mockScheduleExactAlarmStatePreT(true, true, MODE_DEFAULT);
mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
@@ -3068,7 +3122,7 @@ public final class AlarmManagerServiceTest {
when(mActivityManagerInternal.getBootTimeTempAllowListDuration()).thenReturn(durationMs);
mService.mLastOpScheduleExactAlarm.put(TEST_CALLING_UID, MODE_ERRORED);
mockScheduleExactAlarmState(true, false, MODE_ALLOWED);
mockScheduleExactAlarmStatePreT(true, false, MODE_ALLOWED);
mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
@@ -3328,7 +3382,7 @@ public final class AlarmManagerServiceTest {
.putExtra(Intent.EXTRA_REPLACING, true);
mockUseExactAlarmState(false);
mockScheduleExactAlarmState(true, false, MODE_ALLOWED);
mockScheduleExactAlarmStatePreT(true, false, MODE_ALLOWED);
mPackageChangesReceiver.onReceive(mMockContext, packageReplacedIntent);
assertAndHandleMessageSync(CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE);
@@ -3336,7 +3390,7 @@ public final class AlarmManagerServiceTest {
assertEquals(5, mService.mAlarmStore.size());
mockUseExactAlarmState(true);
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED);
mPackageChangesReceiver.onReceive(mMockContext, packageReplacedIntent);
assertAndHandleMessageSync(CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE);
@@ -3344,7 +3398,7 @@ public final class AlarmManagerServiceTest {
assertEquals(5, mService.mAlarmStore.size());
mockUseExactAlarmState(false);
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED);
mPackageChangesReceiver.onReceive(mMockContext, packageReplacedIntent);
assertAndHandleMessageSync(CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE);
@@ -3362,55 +3416,6 @@ public final class AlarmManagerServiceTest {
assertEquals(0, remaining.size());
}
@Test
public void isScheduleExactAlarmAllowedByDefault() {
final String package1 = "priv";
final String package2 = "signed";
final String package3 = "normal";
final String package4 = "wellbeing";
final int uid1 = 1294;
final int uid2 = 8321;
final int uid3 = 3412;
final int uid4 = 4591;
when(mPackageManagerInternal.isUidPrivileged(uid1)).thenReturn(true);
when(mPackageManagerInternal.isUidPrivileged(uid2)).thenReturn(false);
when(mPackageManagerInternal.isUidPrivileged(uid3)).thenReturn(false);
when(mPackageManagerInternal.isUidPrivileged(uid4)).thenReturn(false);
when(mPackageManagerInternal.isPlatformSigned(package1)).thenReturn(false);
when(mPackageManagerInternal.isPlatformSigned(package2)).thenReturn(true);
when(mPackageManagerInternal.isPlatformSigned(package3)).thenReturn(false);
when(mPackageManagerInternal.isPlatformSigned(package4)).thenReturn(false);
when(mRoleManager.getRoleHolders(RoleManager.ROLE_SYSTEM_WELLBEING)).thenReturn(
Arrays.asList(package4));
mockChangeEnabled(SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, false);
mService.mConstants.EXACT_ALARM_DENY_LIST = new ArraySet<>(new String[]{
package1,
package3,
});
// Deny listed packages will be false.
assertFalse(mService.isScheduleExactAlarmAllowedByDefault(package1, uid1));
assertTrue(mService.isScheduleExactAlarmAllowedByDefault(package2, uid2));
assertFalse(mService.isScheduleExactAlarmAllowedByDefault(package3, uid3));
assertTrue(mService.isScheduleExactAlarmAllowedByDefault(package4, uid4));
mockChangeEnabled(SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, true);
mService.mConstants.EXACT_ALARM_DENY_LIST = new ArraySet<>(new String[]{
package1,
package3,
});
// Deny list doesn't matter now, only exemptions should be true.
assertTrue(mService.isScheduleExactAlarmAllowedByDefault(package1, uid1));
assertTrue(mService.isScheduleExactAlarmAllowedByDefault(package2, uid2));
assertFalse(mService.isScheduleExactAlarmAllowedByDefault(package3, uid3));
assertTrue(mService.isScheduleExactAlarmAllowedByDefault(package4, uid4));
}
@Test
public void alarmScheduledAtomPushed() {
for (int i = 0; i < 10; i++) {
@@ -3510,7 +3515,7 @@ public final class AlarmManagerServiceTest {
}
@Test
public void hasUseExactAlarmPermission() {
public void hasUseExactAlarmInternal() {
mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, true);
mockUseExactAlarmState(true);
@@ -3521,7 +3526,7 @@ public final class AlarmManagerServiceTest {
}
@Test
public void hasUseExactAlarmPermissionChangeDisabled() {
public void hasUseExactAlarmInternalChangeDisabled() {
mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, false);
mockUseExactAlarmState(true);
@@ -3531,6 +3536,49 @@ public final class AlarmManagerServiceTest {
assertFalse(mService.hasUseExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID));
}
@Test
public void hasScheduleExactAlarmInternal() {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockChangeEnabled(AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, true);
mockScheduleExactAlarmState(false);
assertFalse(mService.hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID));
mockScheduleExactAlarmState(true);
assertTrue(mService.hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID));
}
@Test
public void hasScheduleExactAlarmInternalPreT() {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockChangeEnabled(AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, false);
mockScheduleExactAlarmStatePreT(true, true, MODE_DEFAULT);
assertFalse(mService.hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID));
mockScheduleExactAlarmStatePreT(false, false, MODE_ALLOWED);
assertFalse(mService.hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID));
mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED);
assertFalse(mService.hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID));
mockScheduleExactAlarmStatePreT(true, false, MODE_ALLOWED);
assertTrue(mService.hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID));
}
@Test
public void hasScheduleExactAlarmInternalPreS() {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, false);
mockScheduleExactAlarmState(true);
mockScheduleExactAlarmStatePreT(true, false, MODE_ALLOWED);
assertFalse(mService.hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID));
mockScheduleExactAlarmState(false);
mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED);
assertFalse(mService.hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID));
}
@Test
public void temporaryQuotaReserve_hasQuota() {
final int quotaToFill = 5;