Merge "Optimizing AppStandby.getIdleUidsForUser" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
fa29f6f85c
@@ -59,7 +59,7 @@ 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.net.Uri;
|
||||
import android.os.BatteryManager;
|
||||
@@ -123,6 +123,7 @@ import com.android.server.JobSchedulerBackgroundThread;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.SystemService;
|
||||
import com.android.server.SystemServiceManager;
|
||||
import com.android.server.pm.permission.PermissionManagerServiceInternal;
|
||||
import com.android.server.usage.AppStandbyInternal;
|
||||
import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
|
||||
|
||||
@@ -198,9 +199,13 @@ public class AlarmManagerService extends SystemService {
|
||||
private UsageStatsManagerInternal mUsageStatsManagerInternal;
|
||||
private ActivityManagerInternal mActivityManagerInternal;
|
||||
private PackageManagerInternal mPackageManagerInternal;
|
||||
private PermissionManagerServiceInternal mLocalPermissionManager;
|
||||
|
||||
final Object mLock = new Object();
|
||||
|
||||
/** Immutable set of app ids that have requested SCHEDULE_EXACT_ALARM permission.*/
|
||||
@VisibleForTesting
|
||||
volatile Set<Integer> mExactAlarmCandidates = Collections.emptySet();
|
||||
// List of alarms per uid deferred due to user applied background restrictions on the source app
|
||||
SparseArray<ArrayList<Alarm>> mPendingBackgroundAlarms = new SparseArray<>();
|
||||
private long mNextWakeup;
|
||||
@@ -1540,6 +1545,21 @@ public class AlarmManagerService extends SystemService {
|
||||
publishBinderService(Context.ALARM_SERVICE, mService);
|
||||
}
|
||||
|
||||
void refreshExactAlarmCandidates() {
|
||||
final String[] candidates = mLocalPermissionManager.getAppOpPermissionPackages(
|
||||
Manifest.permission.SCHEDULE_EXACT_ALARM);
|
||||
final Set<Integer> appIds = new ArraySet<>(candidates.length);
|
||||
for (final String candidate : candidates) {
|
||||
final int uid = mPackageManagerInternal.getPackageUid(candidate,
|
||||
PackageManager.MATCH_ANY_USER, USER_SYSTEM);
|
||||
if (uid > 0) {
|
||||
appIds.add(UserHandle.getAppId(uid));
|
||||
}
|
||||
}
|
||||
// No need to lock. Assignment is always atomic.
|
||||
mExactAlarmCandidates = Collections.unmodifiableSet(appIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBootPhase(int phase) {
|
||||
if (phase == PHASE_SYSTEM_SERVICES_READY) {
|
||||
@@ -1569,6 +1589,11 @@ public class AlarmManagerService extends SystemService {
|
||||
LocalServices.getService(DeviceIdleInternal.class);
|
||||
mUsageStatsManagerInternal =
|
||||
LocalServices.getService(UsageStatsManagerInternal.class);
|
||||
|
||||
mLocalPermissionManager = LocalServices.getService(
|
||||
PermissionManagerServiceInternal.class);
|
||||
refreshExactAlarmCandidates();
|
||||
|
||||
AppStandbyInternal appStandbyInternal =
|
||||
LocalServices.getService(AppStandbyInternal.class);
|
||||
appStandbyInternal.addListener(new AppStandbyTracker());
|
||||
@@ -2097,17 +2122,21 @@ public class AlarmManagerService extends SystemService {
|
||||
|
||||
boolean hasScheduleExactAlarmInternal(String packageName, int uid) {
|
||||
final long start = mStatLogger.getTime();
|
||||
// No locking needed as EXACT_ALARM_DENY_LIST is immutable.
|
||||
final boolean isOnDenyList = mConstants.EXACT_ALARM_DENY_LIST.contains(packageName);
|
||||
if (isOnDenyList && mAppOps.checkOpNoThrow(AppOpsManager.OP_SCHEDULE_EXACT_ALARM, uid,
|
||||
packageName) != AppOpsManager.MODE_ALLOWED) {
|
||||
return false;
|
||||
final boolean hasPermission;
|
||||
// No locking needed as all internal containers being queried are immutable.
|
||||
if (!mExactAlarmCandidates.contains(UserHandle.getAppId(uid))) {
|
||||
hasPermission = false;
|
||||
} else {
|
||||
final int mode = mAppOps.checkOpNoThrow(AppOpsManager.OP_SCHEDULE_EXACT_ALARM, uid,
|
||||
packageName);
|
||||
if (mode == AppOpsManager.MODE_DEFAULT) {
|
||||
hasPermission = !mConstants.EXACT_ALARM_DENY_LIST.contains(packageName);
|
||||
} else {
|
||||
hasPermission = (mode == AppOpsManager.MODE_ALLOWED);
|
||||
}
|
||||
}
|
||||
final boolean has = PermissionChecker.checkPermissionForPreflight(getContext(),
|
||||
Manifest.permission.SCHEDULE_EXACT_ALARM, -1, uid, packageName)
|
||||
== PermissionChecker.PERMISSION_GRANTED;
|
||||
mStatLogger.logDurationStat(Stats.HAS_SCHEDULE_EXACT_ALARM, start);
|
||||
return has;
|
||||
return hasPermission;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2489,6 +2518,9 @@ public class AlarmManagerService extends SystemService {
|
||||
pw.print("Num time change events: ");
|
||||
pw.println(mNumTimeChanged);
|
||||
|
||||
pw.println();
|
||||
pw.println("App ids requesting SCHEDULE_EXACT_ALARM: " + mExactAlarmCandidates);
|
||||
|
||||
pw.println();
|
||||
pw.println("Next alarm clock information: ");
|
||||
pw.increaseIndent();
|
||||
@@ -3924,6 +3956,7 @@ public class AlarmManagerService extends SystemService {
|
||||
public static final int REMOVE_FOR_CANCELED = 7;
|
||||
public static final int REMOVE_EXACT_ALARMS = 8;
|
||||
public static final int EXACT_ALARM_DENY_LIST_CHANGED = 9;
|
||||
public static final int REFRESH_EXACT_ALARM_CANDIDATES = 10;
|
||||
|
||||
AlarmHandler() {
|
||||
super(Looper.myLooper());
|
||||
@@ -4015,6 +4048,9 @@ public class AlarmManagerService extends SystemService {
|
||||
handlePackagesAddedToExactAlarmsDenyListLocked((ArraySet<String>) msg.obj);
|
||||
}
|
||||
break;
|
||||
case REFRESH_EXACT_ALARM_CANDIDATES:
|
||||
refreshExactAlarmCandidates();
|
||||
break;
|
||||
default:
|
||||
// nope, just ignore it
|
||||
break;
|
||||
@@ -4135,6 +4171,7 @@ public class AlarmManagerService extends SystemService {
|
||||
public UninstallReceiver() {
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
|
||||
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
|
||||
filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
|
||||
filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
|
||||
filter.addDataScheme(IntentFilter.SCHEME_PACKAGE);
|
||||
@@ -4179,8 +4216,11 @@ public class AlarmManagerService extends SystemService {
|
||||
case Intent.ACTION_PACKAGE_REMOVED:
|
||||
if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
|
||||
// This package is being updated; don't kill its alarms.
|
||||
// We will refresh the exact alarm candidates on subsequent receipt of
|
||||
// PACKAGE_ADDED.
|
||||
return;
|
||||
}
|
||||
mHandler.sendEmptyMessage(AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES);
|
||||
// Intentional fall-through.
|
||||
case Intent.ACTION_PACKAGE_RESTARTED:
|
||||
final Uri data = intent.getData();
|
||||
@@ -4191,6 +4231,9 @@ public class AlarmManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Intent.ACTION_PACKAGE_ADDED:
|
||||
mHandler.sendEmptyMessage(AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES);
|
||||
return;
|
||||
}
|
||||
if (pkgList != null && (pkgList.length > 0)) {
|
||||
for (String pkg : pkgList) {
|
||||
|
||||
@@ -58,7 +58,6 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.AppGlobals;
|
||||
import android.app.usage.AppStandbyInfo;
|
||||
import android.app.usage.UsageEvents;
|
||||
import android.app.usage.UsageStatsManager.StandbyBuckets;
|
||||
@@ -75,7 +74,6 @@ import android.content.pm.CrossProfileAppsInternal;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.database.ContentObserver;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.net.NetworkScoreManager;
|
||||
@@ -101,7 +99,7 @@ import android.util.ArraySet;
|
||||
import android.util.IndentingPrintWriter;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseIntArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.util.TimeUtils;
|
||||
import android.view.Display;
|
||||
import android.widget.Toast;
|
||||
@@ -118,6 +116,8 @@ import com.android.server.LocalServices;
|
||||
import com.android.server.pm.parsing.pkg.AndroidPackage;
|
||||
import com.android.server.usage.AppIdleHistory.AppUsageHistory;
|
||||
|
||||
import libcore.util.EmptyArray;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
@@ -1249,71 +1249,55 @@ public class AppStandbyController
|
||||
@Override
|
||||
public int[] getIdleUidsForUser(int userId) {
|
||||
if (!mAppIdleEnabled) {
|
||||
return new int[0];
|
||||
return EmptyArray.INT;
|
||||
}
|
||||
|
||||
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "getIdleUidsForUser");
|
||||
|
||||
final long elapsedRealtime = mInjector.elapsedRealtime();
|
||||
|
||||
List<ApplicationInfo> apps;
|
||||
try {
|
||||
ParceledListSlice<ApplicationInfo> slice = AppGlobals.getPackageManager()
|
||||
.getInstalledApplications(/* flags= */ 0, userId);
|
||||
if (slice == null) {
|
||||
return new int[0];
|
||||
}
|
||||
apps = slice.getList();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
final PackageManagerInternal pmi = mInjector.getPackageManagerInternal();
|
||||
final List<ApplicationInfo> apps = pmi.getInstalledApplications(0, userId, Process.myUid());
|
||||
if (apps == null) {
|
||||
return EmptyArray.INT;
|
||||
}
|
||||
|
||||
// State of each uid. Key is the uid. Value lower 16 bits is the number of apps
|
||||
// associated with that uid, upper 16 bits is the number of those apps that is idle.
|
||||
SparseIntArray uidStates = new SparseIntArray();
|
||||
|
||||
// Now resolve all app state. Iterating over all apps, keeping track of how many
|
||||
// we find for each uid and how many of those are idle.
|
||||
// State of each uid: Key is the uid, value is whether all the apps in that uid are idle.
|
||||
final SparseBooleanArray uidIdleStates = new SparseBooleanArray();
|
||||
int notIdleCount = 0;
|
||||
for (int i = apps.size() - 1; i >= 0; i--) {
|
||||
ApplicationInfo ai = apps.get(i);
|
||||
final ApplicationInfo ai = apps.get(i);
|
||||
final int index = uidIdleStates.indexOfKey(ai.uid);
|
||||
|
||||
// Check whether this app is idle.
|
||||
boolean idle = isAppIdleFiltered(ai.packageName, UserHandle.getAppId(ai.uid),
|
||||
userId, elapsedRealtime);
|
||||
final boolean currentIdle = (index < 0) ? true : uidIdleStates.valueAt(index);
|
||||
|
||||
int index = uidStates.indexOfKey(ai.uid);
|
||||
final boolean newIdle = currentIdle && isAppIdleFiltered(ai.packageName,
|
||||
UserHandle.getAppId(ai.uid), userId, elapsedRealtime);
|
||||
|
||||
if (currentIdle && !newIdle) {
|
||||
// This transition from true to false can happen at most once per uid in this loop.
|
||||
notIdleCount++;
|
||||
}
|
||||
if (index < 0) {
|
||||
uidStates.put(ai.uid, 1 + (idle ? 1<<16 : 0));
|
||||
uidIdleStates.put(ai.uid, newIdle);
|
||||
} else {
|
||||
int value = uidStates.valueAt(index);
|
||||
uidStates.setValueAt(index, value + 1 + (idle ? 1<<16 : 0));
|
||||
uidIdleStates.setValueAt(index, newIdle);
|
||||
}
|
||||
}
|
||||
|
||||
int numIdleUids = uidIdleStates.size() - notIdleCount;
|
||||
final int[] idleUids = new int[numIdleUids];
|
||||
for (int i = uidIdleStates.size() - 1; i >= 0; i--) {
|
||||
if (uidIdleStates.valueAt(i)) {
|
||||
idleUids[--numIdleUids] = uidIdleStates.keyAt(i);
|
||||
}
|
||||
}
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "getIdleUids took " + (mInjector.elapsedRealtime() - elapsedRealtime));
|
||||
}
|
||||
int numIdle = 0;
|
||||
for (int i = uidStates.size() - 1; i >= 0; i--) {
|
||||
int value = uidStates.valueAt(i);
|
||||
if ((value&0x7fff) == (value>>16)) {
|
||||
numIdle++;
|
||||
}
|
||||
}
|
||||
|
||||
int[] res = new int[numIdle];
|
||||
numIdle = 0;
|
||||
for (int i = uidStates.size() - 1; i >= 0; i--) {
|
||||
int value = uidStates.valueAt(i);
|
||||
if ((value&0x7fff) == (value>>16)) {
|
||||
res[numIdle] = uidStates.keyAt(i);
|
||||
numIdle++;
|
||||
}
|
||||
}
|
||||
|
||||
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
|
||||
|
||||
return res;
|
||||
return idleUids;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.android.server.alarm;
|
||||
|
||||
import static android.Manifest.permission.SCHEDULE_EXACT_ALARM;
|
||||
import static android.app.AlarmManager.ELAPSED_REALTIME;
|
||||
import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
|
||||
import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE;
|
||||
@@ -54,6 +55,7 @@ import static com.android.server.alarm.AlarmManagerService.ACTIVE_INDEX;
|
||||
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.APP_STANDBY_BUCKET_CHANGED;
|
||||
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.CHARGING_STATUS_CHANGED;
|
||||
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.EXACT_ALARM_DENY_LIST_CHANGED;
|
||||
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES;
|
||||
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_EXACT_ALARMS;
|
||||
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_FOR_CANCELED;
|
||||
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_COMPAT_QUOTA;
|
||||
@@ -99,7 +101,6 @@ import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManagerInternal;
|
||||
import android.app.AlarmManager;
|
||||
@@ -114,7 +115,6 @@ import android.app.compat.CompatChanges;
|
||||
import android.app.usage.UsageStatsManagerInternal;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.PermissionChecker;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.Bundle;
|
||||
@@ -139,14 +139,18 @@ import com.android.dx.mockito.inline.extended.MockedVoidMethod;
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.app.IAppOpsCallback;
|
||||
import com.android.internal.app.IAppOpsService;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.server.AlarmManagerInternal;
|
||||
import com.android.server.AppStateTracker;
|
||||
import com.android.server.AppStateTrackerImpl;
|
||||
import com.android.server.DeviceIdleInternal;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.SystemService;
|
||||
import com.android.server.pm.permission.PermissionManagerServiceInternal;
|
||||
import com.android.server.usage.AppStandbyInternal;
|
||||
|
||||
import libcore.util.EmptyArray;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -160,6 +164,7 @@ import org.mockito.quality.Strictness;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
@@ -176,6 +181,7 @@ public class AlarmManagerServiceTest {
|
||||
private long mAllowWhileIdleWindow;
|
||||
private AlarmManagerService mService;
|
||||
private AppStandbyInternal.AppIdleStateChangeListener mAppStandbyListener;
|
||||
private AlarmManagerService.UninstallReceiver mPackageChangesReceiver;
|
||||
private AlarmManagerService.ChargingReceiver mChargingReceiver;
|
||||
private IAppOpsCallback mIAppOpsCallback;
|
||||
private IAlarmManager mBinder;
|
||||
@@ -190,6 +196,8 @@ public class AlarmManagerServiceTest {
|
||||
@Mock
|
||||
private DeviceIdleInternal mDeviceIdleInternal;
|
||||
@Mock
|
||||
private PermissionManagerServiceInternal mPermissionManagerInternal;
|
||||
@Mock
|
||||
private UsageStatsManagerInternal mUsageStatsManagerInternal;
|
||||
@Mock
|
||||
private AppStandbyInternal mAppStandbyInternal;
|
||||
@@ -351,7 +359,6 @@ public class AlarmManagerServiceTest {
|
||||
.spyStatic(DeviceConfig.class)
|
||||
.mockStatic(LocalServices.class)
|
||||
.spyStatic(Looper.class)
|
||||
.mockStatic(PermissionChecker.class)
|
||||
.mockStatic(Settings.Global.class)
|
||||
.mockStatic(ServiceManager.class)
|
||||
.spyStatic(UserHandle.class)
|
||||
@@ -361,6 +368,8 @@ public class AlarmManagerServiceTest {
|
||||
doReturn(mIActivityManager).when(ActivityManager::getService);
|
||||
doReturn(mDeviceIdleInternal).when(
|
||||
() -> LocalServices.getService(DeviceIdleInternal.class));
|
||||
doReturn(mPermissionManagerInternal).when(
|
||||
() -> LocalServices.getService(PermissionManagerServiceInternal.class));
|
||||
doReturn(mActivityManagerInternal).when(
|
||||
() -> LocalServices.getService(ActivityManagerInternal.class));
|
||||
doReturn(mPackageManagerInternal).when(
|
||||
@@ -399,8 +408,10 @@ public class AlarmManagerServiceTest {
|
||||
|
||||
when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);
|
||||
|
||||
when(mPackageManagerInternal.getPackageUid(eq(TEST_CALLING_PACKAGE), anyInt(),
|
||||
eq(TEST_CALLING_USER))).thenReturn(TEST_CALLING_UID);
|
||||
registerAppIds(new String[]{TEST_CALLING_PACKAGE},
|
||||
new Integer[]{UserHandle.getAppId(TEST_CALLING_UID)});
|
||||
when(mPermissionManagerInternal.getAppOpPermissionPackages(
|
||||
SCHEDULE_EXACT_ALARM)).thenReturn(EmptyArray.STRING);
|
||||
|
||||
mInjector = new Injector(mMockContext);
|
||||
mService = new AlarmManagerService(mMockContext, mInjector);
|
||||
@@ -424,13 +435,22 @@ public class AlarmManagerServiceTest {
|
||||
verify(mAppStandbyInternal).addListener(captor.capture());
|
||||
mAppStandbyListener = captor.getValue();
|
||||
|
||||
ArgumentCaptor<AlarmManagerService.ChargingReceiver> chargingReceiverCaptor =
|
||||
final ArgumentCaptor<AlarmManagerService.ChargingReceiver> chargingReceiverCaptor =
|
||||
ArgumentCaptor.forClass(AlarmManagerService.ChargingReceiver.class);
|
||||
verify(mMockContext).registerReceiver(chargingReceiverCaptor.capture(),
|
||||
argThat((filter) -> filter.hasAction(BatteryManager.ACTION_CHARGING)
|
||||
&& filter.hasAction(BatteryManager.ACTION_DISCHARGING)));
|
||||
mChargingReceiver = chargingReceiverCaptor.getValue();
|
||||
|
||||
final ArgumentCaptor<AlarmManagerService.UninstallReceiver> packageReceiverCaptor =
|
||||
ArgumentCaptor.forClass(AlarmManagerService.UninstallReceiver.class);
|
||||
verify(mMockContext).registerReceiver(packageReceiverCaptor.capture(),
|
||||
argThat((filter) -> filter.hasAction(Intent.ACTION_PACKAGE_ADDED)
|
||||
&& filter.hasAction(Intent.ACTION_PACKAGE_REMOVED)));
|
||||
mPackageChangesReceiver = packageReceiverCaptor.getValue();
|
||||
|
||||
assertEquals(mService.mExactAlarmCandidates, Collections.emptySet());
|
||||
|
||||
ArgumentCaptor<IBinder> binderCaptor = ArgumentCaptor.forClass(IBinder.class);
|
||||
verify(() -> ServiceManager.addService(eq(Context.ALARM_SERVICE), binderCaptor.capture(),
|
||||
anyBoolean(), anyInt()));
|
||||
@@ -927,7 +947,8 @@ public class AlarmManagerServiceTest {
|
||||
|
||||
private void assertAndHandleMessageSync(int what) {
|
||||
final ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
|
||||
verify(mService.mHandler, atLeastOnce()).sendMessage(messageCaptor.capture());
|
||||
verify(mService.mHandler, atLeastOnce()).sendMessageAtTime(messageCaptor.capture(),
|
||||
anyLong());
|
||||
final Message lastMessage = messageCaptor.getValue();
|
||||
assertEquals("Unexpected message send to handler", lastMessage.what,
|
||||
what);
|
||||
@@ -1795,70 +1816,45 @@ public class AlarmManagerServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasScheduleExactAlarmBinderCallEmptyDenyList() throws RemoteException {
|
||||
doReturn(PermissionChecker.PERMISSION_GRANTED).when(
|
||||
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||
public void hasScheduleExactAlarmBinderCallNotDenyListed() throws RemoteException {
|
||||
mockExactAlarmPermissionGrant(true, false, MODE_DEFAULT);
|
||||
assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
|
||||
|
||||
doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
|
||||
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||
mockExactAlarmPermissionGrant(true, false, MODE_ALLOWED);
|
||||
assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
|
||||
|
||||
mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
|
||||
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
|
||||
|
||||
mockExactAlarmPermissionGrant(true, false, MODE_IGNORED);
|
||||
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasScheduleExactAlarmBinderCallWithDenyList() throws RemoteException {
|
||||
setDeviceConfigString(KEY_EXACT_ALARM_DENY_LIST, TEST_CALLING_PACKAGE);
|
||||
|
||||
when(mAppOpsManager.checkOpNoThrow(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID,
|
||||
TEST_CALLING_PACKAGE)).thenReturn(MODE_ERRORED);
|
||||
|
||||
public void hasScheduleExactAlarmBinderCallDenyListed() throws RemoteException {
|
||||
mockExactAlarmPermissionGrant(true, true, MODE_ERRORED);
|
||||
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
|
||||
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)), never());
|
||||
|
||||
when(mAppOpsManager.checkOpNoThrow(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID,
|
||||
TEST_CALLING_PACKAGE)).thenReturn(MODE_DEFAULT);
|
||||
|
||||
mockExactAlarmPermissionGrant(true, true, MODE_DEFAULT);
|
||||
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
|
||||
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)), never());
|
||||
|
||||
when(mAppOpsManager.checkOpNoThrow(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID,
|
||||
TEST_CALLING_PACKAGE)).thenReturn(MODE_IGNORED);
|
||||
|
||||
mockExactAlarmPermissionGrant(true, true, MODE_IGNORED);
|
||||
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
|
||||
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)), never());
|
||||
|
||||
when(mAppOpsManager.checkOpNoThrow(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID,
|
||||
TEST_CALLING_PACKAGE)).thenReturn(MODE_ALLOWED);
|
||||
|
||||
doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
|
||||
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||
|
||||
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
|
||||
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||
|
||||
doReturn(PermissionChecker.PERMISSION_GRANTED).when(
|
||||
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||
|
||||
mockExactAlarmPermissionGrant(true, true, MODE_ALLOWED);
|
||||
assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
|
||||
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)), times(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasScheduleExactAlarmBinderCallNotDeclared() throws RemoteException {
|
||||
mockExactAlarmPermissionGrant(false, false, MODE_DEFAULT);
|
||||
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
|
||||
|
||||
mockExactAlarmPermissionGrant(false, false, MODE_ALLOWED);
|
||||
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
|
||||
|
||||
mockExactAlarmPermissionGrant(false, true, MODE_ALLOWED);
|
||||
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1884,9 +1880,8 @@ public class AlarmManagerServiceTest {
|
||||
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_HEURISTIC, 0,
|
||||
FLAG_ALLOW_WHILE_IDLE, getNewMockPendingIntent(), null, null, null, null);
|
||||
|
||||
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)), never());
|
||||
verify(mService, never()).hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE,
|
||||
TEST_CALLING_UID);
|
||||
verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt());
|
||||
}
|
||||
|
||||
@@ -1969,10 +1964,7 @@ public class AlarmManagerServiceTest {
|
||||
() -> CompatChanges.isChangeEnabled(eq(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION),
|
||||
anyString(), any(UserHandle.class)));
|
||||
|
||||
doReturn(PermissionChecker.PERMISSION_GRANTED).when(
|
||||
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||
mockExactAlarmPermissionGrant(true, false, MODE_ALLOWED);
|
||||
|
||||
final PendingIntent alarmPi = getNewMockPendingIntent();
|
||||
final AlarmManager.AlarmClockInfo alarmClock = mock(AlarmManager.AlarmClockInfo.class);
|
||||
@@ -1980,9 +1972,7 @@ public class AlarmManagerServiceTest {
|
||||
alarmPi, null, null, null, alarmClock);
|
||||
|
||||
// Correct permission checks are invoked.
|
||||
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||
verify(mService).hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID);
|
||||
verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt());
|
||||
|
||||
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
|
||||
@@ -1996,6 +1986,22 @@ public class AlarmManagerServiceTest {
|
||||
assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, type);
|
||||
}
|
||||
|
||||
private void mockExactAlarmPermissionGrant(boolean declared, boolean denyList, int mode) {
|
||||
String[] requesters = declared ? new String[]{TEST_CALLING_PACKAGE} : EmptyArray.STRING;
|
||||
when(mPermissionManagerInternal.getAppOpPermissionPackages(SCHEDULE_EXACT_ALARM))
|
||||
.thenReturn(requesters);
|
||||
mService.refreshExactAlarmCandidates();
|
||||
|
||||
if (denyList) {
|
||||
setDeviceConfigString(KEY_EXACT_ALARM_DENY_LIST, TEST_CALLING_PACKAGE);
|
||||
} else {
|
||||
setDeviceConfigString(KEY_EXACT_ALARM_DENY_LIST, "");
|
||||
}
|
||||
|
||||
when(mAppOpsManager.checkOpNoThrow(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID,
|
||||
TEST_CALLING_PACKAGE)).thenReturn(mode);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void alarmClockBinderCallWithoutPermission() throws RemoteException {
|
||||
setDeviceConfigBoolean(KEY_CRASH_NON_CLOCK_APPS, true);
|
||||
@@ -2003,10 +2009,7 @@ public class AlarmManagerServiceTest {
|
||||
() -> CompatChanges.isChangeEnabled(eq(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION),
|
||||
anyString(), any(UserHandle.class)));
|
||||
|
||||
doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
|
||||
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||
mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
|
||||
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true);
|
||||
|
||||
final PendingIntent alarmPi = getNewMockPendingIntent();
|
||||
@@ -2018,9 +2021,6 @@ public class AlarmManagerServiceTest {
|
||||
} catch (SecurityException se) {
|
||||
// Expected.
|
||||
}
|
||||
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||
verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt());
|
||||
}
|
||||
|
||||
@@ -2030,14 +2030,12 @@ public class AlarmManagerServiceTest {
|
||||
() -> CompatChanges.isChangeEnabled(eq(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION),
|
||||
anyString(), any(UserHandle.class)));
|
||||
|
||||
// Permission check is granted by default by the mock.
|
||||
mockExactAlarmPermissionGrant(true, false, MODE_ALLOWED);
|
||||
final PendingIntent alarmPi = getNewMockPendingIntent();
|
||||
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0,
|
||||
0, alarmPi, null, null, null, null);
|
||||
|
||||
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||
verify(mService).hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID);
|
||||
verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt());
|
||||
|
||||
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
|
||||
@@ -2057,19 +2055,13 @@ public class AlarmManagerServiceTest {
|
||||
() -> CompatChanges.isChangeEnabled(eq(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION),
|
||||
anyString(), any(UserHandle.class)));
|
||||
// If permission is denied, only then allowlist will be checked.
|
||||
doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
|
||||
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||
mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
|
||||
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true);
|
||||
|
||||
final PendingIntent alarmPi = getNewMockPendingIntent();
|
||||
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0,
|
||||
0, alarmPi, null, null, null, null);
|
||||
|
||||
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||
verify(mDeviceIdleInternal).isAppOnWhitelist(UserHandle.getAppId(TEST_CALLING_UID));
|
||||
|
||||
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
|
||||
@@ -2084,14 +2076,11 @@ public class AlarmManagerServiceTest {
|
||||
() -> CompatChanges.isChangeEnabled(eq(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION),
|
||||
anyString(), any(UserHandle.class)));
|
||||
|
||||
// Permission check is granted by default by the mock.
|
||||
mockExactAlarmPermissionGrant(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);
|
||||
|
||||
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||
verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt());
|
||||
|
||||
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
|
||||
@@ -2111,19 +2100,13 @@ public class AlarmManagerServiceTest {
|
||||
() -> CompatChanges.isChangeEnabled(eq(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION),
|
||||
anyString(), any(UserHandle.class)));
|
||||
// If permission is denied, only then allowlist will be checked.
|
||||
doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
|
||||
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||
mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
|
||||
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true);
|
||||
|
||||
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);
|
||||
|
||||
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||
verify(mDeviceIdleInternal).isAppOnWhitelist(UserHandle.getAppId(TEST_CALLING_UID));
|
||||
|
||||
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
|
||||
@@ -2145,10 +2128,7 @@ public class AlarmManagerServiceTest {
|
||||
() -> CompatChanges.isChangeEnabled(eq(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION),
|
||||
anyString(), any(UserHandle.class)));
|
||||
|
||||
doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
|
||||
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||
mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
|
||||
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(false);
|
||||
|
||||
final PendingIntent alarmPi = getNewMockPendingIntent();
|
||||
@@ -2166,9 +2146,6 @@ public class AlarmManagerServiceTest {
|
||||
} catch (SecurityException se) {
|
||||
// Expected.
|
||||
}
|
||||
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)), times(2));
|
||||
verify(mDeviceIdleInternal, times(2)).isAppOnWhitelist(anyInt());
|
||||
}
|
||||
|
||||
@@ -2184,9 +2161,7 @@ public class AlarmManagerServiceTest {
|
||||
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 4321, WINDOW_HEURISTIC, 0,
|
||||
FLAG_ALLOW_WHILE_IDLE, alarmPi, null, null, null, null);
|
||||
|
||||
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)), never());
|
||||
verify(mService, never()).hasScheduleExactAlarmInternal(anyString(), anyInt());
|
||||
verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt());
|
||||
|
||||
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
|
||||
@@ -2205,10 +2180,7 @@ public class AlarmManagerServiceTest {
|
||||
() -> CompatChanges.isChangeEnabled(eq(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION),
|
||||
anyString(), any(UserHandle.class)));
|
||||
|
||||
doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
|
||||
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||
mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
|
||||
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true);
|
||||
when(mAppStateTracker.isUidPowerSaveUserExempt(TEST_CALLING_UID)).thenReturn(true);
|
||||
|
||||
@@ -2355,10 +2327,7 @@ public class AlarmManagerServiceTest {
|
||||
|
||||
@Test
|
||||
public void opScheduleExactAlarmRevoked() throws Exception {
|
||||
doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
|
||||
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||
mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
|
||||
mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
|
||||
assertAndHandleMessageSync(REMOVE_EXACT_ALARMS);
|
||||
verify(mService).removeExactAlarmsOnPermissionRevokedLocked(TEST_CALLING_UID,
|
||||
@@ -2456,6 +2425,73 @@ public class AlarmManagerServiceTest {
|
||||
assertEquals(LazyAlarmStore.TAG, mService.mAlarmStore.getName());
|
||||
}
|
||||
|
||||
private void registerAppIds(String[] packages, Integer[] ids) {
|
||||
assertEquals(packages.length, ids.length);
|
||||
|
||||
when(mPackageManagerInternal.getPackageUid(anyString(), anyInt(), anyInt())).thenAnswer(
|
||||
invocation -> {
|
||||
final String pkg = invocation.getArgument(0);
|
||||
final int index = ArrayUtils.indexOf(packages, pkg);
|
||||
if (index < 0) {
|
||||
return index;
|
||||
}
|
||||
final int userId = invocation.getArgument(2);
|
||||
return UserHandle.getUid(userId, ids[index]);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshExactAlarmCandidatesOnPackageAdded() {
|
||||
final String[] exactAlarmRequesters = new String[]{"p11", "p2", "p9"};
|
||||
final Integer[] appIds = new Integer[]{11, 2, 9};
|
||||
registerAppIds(exactAlarmRequesters, appIds);
|
||||
|
||||
when(mPermissionManagerInternal.getAppOpPermissionPackages(
|
||||
SCHEDULE_EXACT_ALARM)).thenReturn(exactAlarmRequesters);
|
||||
|
||||
final Intent packageAdded = new Intent(Intent.ACTION_PACKAGE_ADDED)
|
||||
.setPackage(TEST_CALLING_PACKAGE);
|
||||
mPackageChangesReceiver.onReceive(mMockContext, packageAdded);
|
||||
|
||||
assertAndHandleMessageSync(REFRESH_EXACT_ALARM_CANDIDATES);
|
||||
assertEquals(new ArraySet<>(appIds), mService.mExactAlarmCandidates);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshExactAlarmCandidatesOnPackageReplaced() {
|
||||
final String[] exactAlarmRequesters = new String[]{"p15", "p21", "p3"};
|
||||
final Integer[] appIds = new Integer[]{15, 21, 3};
|
||||
registerAppIds(exactAlarmRequesters, appIds);
|
||||
|
||||
when(mPermissionManagerInternal.getAppOpPermissionPackages(
|
||||
SCHEDULE_EXACT_ALARM)).thenReturn(exactAlarmRequesters);
|
||||
|
||||
final Intent packageAdded = new Intent(Intent.ACTION_PACKAGE_ADDED)
|
||||
.setPackage(TEST_CALLING_PACKAGE)
|
||||
.putExtra(Intent.EXTRA_REPLACING, true);
|
||||
mPackageChangesReceiver.onReceive(mMockContext, packageAdded);
|
||||
|
||||
assertAndHandleMessageSync(REFRESH_EXACT_ALARM_CANDIDATES);
|
||||
assertEquals(new ArraySet<>(appIds), mService.mExactAlarmCandidates);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshExactAlarmCandidatesOnPackageRemoved() {
|
||||
final String[] exactAlarmRequesters = new String[]{"p99", "p1", "p19"};
|
||||
final Integer[] appIds = new Integer[]{99, 1, 19};
|
||||
registerAppIds(exactAlarmRequesters, appIds);
|
||||
|
||||
when(mPermissionManagerInternal.getAppOpPermissionPackages(
|
||||
SCHEDULE_EXACT_ALARM)).thenReturn(exactAlarmRequesters);
|
||||
|
||||
final Intent packageRemoved = new Intent(Intent.ACTION_PACKAGE_REMOVED)
|
||||
.setPackage(TEST_CALLING_PACKAGE);
|
||||
mPackageChangesReceiver.onReceive(mMockContext, packageRemoved);
|
||||
|
||||
assertAndHandleMessageSync(REFRESH_EXACT_ALARM_CANDIDATES);
|
||||
assertEquals(new ArraySet<>(appIds), mService.mExactAlarmCandidates);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (mMockingSession != null) {
|
||||
|
||||
@@ -59,11 +59,14 @@ import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
import static org.mockito.AdditionalMatchers.not;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.ActivityManager;
|
||||
@@ -77,6 +80,7 @@ import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
@@ -92,6 +96,7 @@ import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.SystemService;
|
||||
import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
|
||||
@@ -101,6 +106,8 @@ import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
@@ -194,6 +201,8 @@ public class AppStandbyControllerTests {
|
||||
}
|
||||
|
||||
static class MyInjector extends AppStandbyController.Injector {
|
||||
@Mock
|
||||
private PackageManagerInternal mPackageManagerInternal;
|
||||
long mElapsedRealtime;
|
||||
boolean mIsAppIdleEnabled = true;
|
||||
boolean mIsCharging;
|
||||
@@ -222,6 +231,7 @@ public class AppStandbyControllerTests {
|
||||
|
||||
MyInjector(Context context, Looper looper) {
|
||||
super(context, looper);
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -268,6 +278,11 @@ public class AppStandbyControllerTests {
|
||||
return mClockApps.contains(Pair.create(packageName, uid));
|
||||
}
|
||||
|
||||
@Override
|
||||
PackageManagerInternal getPackageManagerInternal() {
|
||||
return mPackageManagerInternal;
|
||||
}
|
||||
|
||||
@Override
|
||||
void updatePowerWhitelistCache() {
|
||||
}
|
||||
@@ -491,6 +506,37 @@ public class AppStandbyControllerTests {
|
||||
mInjector.mElapsedRealtime, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetIdleUidsForUser() {
|
||||
final AppStandbyController controllerUnderTest = spy(mController);
|
||||
|
||||
final int userIdForTest = 325;
|
||||
final int[] uids = new int[]{129, 23, 129, 129, 44, 23, 41, 751};
|
||||
final boolean[] idle = new boolean[]{true, true, false, true, false, true, false, true};
|
||||
// Based on uids[] and idle[], the only two uids that have all true's in idle[].
|
||||
final int[] expectedIdleUids = new int[]{23, 751};
|
||||
|
||||
final List<ApplicationInfo> installedApps = new ArrayList<>();
|
||||
for (int i = 0; i < uids.length; i++) {
|
||||
final ApplicationInfo ai = mock(ApplicationInfo.class);
|
||||
ai.uid = uids[i];
|
||||
ai.packageName = "example.package.name." + i;
|
||||
installedApps.add(ai);
|
||||
when(controllerUnderTest.isAppIdleFiltered(eq(ai.packageName),
|
||||
eq(UserHandle.getAppId(ai.uid)), eq(userIdForTest), anyLong()))
|
||||
.thenReturn(idle[i]);
|
||||
}
|
||||
when(mInjector.mPackageManagerInternal.getInstalledApplications(anyInt(), eq(userIdForTest),
|
||||
anyInt())).thenReturn(installedApps);
|
||||
final int[] returnedIdleUids = controllerUnderTest.getIdleUidsForUser(userIdForTest);
|
||||
|
||||
assertEquals(expectedIdleUids.length, returnedIdleUids.length);
|
||||
for (final int uid : expectedIdleUids) {
|
||||
assertTrue("Idle uid: " + uid + " not found in result: " + Arrays.toString(
|
||||
returnedIdleUids), ArrayUtils.contains(returnedIdleUids, uid));
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestParoleListener extends AppIdleStateChangeListener {
|
||||
private boolean mIsParoleOn = false;
|
||||
private CountDownLatch mLatch;
|
||||
|
||||
Reference in New Issue
Block a user