Loading core/java/android/app/AppOpsManager.java +8 −1 Original line number Diff line number Diff line Loading @@ -1267,8 +1267,15 @@ public class AppOpsManager { /** @hide */ public void setUserRestriction(int code, boolean restricted, IBinder token) { setUserRestriction(code, restricted, token, /*exceptionPackages*/null); } /** @hide */ public void setUserRestriction(int code, boolean restricted, IBinder token, String[] exceptionPackages) { try { mService.setUserRestriction(code, restricted, token, mContext.getUserId()); mService.setUserRestriction(code, restricted, token, mContext.getUserId(), exceptionPackages); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading core/java/com/android/internal/app/IAppOpsService.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -45,6 +45,6 @@ interface IAppOpsService { void setAudioRestriction(int code, int usage, int uid, int mode, in String[] exceptionPackages); void setUserRestrictions(in Bundle restrictions, IBinder token, int userHandle); void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle); void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle, in String[] exceptionPackages); void removeUser(int userHandle); } services/core/java/com/android/server/AppOpsService.java +139 −21 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; Loading Loading @@ -57,6 +58,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; import android.util.Log; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; Loading Loading @@ -107,8 +109,21 @@ public class AppOpsService extends IAppOpsService.Stub { private final SparseArray<UidState> mUidStates = new SparseArray<>(); /** These are app op restrictions imposed per user from various parties */ private final ArrayMap<IBinder, SparseArray<boolean[]>> mOpUserRestrictions = new ArrayMap<>(); /* * These are app op restrictions imposed per user from various parties. * * This is organized as follows: * * ArrayMap w/ mapping: * IBinder (for client imposing restriction) --> SparseArray w/ mapping: * User handle --> Pair containing: * - Array w/ index = AppOp code, value = restricted status boolean * - SparseArray w/ mapping: * AppOp code --> Set of packages that are not restricted for this code * */ private final ArrayMap<IBinder, SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>>> mOpUserRestrictions = new ArrayMap<>(); private static final class UidState { public final int uid; Loading Loading @@ -1267,11 +1282,35 @@ public class AppOpsService extends IAppOpsService.Stub { private boolean isOpRestricted(int uid, int code, String packageName) { int userHandle = UserHandle.getUserId(uid); final int restrictionSetCount = mOpUserRestrictions.size(); for (int i = 0; i < restrictionSetCount; i++) { SparseArray<boolean[]> perUserRestrictions = mOpUserRestrictions.valueAt(i); boolean[] opRestrictions = perUserRestrictions.get(userHandle); if (opRestrictions != null && opRestrictions[code]) { // For each client, check that the given op is not restricted, or that the given // package is exempt from the restriction. SparseArray<Pair<boolean[],SparseArray<ArraySet<String>>>> perUserRestrictions = mOpUserRestrictions.valueAt(i); Pair<boolean[],SparseArray<ArraySet<String>>> restrictions = perUserRestrictions.get(userHandle); if (restrictions == null) { continue; // No restrictions set by this client } boolean[] opRestrictions = restrictions.first; SparseArray<ArraySet<String>> opExceptions = restrictions.second; if (opRestrictions == null) { continue; // No restrictions set by this client } if (opRestrictions[code]) { if (opExceptions != null && opExceptions.get(code) != null && opExceptions.get(code).contains(packageName)) { continue; // AppOps code is restricted, but this package is exempt } if (AppOpsManager.opAllowSystemBypassRestriction(code)) { // If we are the system, bypass user restrictions for certain codes synchronized (this) { Ops ops = getOpsLocked(uid, packageName, true); if ((ops != null) && ops.isPrivileged) { Loading @@ -1279,6 +1318,7 @@ public class AppOpsService extends IAppOpsService.Stub { } } } return true; } } Loading Loading @@ -2069,7 +2109,8 @@ public class AppOpsService extends IAppOpsService.Stub { } @Override public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle) { public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle, String[] exceptionPackages) { if (Binder.getCallingPid() != Process.myPid()) { mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS, Binder.getCallingPid(), Binder.getCallingUid(), null); Loading @@ -2085,12 +2126,37 @@ public class AppOpsService extends IAppOpsService.Stub { } verifyIncomingOp(code); Preconditions.checkNotNull(token); setUserRestrictionNoCheck(code, restricted, token, userHandle); setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages); } private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token, int userHandle) { setUserRestrictionNoCheck(code, restricted, token, userHandle, /*exceptionPackages*/null); } private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token, int userHandle, String[] exceptionPackages) { final boolean[] opRestrictions = getOrCreateUserRestrictionsForToken(token, userHandle); if (restricted) { final SparseArray<ArraySet<String>> opExceptions = getUserPackageExemptionsForToken(token, userHandle); // If exceptionPackages is not null, update the exception packages for this AppOps code ArraySet<String> exceptions = opExceptions.get(code); if (exceptionPackages != null) { if (exceptions == null) { exceptions = new ArraySet<>(exceptionPackages.length); opExceptions.put(code, exceptions); } else { exceptions.clear(); } exceptions.addAll(Arrays.asList(exceptionPackages)); } } if (opRestrictions[code] == restricted) { return; } Loading Loading @@ -2132,7 +2198,8 @@ public class AppOpsService extends IAppOpsService.Stub { checkSystemUid("removeUser"); final int tokenCount = mOpUserRestrictions.size(); for (int i = tokenCount - 1; i >= 0; i--) { SparseArray<boolean[]> opRestrictions = mOpUserRestrictions.valueAt(i); SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>> opRestrictions = mOpUserRestrictions.valueAt(i); if (opRestrictions != null) { opRestrictions.remove(userHandle); if (opRestrictions.size() <= 0) { Loading @@ -2144,15 +2211,23 @@ public class AppOpsService extends IAppOpsService.Stub { private void pruneUserRestrictionsForToken(IBinder token, int userHandle) { SparseArray<boolean[]> perTokenRestrictions = mOpUserRestrictions.get(token); SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>> perTokenRestrictions = mOpUserRestrictions.get(token); if (perTokenRestrictions != null) { final boolean[] opRestrictions = perTokenRestrictions.get(userHandle); final Pair<boolean[], SparseArray<ArraySet<String>>> restrictions = perTokenRestrictions.get(userHandle); if (restrictions != null) { final boolean[] opRestrictions = restrictions.first; if (opRestrictions != null) { for (boolean restriction : opRestrictions) { if (restriction) { return; } } } // No restrictions set for this client perTokenRestrictions.remove(userHandle); if (perTokenRestrictions.size() <= 0) { mOpUserRestrictions.remove(token); Loading @@ -2161,18 +2236,61 @@ public class AppOpsService extends IAppOpsService.Stub { } } /** * Get or create the user restrictions array for a given client if it doesn't already exist. * * @param token the binder client creating the restriction. * @param userHandle the user handle to create a restriction for. * * @return the array of restriction states for each AppOps code. */ private boolean[] getOrCreateUserRestrictionsForToken(IBinder token, int userHandle) { SparseArray<boolean[]> perTokenRestrictions = mOpUserRestrictions.get(token); SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>> perTokenRestrictions = mOpUserRestrictions.get(token); if (perTokenRestrictions == null) { perTokenRestrictions = new SparseArray<>(); perTokenRestrictions = new SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>>(); mOpUserRestrictions.put(token, perTokenRestrictions); } boolean[] opRestrictions = perTokenRestrictions.get(userHandle); if (opRestrictions == null) { opRestrictions = new boolean[AppOpsManager._NUM_OP]; perTokenRestrictions.put(userHandle, opRestrictions); Pair<boolean[], SparseArray<ArraySet<String>>> restrictions = perTokenRestrictions.get(userHandle); if (restrictions == null) { restrictions = new Pair<boolean[], SparseArray<ArraySet<String>>>( new boolean[AppOpsManager._NUM_OP], new SparseArray<ArraySet<String>>()); perTokenRestrictions.put(userHandle, restrictions); } return opRestrictions; return restrictions.first; } /** * Get the per-package exemptions for each AppOps code for a given client and userHandle. * * @param token the binder client to get the exemptions for. * @param userHandle the user handle to get the exemptions for. * * @return a mapping from the AppOps code to a set of packages exempt for that code. */ private SparseArray<ArraySet<String>> getUserPackageExemptionsForToken(IBinder token, int userHandle) { SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>> perTokenRestrictions = mOpUserRestrictions.get(token); if (perTokenRestrictions == null) { return null; // Don't create user restrictions accidentally } Pair<boolean[], SparseArray<ArraySet<String>>> restrictions = perTokenRestrictions.get(userHandle); if (restrictions == null) { return null; // Don't create user restrictions accidentally } return restrictions.second; } private void checkSystemUid(String function) { Loading services/core/java/com/android/server/vr/VrManagerService.java +11 −7 Original line number Diff line number Diff line Loading @@ -201,13 +201,16 @@ public class VrManagerService extends SystemService implements EnabledComponentC } } private void updateOverlayStateLocked() { private void updateOverlayStateLocked(ComponentName exemptedComponent) { final long identity = Binder.clearCallingIdentity(); try { AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class); if (appOpsManager != null) { String[] exemptions = (exemptedComponent == null) ? new String[0] : new String[] { exemptedComponent.getPackageName() }; appOpsManager.setUserRestriction(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, mVrModeEnabled, mOverlayToken); mVrModeEnabled, mOverlayToken, exemptions); } } finally { Binder.restoreCallingIdentity(identity); Loading @@ -230,12 +233,12 @@ public class VrManagerService extends SystemService implements EnabledComponentC private boolean updateCurrentVrServiceLocked(boolean enabled, @NonNull ComponentName component, int userId) { // Always send mode change events. changeVrModeLocked(enabled); boolean validUserComponent = (mComponentObserver.isValid(component, userId) == EnabledComponentsObserver.NO_ERROR); // Always send mode change events. changeVrModeLocked(enabled, (enabled && validUserComponent) ? component : null); if (!enabled || !validUserComponent) { // Unbind whatever is running if (mCurrentVrService != null) { Loading Loading @@ -275,8 +278,9 @@ public class VrManagerService extends SystemService implements EnabledComponentC * Note: Must be called while holding {@code mLock}. * * @param enabled new state of the VR mode. * @param exemptedComponent a component to exempt from AppOps restrictions for overlays. */ private void changeVrModeLocked(boolean enabled) { private void changeVrModeLocked(boolean enabled, ComponentName exemptedComponent) { if (mVrModeEnabled != enabled) { mVrModeEnabled = enabled; Loading @@ -284,7 +288,7 @@ public class VrManagerService extends SystemService implements EnabledComponentC Slog.i(TAG, "VR mode " + ((mVrModeEnabled) ? "enabled" : "disabled")); setVrModeNative(mVrModeEnabled); updateOverlayStateLocked(); updateOverlayStateLocked(exemptedComponent); onVrModeChangedLocked(); } } Loading Loading
core/java/android/app/AppOpsManager.java +8 −1 Original line number Diff line number Diff line Loading @@ -1267,8 +1267,15 @@ public class AppOpsManager { /** @hide */ public void setUserRestriction(int code, boolean restricted, IBinder token) { setUserRestriction(code, restricted, token, /*exceptionPackages*/null); } /** @hide */ public void setUserRestriction(int code, boolean restricted, IBinder token, String[] exceptionPackages) { try { mService.setUserRestriction(code, restricted, token, mContext.getUserId()); mService.setUserRestriction(code, restricted, token, mContext.getUserId(), exceptionPackages); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading
core/java/com/android/internal/app/IAppOpsService.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -45,6 +45,6 @@ interface IAppOpsService { void setAudioRestriction(int code, int usage, int uid, int mode, in String[] exceptionPackages); void setUserRestrictions(in Bundle restrictions, IBinder token, int userHandle); void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle); void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle, in String[] exceptionPackages); void removeUser(int userHandle); }
services/core/java/com/android/server/AppOpsService.java +139 −21 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; Loading Loading @@ -57,6 +58,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; import android.util.Log; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; Loading Loading @@ -107,8 +109,21 @@ public class AppOpsService extends IAppOpsService.Stub { private final SparseArray<UidState> mUidStates = new SparseArray<>(); /** These are app op restrictions imposed per user from various parties */ private final ArrayMap<IBinder, SparseArray<boolean[]>> mOpUserRestrictions = new ArrayMap<>(); /* * These are app op restrictions imposed per user from various parties. * * This is organized as follows: * * ArrayMap w/ mapping: * IBinder (for client imposing restriction) --> SparseArray w/ mapping: * User handle --> Pair containing: * - Array w/ index = AppOp code, value = restricted status boolean * - SparseArray w/ mapping: * AppOp code --> Set of packages that are not restricted for this code * */ private final ArrayMap<IBinder, SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>>> mOpUserRestrictions = new ArrayMap<>(); private static final class UidState { public final int uid; Loading Loading @@ -1267,11 +1282,35 @@ public class AppOpsService extends IAppOpsService.Stub { private boolean isOpRestricted(int uid, int code, String packageName) { int userHandle = UserHandle.getUserId(uid); final int restrictionSetCount = mOpUserRestrictions.size(); for (int i = 0; i < restrictionSetCount; i++) { SparseArray<boolean[]> perUserRestrictions = mOpUserRestrictions.valueAt(i); boolean[] opRestrictions = perUserRestrictions.get(userHandle); if (opRestrictions != null && opRestrictions[code]) { // For each client, check that the given op is not restricted, or that the given // package is exempt from the restriction. SparseArray<Pair<boolean[],SparseArray<ArraySet<String>>>> perUserRestrictions = mOpUserRestrictions.valueAt(i); Pair<boolean[],SparseArray<ArraySet<String>>> restrictions = perUserRestrictions.get(userHandle); if (restrictions == null) { continue; // No restrictions set by this client } boolean[] opRestrictions = restrictions.first; SparseArray<ArraySet<String>> opExceptions = restrictions.second; if (opRestrictions == null) { continue; // No restrictions set by this client } if (opRestrictions[code]) { if (opExceptions != null && opExceptions.get(code) != null && opExceptions.get(code).contains(packageName)) { continue; // AppOps code is restricted, but this package is exempt } if (AppOpsManager.opAllowSystemBypassRestriction(code)) { // If we are the system, bypass user restrictions for certain codes synchronized (this) { Ops ops = getOpsLocked(uid, packageName, true); if ((ops != null) && ops.isPrivileged) { Loading @@ -1279,6 +1318,7 @@ public class AppOpsService extends IAppOpsService.Stub { } } } return true; } } Loading Loading @@ -2069,7 +2109,8 @@ public class AppOpsService extends IAppOpsService.Stub { } @Override public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle) { public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle, String[] exceptionPackages) { if (Binder.getCallingPid() != Process.myPid()) { mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS, Binder.getCallingPid(), Binder.getCallingUid(), null); Loading @@ -2085,12 +2126,37 @@ public class AppOpsService extends IAppOpsService.Stub { } verifyIncomingOp(code); Preconditions.checkNotNull(token); setUserRestrictionNoCheck(code, restricted, token, userHandle); setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages); } private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token, int userHandle) { setUserRestrictionNoCheck(code, restricted, token, userHandle, /*exceptionPackages*/null); } private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token, int userHandle, String[] exceptionPackages) { final boolean[] opRestrictions = getOrCreateUserRestrictionsForToken(token, userHandle); if (restricted) { final SparseArray<ArraySet<String>> opExceptions = getUserPackageExemptionsForToken(token, userHandle); // If exceptionPackages is not null, update the exception packages for this AppOps code ArraySet<String> exceptions = opExceptions.get(code); if (exceptionPackages != null) { if (exceptions == null) { exceptions = new ArraySet<>(exceptionPackages.length); opExceptions.put(code, exceptions); } else { exceptions.clear(); } exceptions.addAll(Arrays.asList(exceptionPackages)); } } if (opRestrictions[code] == restricted) { return; } Loading Loading @@ -2132,7 +2198,8 @@ public class AppOpsService extends IAppOpsService.Stub { checkSystemUid("removeUser"); final int tokenCount = mOpUserRestrictions.size(); for (int i = tokenCount - 1; i >= 0; i--) { SparseArray<boolean[]> opRestrictions = mOpUserRestrictions.valueAt(i); SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>> opRestrictions = mOpUserRestrictions.valueAt(i); if (opRestrictions != null) { opRestrictions.remove(userHandle); if (opRestrictions.size() <= 0) { Loading @@ -2144,15 +2211,23 @@ public class AppOpsService extends IAppOpsService.Stub { private void pruneUserRestrictionsForToken(IBinder token, int userHandle) { SparseArray<boolean[]> perTokenRestrictions = mOpUserRestrictions.get(token); SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>> perTokenRestrictions = mOpUserRestrictions.get(token); if (perTokenRestrictions != null) { final boolean[] opRestrictions = perTokenRestrictions.get(userHandle); final Pair<boolean[], SparseArray<ArraySet<String>>> restrictions = perTokenRestrictions.get(userHandle); if (restrictions != null) { final boolean[] opRestrictions = restrictions.first; if (opRestrictions != null) { for (boolean restriction : opRestrictions) { if (restriction) { return; } } } // No restrictions set for this client perTokenRestrictions.remove(userHandle); if (perTokenRestrictions.size() <= 0) { mOpUserRestrictions.remove(token); Loading @@ -2161,18 +2236,61 @@ public class AppOpsService extends IAppOpsService.Stub { } } /** * Get or create the user restrictions array for a given client if it doesn't already exist. * * @param token the binder client creating the restriction. * @param userHandle the user handle to create a restriction for. * * @return the array of restriction states for each AppOps code. */ private boolean[] getOrCreateUserRestrictionsForToken(IBinder token, int userHandle) { SparseArray<boolean[]> perTokenRestrictions = mOpUserRestrictions.get(token); SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>> perTokenRestrictions = mOpUserRestrictions.get(token); if (perTokenRestrictions == null) { perTokenRestrictions = new SparseArray<>(); perTokenRestrictions = new SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>>(); mOpUserRestrictions.put(token, perTokenRestrictions); } boolean[] opRestrictions = perTokenRestrictions.get(userHandle); if (opRestrictions == null) { opRestrictions = new boolean[AppOpsManager._NUM_OP]; perTokenRestrictions.put(userHandle, opRestrictions); Pair<boolean[], SparseArray<ArraySet<String>>> restrictions = perTokenRestrictions.get(userHandle); if (restrictions == null) { restrictions = new Pair<boolean[], SparseArray<ArraySet<String>>>( new boolean[AppOpsManager._NUM_OP], new SparseArray<ArraySet<String>>()); perTokenRestrictions.put(userHandle, restrictions); } return opRestrictions; return restrictions.first; } /** * Get the per-package exemptions for each AppOps code for a given client and userHandle. * * @param token the binder client to get the exemptions for. * @param userHandle the user handle to get the exemptions for. * * @return a mapping from the AppOps code to a set of packages exempt for that code. */ private SparseArray<ArraySet<String>> getUserPackageExemptionsForToken(IBinder token, int userHandle) { SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>> perTokenRestrictions = mOpUserRestrictions.get(token); if (perTokenRestrictions == null) { return null; // Don't create user restrictions accidentally } Pair<boolean[], SparseArray<ArraySet<String>>> restrictions = perTokenRestrictions.get(userHandle); if (restrictions == null) { return null; // Don't create user restrictions accidentally } return restrictions.second; } private void checkSystemUid(String function) { Loading
services/core/java/com/android/server/vr/VrManagerService.java +11 −7 Original line number Diff line number Diff line Loading @@ -201,13 +201,16 @@ public class VrManagerService extends SystemService implements EnabledComponentC } } private void updateOverlayStateLocked() { private void updateOverlayStateLocked(ComponentName exemptedComponent) { final long identity = Binder.clearCallingIdentity(); try { AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class); if (appOpsManager != null) { String[] exemptions = (exemptedComponent == null) ? new String[0] : new String[] { exemptedComponent.getPackageName() }; appOpsManager.setUserRestriction(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, mVrModeEnabled, mOverlayToken); mVrModeEnabled, mOverlayToken, exemptions); } } finally { Binder.restoreCallingIdentity(identity); Loading @@ -230,12 +233,12 @@ public class VrManagerService extends SystemService implements EnabledComponentC private boolean updateCurrentVrServiceLocked(boolean enabled, @NonNull ComponentName component, int userId) { // Always send mode change events. changeVrModeLocked(enabled); boolean validUserComponent = (mComponentObserver.isValid(component, userId) == EnabledComponentsObserver.NO_ERROR); // Always send mode change events. changeVrModeLocked(enabled, (enabled && validUserComponent) ? component : null); if (!enabled || !validUserComponent) { // Unbind whatever is running if (mCurrentVrService != null) { Loading Loading @@ -275,8 +278,9 @@ public class VrManagerService extends SystemService implements EnabledComponentC * Note: Must be called while holding {@code mLock}. * * @param enabled new state of the VR mode. * @param exemptedComponent a component to exempt from AppOps restrictions for overlays. */ private void changeVrModeLocked(boolean enabled) { private void changeVrModeLocked(boolean enabled, ComponentName exemptedComponent) { if (mVrModeEnabled != enabled) { mVrModeEnabled = enabled; Loading @@ -284,7 +288,7 @@ public class VrManagerService extends SystemService implements EnabledComponentC Slog.i(TAG, "VR mode " + ((mVrModeEnabled) ? "enabled" : "disabled")); setVrModeNative(mVrModeEnabled); updateOverlayStateLocked(); updateOverlayStateLocked(exemptedComponent); onVrModeChangedLocked(); } } Loading