summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/am/AppPermissionTracker.java356
-rw-r--r--services/core/java/com/android/server/am/BaseAppStateTracker.java9
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java7
3 files changed, 329 insertions, 43 deletions
diff --git a/services/core/java/com/android/server/am/AppPermissionTracker.java b/services/core/java/com/android/server/am/AppPermissionTracker.java
index 69f70ca0d0e0..8f4cb02af885 100644
--- a/services/core/java/com/android/server/am/AppPermissionTracker.java
+++ b/services/core/java/com/android/server/am/AppPermissionTracker.java
@@ -17,6 +17,10 @@
package com.android.server.am;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.app.AppOpsManager.OPSTR_FINE_LOCATION;
+import static android.app.AppOpsManager.OP_NONE;
+import static android.app.AppOpsManager.opToPublicName;
+import static android.app.AppOpsManager.strOpToOp;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.SYSTEM_UID;
@@ -27,28 +31,37 @@ import static com.android.server.am.AppRestrictionController.DEVICE_CONFIG_SUBNA
import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_PERMISSION;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.OnPermissionsChangedListener;
import android.content.pm.PackageManagerInternal;
import android.os.Handler;
import android.os.Message;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.permission.PermissionManager;
import android.provider.DeviceConfig;
+import android.text.TextUtils;
import android.util.ArraySet;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.IAppOpsCallback;
+import com.android.internal.app.IAppOpsService;
import com.android.server.am.AppPermissionTracker.AppPermissionPolicy;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import java.io.PrintWriter;
import java.lang.reflect.Constructor;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
/**
* The tracker for monitoring selected permission state of apps.
@@ -61,8 +74,17 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
private final MyHandler mHandler;
+ /**
+ * Keep a new instance of callback for each appop we're monitoring,
+ * as the AppOpsService doesn't support monitoring multiple appops with single callback
+ * instance (except the ALL_OPS case).
+ */
+ @GuardedBy("mAppOpsCallbacks")
+ private final SparseArray<MyAppOpsCallback> mAppOpsCallbacks = new SparseArray<>();
+
@GuardedBy("mLock")
- private SparseArray<ArraySet<String>> mUidGrantedPermissionsInMonitor = new SparseArray<>();
+ private SparseArray<ArraySet<UidGrantedPermissionState>> mUidGrantedPermissionsInMonitor =
+ new SparseArray<>();
private volatile boolean mLockedBootCompleted = false;
@@ -82,12 +104,25 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
mHandler.obtainMessage(MyHandler.MSG_PERMISSIONS_CHANGED, uid, 0).sendToTarget();
}
+ private void handleAppOpsInit() {
+ final ArrayList<Integer> ops = new ArrayList<>();
+ final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+ for (int i = 0; i < permissions.length; i++) {
+ final Pair<String, Integer> pair = permissions[i];
+ if (pair.second != OP_NONE) {
+ ops.add(pair.second);
+ }
+ }
+ startWatchingMode(ops.toArray(new Integer[ops.size()]));
+ }
+
private void handlePermissionsInit() {
final int[] allUsers = mInjector.getUserManagerInternal().getUserIds();
final PackageManagerInternal pmi = mInjector.getPackageManagerInternal();
final PermissionManagerServiceInternal pm = mInjector.getPermissionManagerServiceInternal();
- final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
- final SparseArray<ArraySet<String>> uidPerms = mUidGrantedPermissionsInMonitor;
+ final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+ final SparseArray<ArraySet<UidGrantedPermissionState>> uidPerms =
+ mUidGrantedPermissionsInMonitor;
for (int userId : allUsers) {
final List<ApplicationInfo> apps = pmi.getInstalledApplications(0, userId, SYSTEM_UID);
if (apps == null) {
@@ -96,33 +131,44 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
final long now = SystemClock.elapsedRealtime();
for (int i = 0, size = apps.size(); i < size; i++) {
final ApplicationInfo ai = apps.get(i);
- for (String permission : permissions) {
- if (pm.checkUidPermission(ai.uid, permission) != PERMISSION_GRANTED) {
+ for (Pair<String, Integer> permission : permissions) {
+ final UidGrantedPermissionState state = new UidGrantedPermissionState(
+ ai.uid, permission.first, permission.second);
+ if (!state.isGranted()) {
+ // No need to track it.
continue;
}
synchronized (mLock) {
- ArraySet<String> grantedPermissions = uidPerms.get(ai.uid);
+ ArraySet<UidGrantedPermissionState> grantedPermissions =
+ uidPerms.get(ai.uid);
if (grantedPermissions == null) {
- grantedPermissions = new ArraySet<String>();
+ grantedPermissions = new ArraySet<UidGrantedPermissionState>();
uidPerms.put(ai.uid, grantedPermissions);
+ // This UID has at least one active permission-in-interest now,
+ // let the listeners know.
+ notifyListenersOnStateChange(ai.uid, DEFAULT_NAME, true, now,
+ STATE_TYPE_PERMISSION);
}
- grantedPermissions.add(permission);
- notifyListenersOnStateChange(ai.uid, DEFAULT_NAME, true, now,
- STATE_TYPE_PERMISSION);
+ grantedPermissions.add(state);
}
}
}
}
}
+ private void handleAppOpsDestroy() {
+ stopWatchingMode();
+ }
+
private void handlePermissionsDestroy() {
synchronized (mLock) {
- final SparseArray<ArraySet<String>> uidPerms = mUidGrantedPermissionsInMonitor;
+ final SparseArray<ArraySet<UidGrantedPermissionState>> uidPerms =
+ mUidGrantedPermissionsInMonitor;
final long now = SystemClock.elapsedRealtime();
for (int i = 0, size = uidPerms.size(); i < size; i++) {
final int uid = uidPerms.keyAt(i);
- final ArraySet<String> grantedPermissions = uidPerms.valueAt(i);
- for (int j = 0, numOfPerms = grantedPermissions.size(); j < numOfPerms; j++) {
+ final ArraySet<UidGrantedPermissionState> grantedPermissions = uidPerms.valueAt(i);
+ if (grantedPermissions.size() > 0) {
notifyListenersOnStateChange(uid, DEFAULT_NAME, false, now,
STATE_TYPE_PERMISSION);
}
@@ -131,44 +177,78 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
}
}
+ private void handleOpChanged(int op, int uid, String packageName) {
+ if (DEBUG_PERMISSION_TRACKER) {
+ final IAppOpsService appOpsService = mInjector.getIAppOpsService();
+ try {
+ final int mode = appOpsService.checkOperation(op, uid, packageName);
+ Slog.i(TAG, "onOpChanged: " + opToPublicName(op)
+ + " " + UserHandle.formatUid(uid)
+ + " " + packageName + " " + mode);
+ } catch (RemoteException e) {
+ // Intra-process call, should never happen.
+ }
+ }
+ final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+ if (permissions != null && permissions.length > 0) {
+ for (int i = 0; i < permissions.length; i++) {
+ final Pair<String, Integer> pair = permissions[i];
+ if (pair.second != op) {
+ continue;
+ }
+ final UidGrantedPermissionState state =
+ new UidGrantedPermissionState(uid, pair.first, op);
+ synchronized (mLock) {
+ handlePermissionsChangedLocked(uid, new UidGrantedPermissionState[] {state});
+ }
+ break;
+ }
+ }
+ }
+
private void handlePermissionsChanged(int uid) {
- final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+ if (DEBUG_PERMISSION_TRACKER) {
+ Slog.i(TAG, "handlePermissionsChanged " + UserHandle.formatUid(uid));
+ }
+ final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
if (permissions != null && permissions.length > 0) {
final PermissionManagerServiceInternal pm =
mInjector.getPermissionManagerServiceInternal();
- final boolean[] states = new boolean[permissions.length];
+ final UidGrantedPermissionState[] states =
+ new UidGrantedPermissionState[permissions.length];
for (int i = 0; i < permissions.length; i++) {
- states[i] = pm.checkUidPermission(uid, permissions[i]) == PERMISSION_GRANTED;
+ final Pair<String, Integer> pair = permissions[i];
+ states[i] = new UidGrantedPermissionState(uid, pair.first, pair.second);
if (DEBUG_PERMISSION_TRACKER) {
- Slog.i(TAG, UserHandle.formatUid(uid) + " " + permissions[i] + "=" + states[i]);
+ Slog.i(TAG, states[i].toString());
}
}
synchronized (mLock) {
- handlePermissionsChangedLocked(uid, permissions, states);
+ handlePermissionsChangedLocked(uid, states);
}
}
}
@GuardedBy("mLock")
- private void handlePermissionsChangedLocked(int uid, String[] permissions, boolean[] states) {
+ private void handlePermissionsChangedLocked(int uid, UidGrantedPermissionState[] states) {
final int index = mUidGrantedPermissionsInMonitor.indexOfKey(uid);
- ArraySet<String> grantedPermissions = index >= 0
+ ArraySet<UidGrantedPermissionState> grantedPermissions = index >= 0
? mUidGrantedPermissionsInMonitor.valueAt(index) : null;
final long now = SystemClock.elapsedRealtime();
- for (int i = 0; i < permissions.length; i++) {
- final String permission = permissions[i];
- final boolean granted = states[i];
+ for (int i = 0; i < states.length; i++) {
+ final boolean granted = states[i].isGranted();
boolean changed = false;
if (granted) {
if (grantedPermissions == null) {
grantedPermissions = new ArraySet<>();
mUidGrantedPermissionsInMonitor.put(uid, grantedPermissions);
+ changed = true;
}
- changed = grantedPermissions.add(permission);
- } else if (grantedPermissions != null) {
- changed = grantedPermissions.remove(permission);
- if (grantedPermissions.isEmpty()) {
+ grantedPermissions.add(states[i]);
+ } else if (grantedPermissions != null && !grantedPermissions.isEmpty()) {
+ if (grantedPermissions.remove(states[i]) && grantedPermissions.isEmpty()) {
mUidGrantedPermissionsInMonitor.removeAt(index);
+ changed = true;
}
}
if (changed) {
@@ -178,10 +258,141 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
}
}
+ /**
+ * Represents the grant state of a permission + appop of the given UID.
+ */
+ private class UidGrantedPermissionState {
+ final int mUid;
+ final @Nullable String mPermission;
+ final int mAppOp;
+
+ private boolean mPermissionGranted;
+ private boolean mAppOpAllowed;
+
+ UidGrantedPermissionState(int uid, @Nullable String permission, int appOp) {
+ mUid = uid;
+ mPermission = permission;
+ mAppOp = appOp;
+ updatePermissionState();
+ updateAppOps();
+ }
+
+ void updatePermissionState() {
+ if (TextUtils.isEmpty(mPermission)) {
+ mPermissionGranted = true;
+ return;
+ }
+ mPermissionGranted = mInjector.getPermissionManagerServiceInternal()
+ .checkUidPermission(mUid, mPermission) == PERMISSION_GRANTED;
+ }
+
+ void updateAppOps() {
+ if (mAppOp == OP_NONE) {
+ mAppOpAllowed = true;
+ return;
+ }
+ final String[] packages = mInjector.getPackageManager().getPackagesForUid(mUid);
+ if (packages != null) {
+ final IAppOpsService appOpsService = mInjector.getIAppOpsService();
+ for (String pkg : packages) {
+ try {
+ final int mode = appOpsService.checkOperation(mAppOp, mUid, pkg);
+ if (mode == AppOpsManager.MODE_ALLOWED) {
+ mAppOpAllowed = true;
+ return;
+ }
+ } catch (RemoteException e) {
+ // Intra-process call, should never happen.
+ }
+ }
+ }
+ mAppOpAllowed = false;
+ }
+
+ boolean isGranted() {
+ return mPermissionGranted && mAppOpAllowed;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == null || !(other instanceof UidGrantedPermissionState)) {
+ return false;
+ }
+ final UidGrantedPermissionState otherState = (UidGrantedPermissionState) other;
+ return mUid == otherState.mUid && mAppOp == otherState.mAppOp
+ && Objects.equals(mPermission, otherState.mPermission);
+ }
+
+ @Override
+ public int hashCode() {
+ return (Integer.hashCode(mUid) * 31 + Integer.hashCode(mAppOp)) * 31
+ + (mPermission == null ? 0 : mPermission.hashCode());
+ }
+
+ @Override
+ public String toString() {
+ String s = "UidGrantedPermissionState{"
+ + System.identityHashCode(this) + " "
+ + UserHandle.formatUid(mUid) + ": ";
+ final boolean emptyPermissionName = TextUtils.isEmpty(mPermission);
+ if (!emptyPermissionName) {
+ s += mPermission + "=" + mPermissionGranted;
+ }
+ if (mAppOp != OP_NONE) {
+ if (!emptyPermissionName) {
+ s += ",";
+ }
+ s += opToPublicName(mAppOp) + "=" + mAppOpAllowed;
+ }
+ s += "}";
+ return s;
+ }
+ }
+
+ private void startWatchingMode(@NonNull Integer[] ops) {
+ synchronized (mAppOpsCallbacks) {
+ stopWatchingMode();
+ final IAppOpsService appOpsService = mInjector.getIAppOpsService();
+ try {
+ for (int op: ops) {
+ final MyAppOpsCallback cb = new MyAppOpsCallback();
+ mAppOpsCallbacks.put(op, cb);
+ appOpsService.startWatchingModeWithFlags(op, null,
+ AppOpsManager.WATCH_FOREGROUND_CHANGES, cb);
+ }
+ } catch (RemoteException e) {
+ // Intra-process call, should never happen.
+ }
+ }
+ }
+
+ private void stopWatchingMode() {
+ synchronized (mAppOpsCallbacks) {
+ final IAppOpsService appOpsService = mInjector.getIAppOpsService();
+ for (int i = mAppOpsCallbacks.size() - 1; i >= 0; i--) {
+ try {
+ appOpsService.stopWatchingMode(mAppOpsCallbacks.valueAt(i));
+ } catch (RemoteException e) {
+ // Intra-process call, should never happen.
+ }
+ }
+ mAppOpsCallbacks.clear();
+ }
+ }
+
+ private class MyAppOpsCallback extends IAppOpsCallback.Stub {
+ @Override
+ public void opChanged(int op, int uid, String packageName) {
+ mHandler.obtainMessage(MyHandler.MSG_APPOPS_CHANGED, op, uid, packageName)
+ .sendToTarget();
+ }
+ }
+
private static class MyHandler extends Handler {
static final int MSG_PERMISSIONS_INIT = 0;
static final int MSG_PERMISSIONS_DESTROY = 1;
static final int MSG_PERMISSIONS_CHANGED = 2;
+ static final int MSG_APPOPS_CHANGED = 3;
private @NonNull AppPermissionTracker mTracker;
@@ -194,14 +405,19 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_PERMISSIONS_INIT:
+ mTracker.handleAppOpsInit();
mTracker.handlePermissionsInit();
break;
case MSG_PERMISSIONS_DESTROY:
mTracker.handlePermissionsDestroy();
+ mTracker.handleAppOpsDestroy();
break;
case MSG_PERMISSIONS_CHANGED:
mTracker.handlePermissionsChanged(msg.arg1);
break;
+ case MSG_APPOPS_CHANGED:
+ mTracker.handleOpChanged(msg.arg1, msg.arg2, (String) msg.obj);
+ break;
}
}
}
@@ -231,25 +447,41 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
void dump(PrintWriter pw, String prefix) {
pw.print(prefix);
pw.println("APP PERMISSIONS TRACKER:");
- final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+ final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
final String prefixMore = " " + prefix;
final String prefixMoreMore = " " + prefixMore;
- for (String permission : permissions) {
+ for (Pair<String, Integer> permission : permissions) {
pw.print(prefixMore);
- pw.print(permission);
+ final boolean emptyPermissionName = TextUtils.isEmpty(permission.first);
+ if (!emptyPermissionName) {
+ pw.print(permission.first);
+ }
+ if (permission.second != OP_NONE) {
+ if (!emptyPermissionName) {
+ pw.print('+');
+ }
+ pw.print(opToPublicName(permission.second));
+ }
pw.println(':');
synchronized (mLock) {
- final SparseArray<ArraySet<String>> uidPerms = mUidGrantedPermissionsInMonitor;
+ final SparseArray<ArraySet<UidGrantedPermissionState>> uidPerms =
+ mUidGrantedPermissionsInMonitor;
pw.print(prefixMoreMore);
pw.print('[');
boolean needDelimiter = false;
for (int i = 0, size = uidPerms.size(); i < size; i++) {
- if (uidPerms.valueAt(i).contains(permission)) {
- if (needDelimiter) {
- pw.print(',');
+ final ArraySet<UidGrantedPermissionState> uidPerm = uidPerms.valueAt(i);
+ for (int j = uidPerm.size() - 1; j >= 0; j--) {
+ final UidGrantedPermissionState state = uidPerm.valueAt(j);
+ if (state.mAppOp == permission.second
+ && TextUtils.equals(state.mPermission, permission.first)) {
+ if (needDelimiter) {
+ pw.print(',');
+ }
+ needDelimiter = true;
+ pw.print(UserHandle.formatUid(state.mUid));
+ break;
}
- needDelimiter = true;
- pw.print(UserHandle.formatUid(uidPerms.keyAt(i)));
}
}
pw.println(']');
@@ -277,20 +509,23 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
static final boolean DEFAULT_BG_PERMISSION_MONITOR_ENABLED = true;
/**
- * Default value to {@link #mBgPermissionsInMonitor}.
+ * Default value to {@link #mBgPermissionsInMonitor}, it comes in pair;
+ * the first string strings in the pair is the permission name, and the second string
+ * is the appops name, if they are associated.
*/
static final String[] DEFAULT_BG_PERMISSIONS_IN_MONITOR = new String[] {
- ACCESS_FINE_LOCATION,
+ ACCESS_FINE_LOCATION, OPSTR_FINE_LOCATION,
};
/**
* @see #KEY_BG_PERMISSIONS_IN_MONITOR.
*/
- volatile String[] mBgPermissionsInMonitor = DEFAULT_BG_PERMISSIONS_IN_MONITOR;
+ volatile @NonNull Pair[] mBgPermissionsInMonitor;
AppPermissionPolicy(@NonNull Injector injector, @NonNull AppPermissionTracker tracker) {
super(injector, tracker, KEY_BG_PERMISSION_MONITOR_ENABLED,
DEFAULT_BG_PERMISSION_MONITOR_ENABLED);
+ mBgPermissionsInMonitor = parsePermissionConfig(DEFAULT_BG_PERMISSIONS_IN_MONITOR);
}
@Override
@@ -311,17 +546,38 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
}
}
- String[] getBgPermissionsInMonitor() {
+ Pair[] getBgPermissionsInMonitor() {
return mBgPermissionsInMonitor;
}
+ private @NonNull Pair[] parsePermissionConfig(@NonNull String[] perms) {
+ final Pair[] result = new Pair[perms.length / 2];
+ for (int i = 0, j = 0; i < perms.length; i += 2, j++) {
+ try {
+ result[j] = Pair.create(TextUtils.isEmpty(perms[i]) ? null : perms[i],
+ TextUtils.isEmpty(perms[i + 1]) ? OP_NONE : strOpToOp(perms[i + 1]));
+ } catch (Exception e) {
+ // Ignore.
+ }
+ }
+ return result;
+ }
+
private void updateBgPermissionsInMonitor() {
final String config = DeviceConfig.getString(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
KEY_BG_PERMISSIONS_IN_MONITOR,
null);
- mBgPermissionsInMonitor = config != null
- ? config.split(",") : DEFAULT_BG_PERMISSIONS_IN_MONITOR;
+ final Pair[] newPermsInMonitor = parsePermissionConfig(
+ config != null ? config.split(",") : DEFAULT_BG_PERMISSIONS_IN_MONITOR);
+ if (!Arrays.equals(mBgPermissionsInMonitor, newPermsInMonitor)) {
+ mBgPermissionsInMonitor = newPermsInMonitor;
+ if (isEnabled()) {
+ // Trigger a reload.
+ onTrackerEnabled(false);
+ onTrackerEnabled(true);
+ }
+ }
}
@Override
@@ -338,7 +594,21 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
pw.print(prefix);
pw.print(KEY_BG_PERMISSIONS_IN_MONITOR);
pw.print('=');
- pw.println(Arrays.toString(mBgPermissionsInMonitor));
+ pw.print('[');
+ for (int i = 0; i < mBgPermissionsInMonitor.length; i++) {
+ if (i > 0) {
+ pw.print(',');
+ }
+ final Pair<String, Integer> pair = mBgPermissionsInMonitor[i];
+ if (pair.first != null) {
+ pw.print(pair.first);
+ }
+ pw.print(',');
+ if (pair.second != OP_NONE) {
+ pw.print(opToPublicName(pair.second));
+ }
+ }
+ pw.println(']');
}
}
}
diff --git a/services/core/java/com/android/server/am/BaseAppStateTracker.java b/services/core/java/com/android/server/am/BaseAppStateTracker.java
index 0fada53d622e..61c7149d0dcd 100644
--- a/services/core/java/com/android/server/am/BaseAppStateTracker.java
+++ b/services/core/java/com/android/server/am/BaseAppStateTracker.java
@@ -33,9 +33,11 @@ import android.media.session.MediaSessionManager;
import android.os.BatteryManagerInternal;
import android.os.BatteryStatsInternal;
import android.os.Handler;
+import android.os.ServiceManager;
import android.permission.PermissionManager;
import android.util.Slog;
+import com.android.internal.app.IAppOpsService;
import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
import com.android.server.notification.NotificationManagerInternal;
@@ -266,6 +268,7 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
MediaSessionManager mMediaSessionManager;
RoleManager mRoleManager;
NotificationManagerInternal mNotificationManagerInternal;
+ IAppOpsService mIAppOpsService;
void setPolicy(T policy) {
mAppStatePolicy = policy;
@@ -288,6 +291,8 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
mRoleManager = context.getSystemService(RoleManager.class);
mNotificationManagerInternal = LocalServices.getService(
NotificationManagerInternal.class);
+ mIAppOpsService = IAppOpsService.Stub.asInterface(
+ ServiceManager.getService(Context.APP_OPS_SERVICE));
getPolicy().onSystemReady();
}
@@ -358,5 +363,9 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
NotificationManagerInternal getNotificationManagerInternal() {
return mNotificationManagerInternal;
}
+
+ IAppOpsService getIAppOpsService() {
+ return mIAppOpsService;
+ }
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
index 053551309661..8bab6d68c20e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
@@ -119,6 +119,7 @@ import android.util.Pair;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.R;
+import com.android.internal.app.IAppOpsService;
import com.android.server.AppStateTracker;
import com.android.server.DeviceIdleInternal;
import com.android.server.am.AppBatteryExemptionTracker.AppBatteryExemptionPolicy;
@@ -231,6 +232,7 @@ public final class BackgroundRestrictionTest {
@Mock private MediaSessionManager mMediaSessionManager;
@Mock private RoleManager mRoleManager;
@Mock private TelephonyManager mTelephonyManager;
+ @Mock private IAppOpsService mIAppOpsService;
private long mCurrentTimeMillis;
@@ -2748,6 +2750,11 @@ public final class BackgroundRestrictionTest {
RoleManager getRoleManager() {
return BackgroundRestrictionTest.this.mRoleManager;
}
+
+ @Override
+ IAppOpsService getIAppOpsService() {
+ return BackgroundRestrictionTest.this.mIAppOpsService;
+ }
}
private class TestAppBatteryTrackerInjector extends TestBaseTrackerInjector<AppBatteryPolicy> {