Merge changes from topics "presubmit-am-cd22d6400493475a97208d8e6980896b", "presubmit-am-d70f1b45fe9f4623abc8ce60634bd0c9" into tm-dev
* changes: Add exemptions for the apps with the camera/mic permissions granted Add bg exemption tracks for foreground only permissions
This commit is contained in:
@@ -17,6 +17,14 @@
|
||||
package com.android.server.am;
|
||||
|
||||
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
|
||||
import static android.Manifest.permission.CAMERA;
|
||||
import static android.Manifest.permission.RECORD_AUDIO;
|
||||
import static android.app.AppOpsManager.OPSTR_CAMERA;
|
||||
import static android.app.AppOpsManager.OPSTR_FINE_LOCATION;
|
||||
import static android.app.AppOpsManager.OPSTR_RECORD_AUDIO;
|
||||
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 +35,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 +78,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 +108,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 +135,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 +181,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 +262,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 +409,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 +451,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 +513,25 @@ 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,
|
||||
CAMERA, OPSTR_CAMERA,
|
||||
RECORD_AUDIO, OPSTR_RECORD_AUDIO,
|
||||
};
|
||||
|
||||
/**
|
||||
* @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 +552,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 +600,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(']');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,10 +33,12 @@ 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 android.util.proto.ProtoOutputStream;
|
||||
|
||||
import com.android.internal.app.IAppOpsService;
|
||||
import com.android.server.DeviceIdleInternal;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.notification.NotificationManagerInternal;
|
||||
@@ -270,6 +272,7 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
|
||||
MediaSessionManager mMediaSessionManager;
|
||||
RoleManager mRoleManager;
|
||||
NotificationManagerInternal mNotificationManagerInternal;
|
||||
IAppOpsService mIAppOpsService;
|
||||
|
||||
void setPolicy(T policy) {
|
||||
mAppStatePolicy = policy;
|
||||
@@ -292,6 +295,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();
|
||||
}
|
||||
@@ -362,5 +367,9 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
|
||||
NotificationManagerInternal getNotificationManagerInternal() {
|
||||
return mNotificationManagerInternal;
|
||||
}
|
||||
|
||||
IAppOpsService getIAppOpsService() {
|
||||
return mIAppOpsService;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
|
||||
Reference in New Issue
Block a user