Merge "Revert "Revert "AppOps refactor for mode watchers."""
This commit is contained in:
committed by
Android (Google) Code Review
commit
b6d070d1b8
@@ -63,7 +63,6 @@ import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
|
||||
import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
|
||||
import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
|
||||
import static android.app.AppOpsManager.UID_STATE_TOP;
|
||||
import static android.app.AppOpsManager.WATCH_FOREGROUND_CHANGES;
|
||||
import static android.app.AppOpsManager._NUM_OP;
|
||||
import static android.app.AppOpsManager.extractFlagsFromKey;
|
||||
import static android.app.AppOpsManager.extractUidStateFromKey;
|
||||
@@ -563,6 +562,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
public ArrayMap<String, Ops> pkgOps;
|
||||
|
||||
// true indicates there is an interested observer, false there isn't but it has such an op
|
||||
//TODO: Move foregroundOps and hasForegroundWatchers into the AppOpsServiceInterface.
|
||||
public SparseBooleanArray foregroundOps;
|
||||
public boolean hasForegroundWatchers;
|
||||
|
||||
@@ -658,48 +658,24 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
return mode;
|
||||
}
|
||||
|
||||
private void evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers,
|
||||
SparseBooleanArray which) {
|
||||
boolean curValue = which.get(op, false);
|
||||
ArraySet<ModeCallback> callbacks = watchers.get(op);
|
||||
if (callbacks != null) {
|
||||
for (int cbi = callbacks.size() - 1; !curValue && cbi >= 0; cbi--) {
|
||||
if ((callbacks.valueAt(cbi).mFlags
|
||||
& AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) {
|
||||
hasForegroundWatchers = true;
|
||||
curValue = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
which.put(op, curValue);
|
||||
}
|
||||
|
||||
public void evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers) {
|
||||
SparseBooleanArray which = null;
|
||||
hasForegroundWatchers = false;
|
||||
final SparseIntArray opModes = getNonDefaultUidModes();
|
||||
for (int i = opModes.size() - 1; i >= 0; i--) {
|
||||
if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
|
||||
if (which == null) {
|
||||
which = new SparseBooleanArray();
|
||||
}
|
||||
evalForegroundWatchers(opModes.keyAt(i), watchers, which);
|
||||
}
|
||||
}
|
||||
public void evalForegroundOps() {
|
||||
foregroundOps = null;
|
||||
foregroundOps = mAppOpsServiceInterface.evalForegroundUidOps(uid, foregroundOps);
|
||||
if (pkgOps != null) {
|
||||
for (int i = pkgOps.size() - 1; i >= 0; i--) {
|
||||
Ops ops = pkgOps.valueAt(i);
|
||||
for (int j = ops.size() - 1; j >= 0; j--) {
|
||||
if (ops.valueAt(j).getMode() == AppOpsManager.MODE_FOREGROUND) {
|
||||
if (which == null) {
|
||||
which = new SparseBooleanArray();
|
||||
}
|
||||
evalForegroundWatchers(ops.keyAt(j), watchers, which);
|
||||
}
|
||||
foregroundOps = mAppOpsServiceInterface
|
||||
.evalForegroundPackageOps(pkgOps.valueAt(i).packageName, foregroundOps);
|
||||
}
|
||||
}
|
||||
hasForegroundWatchers = false;
|
||||
if (foregroundOps != null) {
|
||||
for (int i = 0; i < foregroundOps.size(); i++) {
|
||||
if (foregroundOps.valueAt(i)) {
|
||||
hasForegroundWatchers = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
foregroundOps = which;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1562,33 +1538,24 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
}
|
||||
}
|
||||
|
||||
final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>();
|
||||
final ArrayMap<String, ArraySet<ModeCallback>> mPackageModeWatchers = new ArrayMap<>();
|
||||
final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>();
|
||||
final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>();
|
||||
final ArrayMap<IBinder, SparseArray<StartedCallback>> mStartedWatchers = new ArrayMap<>();
|
||||
final ArrayMap<IBinder, SparseArray<NotedCallback>> mNotedWatchers = new ArrayMap<>();
|
||||
final AudioRestrictionManager mAudioRestrictionManager = new AudioRestrictionManager();
|
||||
|
||||
final class ModeCallback implements DeathRecipient {
|
||||
final class ModeCallback extends OnOpModeChangedListener implements DeathRecipient {
|
||||
/** If mWatchedOpCode==ALL_OPS notify for ops affected by the switch-op */
|
||||
public static final int ALL_OPS = -2;
|
||||
|
||||
final IAppOpsCallback mCallback;
|
||||
final int mWatchingUid;
|
||||
final int mFlags;
|
||||
final int mWatchedOpCode;
|
||||
final int mCallingUid;
|
||||
final int mCallingPid;
|
||||
// Need to keep this only because stopWatchingMode needs an IAppOpsCallback.
|
||||
// Otherwise we can just use the IBinder object.
|
||||
private final IAppOpsCallback mCallback;
|
||||
|
||||
ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int watchedOp,
|
||||
ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int watchedOpCode,
|
||||
int callingUid, int callingPid) {
|
||||
mCallback = callback;
|
||||
mWatchingUid = watchingUid;
|
||||
mFlags = flags;
|
||||
mWatchedOpCode = watchedOp;
|
||||
mCallingUid = callingUid;
|
||||
mCallingPid = callingPid;
|
||||
super(watchingUid, flags, watchedOpCode, callingUid, callingPid);
|
||||
this.mCallback = callback;
|
||||
try {
|
||||
mCallback.asBinder().linkToDeath(this, 0);
|
||||
} catch (RemoteException e) {
|
||||
@@ -1596,20 +1563,16 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isWatchingUid(int uid) {
|
||||
return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(128);
|
||||
sb.append("ModeCallback{");
|
||||
sb.append(Integer.toHexString(System.identityHashCode(this)));
|
||||
sb.append(" watchinguid=");
|
||||
UserHandle.formatUid(sb, mWatchingUid);
|
||||
UserHandle.formatUid(sb, getWatchingUid());
|
||||
sb.append(" flags=0x");
|
||||
sb.append(Integer.toHexString(mFlags));
|
||||
switch (mWatchedOpCode) {
|
||||
sb.append(Integer.toHexString(getFlags()));
|
||||
switch (getWatchedOpCode()) {
|
||||
case OP_NONE:
|
||||
break;
|
||||
case ALL_OPS:
|
||||
@@ -1617,13 +1580,13 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
break;
|
||||
default:
|
||||
sb.append(" op=");
|
||||
sb.append(opToName(mWatchedOpCode));
|
||||
sb.append(opToName(getWatchedOpCode()));
|
||||
break;
|
||||
}
|
||||
sb.append(" from uid=");
|
||||
UserHandle.formatUid(sb, mCallingUid);
|
||||
UserHandle.formatUid(sb, getCallingUid());
|
||||
sb.append(" pid=");
|
||||
sb.append(mCallingPid);
|
||||
sb.append(getCallingPid());
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
@@ -1636,6 +1599,11 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
public void binderDied() {
|
||||
stopWatchingMode(mCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpModeChanged(int op, int uid, String packageName) throws RemoteException {
|
||||
mCallback.opChanged(op, uid, packageName);
|
||||
}
|
||||
}
|
||||
|
||||
final class ActiveCallback implements DeathRecipient {
|
||||
@@ -1804,7 +1772,14 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
|
||||
public AppOpsService(File storagePath, Handler handler, Context context) {
|
||||
mContext = context;
|
||||
mAppOpsServiceInterface = new LegacyAppOpsServiceInterfaceImpl(this, this);
|
||||
|
||||
for (int switchedCode = 0; switchedCode < _NUM_OP; switchedCode++) {
|
||||
int switchCode = AppOpsManager.opToSwitch(switchedCode);
|
||||
mSwitchedOps.put(switchCode,
|
||||
ArrayUtils.appendInt(mSwitchedOps.get(switchCode), switchedCode));
|
||||
}
|
||||
mAppOpsServiceInterface =
|
||||
new LegacyAppOpsServiceInterfaceImpl(this, this, handler, context, mSwitchedOps);
|
||||
|
||||
LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
|
||||
mFile = new AtomicFile(storagePath, "appops");
|
||||
@@ -1818,12 +1793,6 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
mHandler = handler;
|
||||
mConstants = new Constants(mHandler);
|
||||
readState();
|
||||
|
||||
for (int switchedCode = 0; switchedCode < _NUM_OP; switchedCode++) {
|
||||
int switchCode = AppOpsManager.opToSwitch(switchedCode);
|
||||
mSwitchedOps.put(switchCode,
|
||||
ArrayUtils.appendInt(mSwitchedOps.get(switchCode), switchedCode));
|
||||
}
|
||||
}
|
||||
|
||||
public void publish() {
|
||||
@@ -1982,20 +1951,20 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
final String[] changedPkgs = intent.getStringArrayExtra(
|
||||
Intent.EXTRA_CHANGED_PACKAGE_LIST);
|
||||
for (int code : OPS_RESTRICTED_ON_SUSPEND) {
|
||||
ArraySet<ModeCallback> callbacks;
|
||||
ArraySet<OnOpModeChangedListener> onModeChangedListeners;
|
||||
synchronized (AppOpsService.this) {
|
||||
callbacks = mOpModeWatchers.get(code);
|
||||
if (callbacks == null) {
|
||||
onModeChangedListeners =
|
||||
mAppOpsServiceInterface.getOpModeChangedListeners(code);
|
||||
if (onModeChangedListeners == null) {
|
||||
continue;
|
||||
}
|
||||
callbacks = new ArraySet<>(callbacks);
|
||||
}
|
||||
for (int i = 0; i < changedUids.length; i++) {
|
||||
final int changedUid = changedUids[i];
|
||||
final String changedPkg = changedPkgs[i];
|
||||
// We trust packagemanager to insert matching uid and packageNames in the
|
||||
// extras
|
||||
notifyOpChanged(callbacks, code, changedUid, changedPkg);
|
||||
notifyOpChanged(onModeChangedListeners, code, changedUid, changedPkg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2596,7 +2565,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
if (!uidState.setUidMode(code, mode)) {
|
||||
return;
|
||||
}
|
||||
uidState.evalForegroundOps(mOpModeWatchers);
|
||||
uidState.evalForegroundOps();
|
||||
if (mode != MODE_ERRORED && mode != previousMode) {
|
||||
updateStartedOpModeForUidLocked(code, mode == MODE_IGNORED, uid);
|
||||
}
|
||||
@@ -2615,78 +2584,10 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
*/
|
||||
private void notifyOpChangedForAllPkgsInUid(int code, int uid, boolean onlyForeground,
|
||||
@Nullable IAppOpsCallback callbackToIgnore) {
|
||||
String[] uidPackageNames = getPackagesForUid(uid);
|
||||
ArrayMap<ModeCallback, ArraySet<String>> callbackSpecs = null;
|
||||
|
||||
synchronized (this) {
|
||||
ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
|
||||
if (callbacks != null) {
|
||||
final int callbackCount = callbacks.size();
|
||||
for (int i = 0; i < callbackCount; i++) {
|
||||
ModeCallback callback = callbacks.valueAt(i);
|
||||
if (onlyForeground && (callback.mFlags & WATCH_FOREGROUND_CHANGES) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ArraySet<String> changedPackages = new ArraySet<>();
|
||||
Collections.addAll(changedPackages, uidPackageNames);
|
||||
if (callbackSpecs == null) {
|
||||
callbackSpecs = new ArrayMap<>();
|
||||
}
|
||||
callbackSpecs.put(callback, changedPackages);
|
||||
}
|
||||
}
|
||||
|
||||
for (String uidPackageName : uidPackageNames) {
|
||||
callbacks = mPackageModeWatchers.get(uidPackageName);
|
||||
if (callbacks != null) {
|
||||
if (callbackSpecs == null) {
|
||||
callbackSpecs = new ArrayMap<>();
|
||||
}
|
||||
final int callbackCount = callbacks.size();
|
||||
for (int i = 0; i < callbackCount; i++) {
|
||||
ModeCallback callback = callbacks.valueAt(i);
|
||||
if (onlyForeground && (callback.mFlags & WATCH_FOREGROUND_CHANGES) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ArraySet<String> changedPackages = callbackSpecs.get(callback);
|
||||
if (changedPackages == null) {
|
||||
changedPackages = new ArraySet<>();
|
||||
callbackSpecs.put(callback, changedPackages);
|
||||
}
|
||||
changedPackages.add(uidPackageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (callbackSpecs != null && callbackToIgnore != null) {
|
||||
callbackSpecs.remove(mModeWatchers.get(callbackToIgnore.asBinder()));
|
||||
}
|
||||
}
|
||||
|
||||
if (callbackSpecs == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < callbackSpecs.size(); i++) {
|
||||
final ModeCallback callback = callbackSpecs.keyAt(i);
|
||||
final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
|
||||
if (reportedPackageNames == null) {
|
||||
mHandler.sendMessage(PooledLambda.obtainMessage(
|
||||
AppOpsService::notifyOpChanged,
|
||||
this, callback, code, uid, (String) null));
|
||||
|
||||
} else {
|
||||
final int reportedPackageCount = reportedPackageNames.size();
|
||||
for (int j = 0; j < reportedPackageCount; j++) {
|
||||
final String reportedPackageName = reportedPackageNames.valueAt(j);
|
||||
mHandler.sendMessage(PooledLambda.obtainMessage(
|
||||
AppOpsService::notifyOpChanged,
|
||||
this, callback, code, uid, reportedPackageName));
|
||||
}
|
||||
}
|
||||
}
|
||||
ModeCallback listenerToIgnore = callbackToIgnore != null
|
||||
? mModeWatchers.get(callbackToIgnore.asBinder()) : null;
|
||||
mAppOpsServiceInterface.notifyOpChangedForAllPkgsInUid(code, uid, onlyForeground,
|
||||
listenerToIgnore);
|
||||
}
|
||||
|
||||
private void updatePermissionRevokedCompat(int uid, int switchCode, int mode) {
|
||||
@@ -2810,7 +2711,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
return;
|
||||
}
|
||||
|
||||
ArraySet<ModeCallback> repCbs = null;
|
||||
ArraySet<OnOpModeChangedListener> repCbs = null;
|
||||
code = AppOpsManager.opToSwitch(code);
|
||||
|
||||
PackageVerificationResult pvr;
|
||||
@@ -2831,16 +2732,17 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
op.setMode(mode);
|
||||
|
||||
if (uidState != null) {
|
||||
uidState.evalForegroundOps(mOpModeWatchers);
|
||||
uidState.evalForegroundOps();
|
||||
}
|
||||
ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code);
|
||||
ArraySet<OnOpModeChangedListener> cbs =
|
||||
mAppOpsServiceInterface.getOpModeChangedListeners(code);
|
||||
if (cbs != null) {
|
||||
if (repCbs == null) {
|
||||
repCbs = new ArraySet<>();
|
||||
}
|
||||
repCbs.addAll(cbs);
|
||||
}
|
||||
cbs = mPackageModeWatchers.get(packageName);
|
||||
cbs = mAppOpsServiceInterface.getPackageModeChangedListeners(packageName);
|
||||
if (cbs != null) {
|
||||
if (repCbs == null) {
|
||||
repCbs = new ArraySet<>();
|
||||
@@ -2871,47 +2773,17 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
notifyOpChangedSync(code, uid, packageName, mode, previousMode);
|
||||
}
|
||||
|
||||
private void notifyOpChanged(ArraySet<ModeCallback> callbacks, int code,
|
||||
private void notifyOpChanged(ArraySet<OnOpModeChangedListener> callbacks, int code,
|
||||
int uid, String packageName) {
|
||||
for (int i = 0; i < callbacks.size(); i++) {
|
||||
final ModeCallback callback = callbacks.valueAt(i);
|
||||
final OnOpModeChangedListener callback = callbacks.valueAt(i);
|
||||
notifyOpChanged(callback, code, uid, packageName);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyOpChanged(ModeCallback callback, int code,
|
||||
private void notifyOpChanged(OnOpModeChangedListener callback, int code,
|
||||
int uid, String packageName) {
|
||||
if (uid != UID_ANY && callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
|
||||
return;
|
||||
}
|
||||
|
||||
// See CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE
|
||||
int[] switchedCodes;
|
||||
if (callback.mWatchedOpCode == ALL_OPS) {
|
||||
switchedCodes = mSwitchedOps.get(code);
|
||||
} else if (callback.mWatchedOpCode == OP_NONE) {
|
||||
switchedCodes = new int[]{code};
|
||||
} else {
|
||||
switchedCodes = new int[]{callback.mWatchedOpCode};
|
||||
}
|
||||
|
||||
for (int switchedCode : switchedCodes) {
|
||||
// There are features watching for mode changes such as window manager
|
||||
// and location manager which are in our process. The callbacks in these
|
||||
// features may require permissions our remote caller does not have.
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
if (shouldIgnoreCallback(switchedCode, callback.mCallingPid,
|
||||
callback.mCallingUid)) {
|
||||
continue;
|
||||
}
|
||||
callback.mCallback.opChanged(switchedCode, uid, packageName);
|
||||
} catch (RemoteException e) {
|
||||
/* ignore */
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
mAppOpsServiceInterface.notifyOpChanged(callback, code, uid, packageName);
|
||||
}
|
||||
|
||||
private static ArrayList<ChangeRec> addChange(ArrayList<ChangeRec> reports,
|
||||
@@ -2936,9 +2808,10 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
return reports;
|
||||
}
|
||||
|
||||
private static HashMap<ModeCallback, ArrayList<ChangeRec>> addCallbacks(
|
||||
HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks,
|
||||
int op, int uid, String packageName, int previousMode, ArraySet<ModeCallback> cbs) {
|
||||
private static HashMap<OnOpModeChangedListener, ArrayList<ChangeRec>> addCallbacks(
|
||||
HashMap<OnOpModeChangedListener, ArrayList<ChangeRec>> callbacks,
|
||||
int op, int uid, String packageName, int previousMode,
|
||||
ArraySet<OnOpModeChangedListener> cbs) {
|
||||
if (cbs == null) {
|
||||
return callbacks;
|
||||
}
|
||||
@@ -2947,7 +2820,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
}
|
||||
final int N = cbs.size();
|
||||
for (int i=0; i<N; i++) {
|
||||
ModeCallback cb = cbs.valueAt(i);
|
||||
OnOpModeChangedListener cb = cbs.valueAt(i);
|
||||
ArrayList<ChangeRec> reports = callbacks.get(cb);
|
||||
ArrayList<ChangeRec> changed = addChange(reports, op, uid, packageName, previousMode);
|
||||
if (changed != reports) {
|
||||
@@ -2990,7 +2863,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
|
||||
enforceManageAppOpsModes(callingPid, callingUid, reqUid);
|
||||
|
||||
HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks = null;
|
||||
HashMap<OnOpModeChangedListener, ArrayList<ChangeRec>> callbacks = null;
|
||||
ArrayList<ChangeRec> allChanges = new ArrayList<>();
|
||||
synchronized (this) {
|
||||
boolean changed = false;
|
||||
@@ -3007,9 +2880,11 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
uidState.setUidMode(code, AppOpsManager.opToDefaultMode(code));
|
||||
for (String packageName : getPackagesForUid(uidState.uid)) {
|
||||
callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
|
||||
previousMode, mOpModeWatchers.get(code));
|
||||
previousMode,
|
||||
mAppOpsServiceInterface.getOpModeChangedListeners(code));
|
||||
callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
|
||||
previousMode, mPackageModeWatchers.get(packageName));
|
||||
previousMode, mAppOpsServiceInterface
|
||||
.getPackageModeChangedListeners(packageName));
|
||||
|
||||
allChanges = addChange(allChanges, code, uidState.uid,
|
||||
packageName, previousMode);
|
||||
@@ -3053,9 +2928,11 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
uidChanged = true;
|
||||
final int uid = curOp.uidState.uid;
|
||||
callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
|
||||
previousMode, mOpModeWatchers.get(curOp.op));
|
||||
previousMode,
|
||||
mAppOpsServiceInterface.getOpModeChangedListeners(curOp.op));
|
||||
callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
|
||||
previousMode, mPackageModeWatchers.get(packageName));
|
||||
previousMode, mAppOpsServiceInterface
|
||||
.getPackageModeChangedListeners(packageName));
|
||||
|
||||
allChanges = addChange(allChanges, curOp.op, uid, packageName,
|
||||
previousMode);
|
||||
@@ -3075,7 +2952,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
mUidStates.remove(uidState.uid);
|
||||
}
|
||||
if (uidChanged) {
|
||||
uidState.evalForegroundOps(mOpModeWatchers);
|
||||
uidState.evalForegroundOps();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3084,8 +2961,9 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
}
|
||||
}
|
||||
if (callbacks != null) {
|
||||
for (Map.Entry<ModeCallback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) {
|
||||
ModeCallback cb = ent.getKey();
|
||||
for (Map.Entry<OnOpModeChangedListener, ArrayList<ChangeRec>> ent
|
||||
: callbacks.entrySet()) {
|
||||
OnOpModeChangedListener cb = ent.getKey();
|
||||
ArrayList<ChangeRec> reports = ent.getValue();
|
||||
for (int i=0; i<reports.size(); i++) {
|
||||
ChangeRec rep = reports.get(i);
|
||||
@@ -3121,7 +2999,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) {
|
||||
final UidState uidState = mUidStates.valueAt(uidi);
|
||||
if (uidState.foregroundOps != null) {
|
||||
uidState.evalForegroundOps(mOpModeWatchers);
|
||||
uidState.evalForegroundOps();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3169,20 +3047,10 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
mModeWatchers.put(callback.asBinder(), cb);
|
||||
}
|
||||
if (switchOp != AppOpsManager.OP_NONE) {
|
||||
ArraySet<ModeCallback> cbs = mOpModeWatchers.get(switchOp);
|
||||
if (cbs == null) {
|
||||
cbs = new ArraySet<>();
|
||||
mOpModeWatchers.put(switchOp, cbs);
|
||||
}
|
||||
cbs.add(cb);
|
||||
mAppOpsServiceInterface.startWatchingOpModeChanged(cb, switchOp);
|
||||
}
|
||||
if (mayWatchPackageName) {
|
||||
ArraySet<ModeCallback> cbs = mPackageModeWatchers.get(packageName);
|
||||
if (cbs == null) {
|
||||
cbs = new ArraySet<>();
|
||||
mPackageModeWatchers.put(packageName, cbs);
|
||||
}
|
||||
cbs.add(cb);
|
||||
mAppOpsServiceInterface.startWatchingPackageModeChanged(cb, packageName);
|
||||
}
|
||||
evalAllForegroundOpsLocked();
|
||||
}
|
||||
@@ -3197,21 +3065,9 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
ModeCallback cb = mModeWatchers.remove(callback.asBinder());
|
||||
if (cb != null) {
|
||||
cb.unlinkToDeath();
|
||||
for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
|
||||
ArraySet<ModeCallback> cbs = mOpModeWatchers.valueAt(i);
|
||||
cbs.remove(cb);
|
||||
if (cbs.size() <= 0) {
|
||||
mOpModeWatchers.removeAt(i);
|
||||
}
|
||||
}
|
||||
for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
|
||||
ArraySet<ModeCallback> cbs = mPackageModeWatchers.valueAt(i);
|
||||
cbs.remove(cb);
|
||||
if (cbs.size() <= 0) {
|
||||
mPackageModeWatchers.removeAt(i);
|
||||
}
|
||||
}
|
||||
mAppOpsServiceInterface.removeListener(cb);
|
||||
}
|
||||
|
||||
evalAllForegroundOpsLocked();
|
||||
}
|
||||
}
|
||||
@@ -4542,12 +4398,14 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
AppOpsService::notifyOpChangedForAllPkgsInUid,
|
||||
this, code, uidState.uid, true, null));
|
||||
} else if (uidState.pkgOps != null) {
|
||||
final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
|
||||
if (callbacks != null) {
|
||||
for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) {
|
||||
final ModeCallback callback = callbacks.valueAt(cbi);
|
||||
if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
|
||||
|| !callback.isWatchingUid(uidState.uid)) {
|
||||
final ArraySet<OnOpModeChangedListener> listenerSet =
|
||||
mAppOpsServiceInterface.getOpModeChangedListeners(code);
|
||||
if (listenerSet != null) {
|
||||
for (int cbi = listenerSet.size() - 1; cbi >= 0; cbi--) {
|
||||
final OnOpModeChangedListener listener = listenerSet.valueAt(cbi);
|
||||
if ((listener.getFlags()
|
||||
& AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
|
||||
|| !listener.isWatchingUid(uidState.uid)) {
|
||||
continue;
|
||||
}
|
||||
for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
|
||||
@@ -4558,7 +4416,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
if (op.getMode() == AppOpsManager.MODE_FOREGROUND) {
|
||||
mHandler.sendMessage(PooledLambda.obtainMessage(
|
||||
AppOpsService::notifyOpChanged,
|
||||
this, callback, code, uidState.uid,
|
||||
this, listenerSet.valueAt(cbi), code, uidState.uid,
|
||||
uidState.pkgOps.keyAt(pkgi)));
|
||||
}
|
||||
}
|
||||
@@ -5045,7 +4903,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
uidState.evalForegroundOps(mOpModeWatchers);
|
||||
uidState.evalForegroundOps();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5131,7 +4989,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
}
|
||||
}
|
||||
uidState.evalForegroundOps(mOpModeWatchers);
|
||||
uidState.evalForegroundOps();
|
||||
}
|
||||
|
||||
private void readAttributionOp(TypedXmlPullParser parser, @NonNull Op parent,
|
||||
@@ -6122,62 +5980,17 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
}
|
||||
pw.println();
|
||||
}
|
||||
if (mOpModeWatchers.size() > 0 && !dumpHistory) {
|
||||
boolean printedHeader = false;
|
||||
for (int i=0; i<mOpModeWatchers.size(); i++) {
|
||||
if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
|
||||
continue;
|
||||
}
|
||||
boolean printedOpHeader = false;
|
||||
ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i);
|
||||
for (int j=0; j<callbacks.size(); j++) {
|
||||
final ModeCallback cb = callbacks.valueAt(j);
|
||||
if (dumpPackage != null
|
||||
&& dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
|
||||
continue;
|
||||
}
|
||||
needSep = true;
|
||||
if (!printedHeader) {
|
||||
pw.println(" Op mode watchers:");
|
||||
printedHeader = true;
|
||||
}
|
||||
if (!printedOpHeader) {
|
||||
pw.print(" Op ");
|
||||
pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
|
||||
pw.println(":");
|
||||
printedOpHeader = true;
|
||||
}
|
||||
pw.print(" #"); pw.print(j); pw.print(": ");
|
||||
pw.println(cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mPackageModeWatchers.size() > 0 && dumpOp < 0 && !dumpHistory) {
|
||||
boolean printedHeader = false;
|
||||
for (int i=0; i<mPackageModeWatchers.size(); i++) {
|
||||
if (dumpPackage != null && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
|
||||
continue;
|
||||
}
|
||||
needSep = true;
|
||||
if (!printedHeader) {
|
||||
pw.println(" Package mode watchers:");
|
||||
printedHeader = true;
|
||||
}
|
||||
pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
|
||||
pw.println(":");
|
||||
ArraySet<ModeCallback> callbacks = mPackageModeWatchers.valueAt(i);
|
||||
for (int j=0; j<callbacks.size(); j++) {
|
||||
pw.print(" #"); pw.print(j); pw.print(": ");
|
||||
pw.println(callbacks.valueAt(j));
|
||||
}
|
||||
}
|
||||
|
||||
if (!dumpHistory) {
|
||||
needSep |= mAppOpsServiceInterface.dumpListeners(dumpOp, dumpUid, dumpPackage, pw);
|
||||
}
|
||||
|
||||
if (mModeWatchers.size() > 0 && dumpOp < 0 && !dumpHistory) {
|
||||
boolean printedHeader = false;
|
||||
for (int i=0; i<mModeWatchers.size(); i++) {
|
||||
for (int i = 0; i < mModeWatchers.size(); i++) {
|
||||
final ModeCallback cb = mModeWatchers.valueAt(i);
|
||||
if (dumpPackage != null
|
||||
&& dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
|
||||
&& dumpUid != UserHandle.getAppId(cb.getWatchingUid())) {
|
||||
continue;
|
||||
}
|
||||
needSep = true;
|
||||
@@ -6729,16 +6542,15 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
}
|
||||
|
||||
private void notifyWatchersOfChange(int code, int uid) {
|
||||
final ArraySet<ModeCallback> clonedCallbacks;
|
||||
final ArraySet<OnOpModeChangedListener> modeChangedListenerSet;
|
||||
synchronized (this) {
|
||||
ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
|
||||
if (callbacks == null) {
|
||||
modeChangedListenerSet = mAppOpsServiceInterface.getOpModeChangedListeners(code);
|
||||
if (modeChangedListenerSet == null) {
|
||||
return;
|
||||
}
|
||||
clonedCallbacks = new ArraySet<>(callbacks);
|
||||
}
|
||||
|
||||
notifyOpChanged(clonedCallbacks, code, uid, null);
|
||||
notifyOpChanged(modeChangedListenerSet, code, uid, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -14,12 +14,20 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.server.appop;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.AppOpsManager.Mode;
|
||||
import android.util.ArraySet;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Interface for accessing and modifying modes for app-ops i.e. package and uid modes.
|
||||
* In the future this interface will also include mode callbacks and op restrictions.
|
||||
* This interface also includes functions for added and removing op mode watchers.
|
||||
* In the future this interface will also include op restrictions.
|
||||
*/
|
||||
public interface AppOpsServiceInterface {
|
||||
/**
|
||||
@@ -95,4 +103,93 @@ public interface AppOpsServiceInterface {
|
||||
* Stop tracking app-op modes for all uid and packages.
|
||||
*/
|
||||
void clearAllModes();
|
||||
|
||||
/**
|
||||
* Registers changedListener to listen to op's mode change.
|
||||
* @param changedListener the listener that must be trigger on the op's mode change.
|
||||
* @param op op representing the app-op whose mode change needs to be listened to.
|
||||
*/
|
||||
void startWatchingOpModeChanged(@NonNull OnOpModeChangedListener changedListener, int op);
|
||||
|
||||
/**
|
||||
* Registers changedListener to listen to package's app-op's mode change.
|
||||
* @param changedListener the listener that must be trigger on the mode change.
|
||||
* @param packageName of the package whose app-op's mode change needs to be listened to.
|
||||
*/
|
||||
void startWatchingPackageModeChanged(@NonNull OnOpModeChangedListener changedListener,
|
||||
@NonNull String packageName);
|
||||
|
||||
/**
|
||||
* Stop the changedListener from triggering on any mode change.
|
||||
* @param changedListener the listener that needs to be removed.
|
||||
*/
|
||||
void removeListener(@NonNull OnOpModeChangedListener changedListener);
|
||||
|
||||
/**
|
||||
* Temporary API which will be removed once we can safely untangle the methods that use this.
|
||||
* Returns a set of OnOpModeChangedListener that are listening for op's mode changes.
|
||||
* @param op app-op whose mode change is being listened to.
|
||||
*/
|
||||
ArraySet<OnOpModeChangedListener> getOpModeChangedListeners(int op);
|
||||
|
||||
/**
|
||||
* Temporary API which will be removed once we can safely untangle the methods that use this.
|
||||
* Returns a set of OnOpModeChangedListener that are listening for package's op's mode changes.
|
||||
* @param packageName of package whose app-op's mode change is being listened to.
|
||||
*/
|
||||
ArraySet<OnOpModeChangedListener> getPackageModeChangedListeners(@NonNull String packageName);
|
||||
|
||||
/**
|
||||
* Temporary API which will be removed once we can safely untangle the methods that use this.
|
||||
* Notify that the app-op's mode is changed by triggering the change listener.
|
||||
* @param changedListener the change listener.
|
||||
* @param op App-op whose mode has changed
|
||||
* @param uid user id associated with the app-op
|
||||
* @param packageName package name that is associated with the app-op
|
||||
*/
|
||||
void notifyOpChanged(@NonNull OnOpModeChangedListener changedListener, int op, int uid,
|
||||
@Nullable String packageName);
|
||||
|
||||
/**
|
||||
* Temporary API which will be removed once we can safely untangle the methods that use this.
|
||||
* Notify that the app-op's mode is changed to all packages associated with the uid by
|
||||
* triggering the appropriate change listener.
|
||||
* @param op App-op whose mode has changed
|
||||
* @param uid user id associated with the app-op
|
||||
* @param onlyForeground true if only watchers that
|
||||
* @param callbackToIgnore callback that should be ignored.
|
||||
*/
|
||||
void notifyOpChangedForAllPkgsInUid(int op, int uid, boolean onlyForeground,
|
||||
@Nullable OnOpModeChangedListener callbackToIgnore);
|
||||
|
||||
/**
|
||||
* TODO: Move hasForegroundWatchers and foregroundOps into this.
|
||||
* Go over the list of app-ops for the uid and mark app-ops with MODE_FOREGROUND in
|
||||
* foregroundOps.
|
||||
* @param uid for which the app-op's mode needs to be marked.
|
||||
* @param foregroundOps boolean array where app-ops that have MODE_FOREGROUND are marked true.
|
||||
* @return foregroundOps.
|
||||
*/
|
||||
SparseBooleanArray evalForegroundUidOps(int uid, SparseBooleanArray foregroundOps);
|
||||
|
||||
/**
|
||||
* Go over the list of app-ops for the package name and mark app-ops with MODE_FOREGROUND in
|
||||
* foregroundOps.
|
||||
* @param packageName for which the app-op's mode needs to be marked.
|
||||
* @param foregroundOps boolean array where app-ops that have MODE_FOREGROUND are marked true.
|
||||
* @return foregroundOps.
|
||||
*/
|
||||
SparseBooleanArray evalForegroundPackageOps(String packageName,
|
||||
SparseBooleanArray foregroundOps);
|
||||
|
||||
/**
|
||||
* Dump op mode and package mode listeners and their details.
|
||||
* @param dumpOp if -1 then op mode listeners for all app-ops are dumped. If it's set to an
|
||||
* app-op, only the watchers for that app-op are dumped.
|
||||
* @param dumpUid uid for which we want to dump op mode watchers.
|
||||
* @param dumpPackage if not null and if dumpOp is -1, dumps watchers for the package name.
|
||||
* @param printWriter writer to dump to.
|
||||
*/
|
||||
boolean dumpListeners(int dumpOp, int dumpUid, String dumpPackage, PrintWriter printWriter);
|
||||
|
||||
}
|
||||
|
||||
@@ -16,15 +16,39 @@
|
||||
|
||||
package com.android.server.appop;
|
||||
|
||||
import static android.app.AppOpsManager.OP_NONE;
|
||||
import static android.app.AppOpsManager.WATCH_FOREGROUND_CHANGES;
|
||||
import static android.app.AppOpsManager.opRestrictsRead;
|
||||
|
||||
import static com.android.server.appop.AppOpsService.ModeCallback.ALL_OPS;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.AppGlobals;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.AppOpsManager.Mode;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.function.pooled.PooledLambda;
|
||||
|
||||
import libcore.util.EmptyArray;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
/**
|
||||
@@ -33,8 +57,13 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
*/
|
||||
public class LegacyAppOpsServiceInterfaceImpl implements AppOpsServiceInterface {
|
||||
|
||||
// Should be the same object that the AppOpsService is using for locking.
|
||||
static final String TAG = "LegacyAppOpsServiceInterfaceImpl";
|
||||
|
||||
// Must be the same object that the AppOpsService is using for locking.
|
||||
final Object mLock;
|
||||
final Handler mHandler;
|
||||
final Context mContext;
|
||||
final SparseArray<int[]> mSwitchedOps;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
@VisibleForTesting
|
||||
@@ -43,13 +72,25 @@ public class LegacyAppOpsServiceInterfaceImpl implements AppOpsServiceInterface
|
||||
@GuardedBy("mLock")
|
||||
final ArrayMap<String, SparseIntArray> mPackageModes = new ArrayMap<>();
|
||||
|
||||
final SparseArray<ArraySet<OnOpModeChangedListener>> mOpModeWatchers = new SparseArray<>();
|
||||
final ArrayMap<String, ArraySet<OnOpModeChangedListener>> mPackageModeWatchers =
|
||||
new ArrayMap<>();
|
||||
|
||||
final PersistenceScheduler mPersistenceScheduler;
|
||||
|
||||
|
||||
// Constant meaning that any UID should be matched when dispatching callbacks
|
||||
private static final int UID_ANY = -2;
|
||||
|
||||
|
||||
LegacyAppOpsServiceInterfaceImpl(PersistenceScheduler persistenceScheduler,
|
||||
@NonNull Object lock) {
|
||||
@NonNull Object lock, Handler handler, Context context,
|
||||
SparseArray<int[]> switchedOps) {
|
||||
this.mPersistenceScheduler = persistenceScheduler;
|
||||
this.mLock = lock;
|
||||
this.mHandler = handler;
|
||||
this.mContext = context;
|
||||
this.mSwitchedOps = switchedOps;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -158,7 +199,6 @@ public class LegacyAppOpsServiceInterfaceImpl implements AppOpsServiceInterface
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean areUidModesDefault(int uid) {
|
||||
synchronized (mLock) {
|
||||
@@ -195,4 +235,335 @@ public class LegacyAppOpsServiceInterfaceImpl implements AppOpsServiceInterface
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public void startWatchingOpModeChanged(@NonNull OnOpModeChangedListener changedListener,
|
||||
int op) {
|
||||
Objects.requireNonNull(changedListener);
|
||||
synchronized (mLock) {
|
||||
ArraySet<OnOpModeChangedListener> modeWatcherSet = mOpModeWatchers.get(op);
|
||||
if (modeWatcherSet == null) {
|
||||
modeWatcherSet = new ArraySet<>();
|
||||
mOpModeWatchers.put(op, modeWatcherSet);
|
||||
}
|
||||
modeWatcherSet.add(changedListener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startWatchingPackageModeChanged(@NonNull OnOpModeChangedListener changedListener,
|
||||
@NonNull String packageName) {
|
||||
Objects.requireNonNull(changedListener);
|
||||
Objects.requireNonNull(packageName);
|
||||
synchronized (mLock) {
|
||||
ArraySet<OnOpModeChangedListener> modeWatcherSet =
|
||||
mPackageModeWatchers.get(packageName);
|
||||
if (modeWatcherSet == null) {
|
||||
modeWatcherSet = new ArraySet<>();
|
||||
mPackageModeWatchers.put(packageName, modeWatcherSet);
|
||||
}
|
||||
modeWatcherSet.add(changedListener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(@NonNull OnOpModeChangedListener changedListener) {
|
||||
Objects.requireNonNull(changedListener);
|
||||
|
||||
synchronized (mLock) {
|
||||
for (int i = mOpModeWatchers.size() - 1; i >= 0; i--) {
|
||||
ArraySet<OnOpModeChangedListener> cbs = mOpModeWatchers.valueAt(i);
|
||||
cbs.remove(changedListener);
|
||||
if (cbs.size() <= 0) {
|
||||
mOpModeWatchers.removeAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = mPackageModeWatchers.size() - 1; i >= 0; i--) {
|
||||
ArraySet<OnOpModeChangedListener> cbs = mPackageModeWatchers.valueAt(i);
|
||||
cbs.remove(changedListener);
|
||||
if (cbs.size() <= 0) {
|
||||
mPackageModeWatchers.removeAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArraySet<OnOpModeChangedListener> getOpModeChangedListeners(int op) {
|
||||
synchronized (mLock) {
|
||||
ArraySet<OnOpModeChangedListener> modeChangedListenersSet = mOpModeWatchers.get(op);
|
||||
if (modeChangedListenersSet == null) {
|
||||
return new ArraySet<>();
|
||||
}
|
||||
return new ArraySet<>(modeChangedListenersSet);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArraySet<OnOpModeChangedListener> getPackageModeChangedListeners(
|
||||
@NonNull String packageName) {
|
||||
Objects.requireNonNull(packageName);
|
||||
|
||||
synchronized (mLock) {
|
||||
ArraySet<OnOpModeChangedListener> modeChangedListenersSet =
|
||||
mPackageModeWatchers.get(packageName);
|
||||
if (modeChangedListenersSet == null) {
|
||||
return new ArraySet<>();
|
||||
}
|
||||
return new ArraySet<>(modeChangedListenersSet);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyOpChanged(@NonNull OnOpModeChangedListener onModeChangedListener, int code,
|
||||
int uid, @Nullable String packageName) {
|
||||
Objects.requireNonNull(onModeChangedListener);
|
||||
|
||||
if (uid != UID_ANY && onModeChangedListener.getWatchingUid() >= 0
|
||||
&& onModeChangedListener.getWatchingUid() != uid) {
|
||||
return;
|
||||
}
|
||||
|
||||
// See CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE
|
||||
int[] switchedCodes;
|
||||
if (onModeChangedListener.getWatchedOpCode() == ALL_OPS) {
|
||||
switchedCodes = mSwitchedOps.get(code);
|
||||
} else if (onModeChangedListener.getWatchedOpCode() == OP_NONE) {
|
||||
switchedCodes = new int[]{code};
|
||||
} else {
|
||||
switchedCodes = new int[]{onModeChangedListener.getWatchedOpCode()};
|
||||
}
|
||||
|
||||
for (int switchedCode : switchedCodes) {
|
||||
// There are features watching for mode changes such as window manager
|
||||
// and location manager which are in our process. The callbacks in these
|
||||
// features may require permissions our remote caller does not have.
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
if (shouldIgnoreCallback(switchedCode, onModeChangedListener.getCallingPid(),
|
||||
onModeChangedListener.getCallingUid())) {
|
||||
continue;
|
||||
}
|
||||
onModeChangedListener.onOpModeChanged(switchedCode, uid, packageName);
|
||||
} catch (RemoteException e) {
|
||||
/* ignore */
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldIgnoreCallback(int op, int watcherPid, int watcherUid) {
|
||||
// If it's a restricted read op, ignore it if watcher doesn't have manage ops permission,
|
||||
// as watcher should not use this to signal if the value is changed.
|
||||
return opRestrictsRead(op) && mContext.checkPermission(Manifest.permission.MANAGE_APPOPS,
|
||||
watcherPid, watcherUid) != PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyOpChangedForAllPkgsInUid(int code, int uid, boolean onlyForeground,
|
||||
@Nullable OnOpModeChangedListener callbackToIgnore) {
|
||||
String[] uidPackageNames = getPackagesForUid(uid);
|
||||
ArrayMap<OnOpModeChangedListener, ArraySet<String>> callbackSpecs = null;
|
||||
|
||||
synchronized (mLock) {
|
||||
ArraySet<OnOpModeChangedListener> callbacks = mOpModeWatchers.get(code);
|
||||
if (callbacks != null) {
|
||||
final int callbackCount = callbacks.size();
|
||||
for (int i = 0; i < callbackCount; i++) {
|
||||
OnOpModeChangedListener callback = callbacks.valueAt(i);
|
||||
|
||||
if (onlyForeground && (callback.getFlags()
|
||||
& WATCH_FOREGROUND_CHANGES) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ArraySet<String> changedPackages = new ArraySet<>();
|
||||
Collections.addAll(changedPackages, uidPackageNames);
|
||||
if (callbackSpecs == null) {
|
||||
callbackSpecs = new ArrayMap<>();
|
||||
}
|
||||
callbackSpecs.put(callback, changedPackages);
|
||||
}
|
||||
}
|
||||
|
||||
for (String uidPackageName : uidPackageNames) {
|
||||
callbacks = mPackageModeWatchers.get(uidPackageName);
|
||||
if (callbacks != null) {
|
||||
if (callbackSpecs == null) {
|
||||
callbackSpecs = new ArrayMap<>();
|
||||
}
|
||||
final int callbackCount = callbacks.size();
|
||||
for (int i = 0; i < callbackCount; i++) {
|
||||
OnOpModeChangedListener callback = callbacks.valueAt(i);
|
||||
|
||||
if (onlyForeground && (callback.getFlags()
|
||||
& WATCH_FOREGROUND_CHANGES) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ArraySet<String> changedPackages = callbackSpecs.get(callback);
|
||||
if (changedPackages == null) {
|
||||
changedPackages = new ArraySet<>();
|
||||
callbackSpecs.put(callback, changedPackages);
|
||||
}
|
||||
changedPackages.add(uidPackageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (callbackSpecs != null && callbackToIgnore != null) {
|
||||
callbackSpecs.remove(callbackToIgnore);
|
||||
}
|
||||
}
|
||||
|
||||
if (callbackSpecs == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < callbackSpecs.size(); i++) {
|
||||
final OnOpModeChangedListener callback = callbackSpecs.keyAt(i);
|
||||
final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
|
||||
if (reportedPackageNames == null) {
|
||||
mHandler.sendMessage(PooledLambda.obtainMessage(
|
||||
LegacyAppOpsServiceInterfaceImpl::notifyOpChanged,
|
||||
this, callback, code, uid, (String) null));
|
||||
|
||||
} else {
|
||||
final int reportedPackageCount = reportedPackageNames.size();
|
||||
for (int j = 0; j < reportedPackageCount; j++) {
|
||||
final String reportedPackageName = reportedPackageNames.valueAt(j);
|
||||
mHandler.sendMessage(PooledLambda.obtainMessage(
|
||||
LegacyAppOpsServiceInterfaceImpl::notifyOpChanged,
|
||||
this, callback, code, uid, reportedPackageName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String[] getPackagesForUid(int uid) {
|
||||
String[] packageNames = null;
|
||||
|
||||
// Very early during boot the package manager is not yet or not yet fully started. At this
|
||||
// time there are no packages yet.
|
||||
if (AppGlobals.getPackageManager() != null) {
|
||||
try {
|
||||
packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
|
||||
} catch (RemoteException e) {
|
||||
/* ignore - local call */
|
||||
}
|
||||
}
|
||||
if (packageNames == null) {
|
||||
return EmptyArray.STRING;
|
||||
}
|
||||
return packageNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SparseBooleanArray evalForegroundUidOps(int uid, SparseBooleanArray foregroundOps) {
|
||||
synchronized (mLock) {
|
||||
return evalForegroundOps(mUidModes.get(uid), foregroundOps);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SparseBooleanArray evalForegroundPackageOps(String packageName,
|
||||
SparseBooleanArray foregroundOps) {
|
||||
synchronized (mLock) {
|
||||
return evalForegroundOps(mPackageModes.get(packageName), foregroundOps);
|
||||
}
|
||||
}
|
||||
|
||||
private SparseBooleanArray evalForegroundOps(SparseIntArray opModes,
|
||||
SparseBooleanArray foregroundOps) {
|
||||
SparseBooleanArray tempForegroundOps = foregroundOps;
|
||||
if (opModes != null) {
|
||||
for (int i = opModes.size() - 1; i >= 0; i--) {
|
||||
if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
|
||||
if (tempForegroundOps == null) {
|
||||
tempForegroundOps = new SparseBooleanArray();
|
||||
}
|
||||
evalForegroundWatchers(opModes.keyAt(i), tempForegroundOps);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tempForegroundOps;
|
||||
}
|
||||
|
||||
private void evalForegroundWatchers(int op, SparseBooleanArray foregroundOps) {
|
||||
boolean curValue = foregroundOps.get(op, false);
|
||||
ArraySet<OnOpModeChangedListener> listenerSet = mOpModeWatchers.get(op);
|
||||
if (listenerSet != null) {
|
||||
for (int cbi = listenerSet.size() - 1; !curValue && cbi >= 0; cbi--) {
|
||||
if ((listenerSet.valueAt(cbi).getFlags()
|
||||
& AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) {
|
||||
curValue = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
foregroundOps.put(op, curValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dumpListeners(int dumpOp, int dumpUid, String dumpPackage,
|
||||
PrintWriter printWriter) {
|
||||
boolean needSep = false;
|
||||
if (mOpModeWatchers.size() > 0) {
|
||||
boolean printedHeader = false;
|
||||
for (int i = 0; i < mOpModeWatchers.size(); i++) {
|
||||
if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
|
||||
continue;
|
||||
}
|
||||
boolean printedOpHeader = false;
|
||||
ArraySet<OnOpModeChangedListener> modeChangedListenerSet =
|
||||
mOpModeWatchers.valueAt(i);
|
||||
for (int j = 0; j < modeChangedListenerSet.size(); j++) {
|
||||
final OnOpModeChangedListener listener = modeChangedListenerSet.valueAt(j);
|
||||
if (dumpPackage != null
|
||||
&& dumpUid != UserHandle.getAppId(listener.getWatchingUid())) {
|
||||
continue;
|
||||
}
|
||||
needSep = true;
|
||||
if (!printedHeader) {
|
||||
printWriter.println(" Op mode watchers:");
|
||||
printedHeader = true;
|
||||
}
|
||||
if (!printedOpHeader) {
|
||||
printWriter.print(" Op ");
|
||||
printWriter.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
|
||||
printWriter.println(":");
|
||||
printedOpHeader = true;
|
||||
}
|
||||
printWriter.print(" #"); printWriter.print(j); printWriter.print(": ");
|
||||
printWriter.println(listener.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mPackageModeWatchers.size() > 0 && dumpOp < 0) {
|
||||
boolean printedHeader = false;
|
||||
for (int i = 0; i < mPackageModeWatchers.size(); i++) {
|
||||
if (dumpPackage != null
|
||||
&& !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
|
||||
continue;
|
||||
}
|
||||
needSep = true;
|
||||
if (!printedHeader) {
|
||||
printWriter.println(" Package mode watchers:");
|
||||
printedHeader = true;
|
||||
}
|
||||
printWriter.print(" Pkg "); printWriter.print(mPackageModeWatchers.keyAt(i));
|
||||
printWriter.println(":");
|
||||
ArraySet<OnOpModeChangedListener> modeChangedListenerSet =
|
||||
mPackageModeWatchers.valueAt(i);
|
||||
|
||||
for (int j = 0; j < modeChangedListenerSet.size(); j++) {
|
||||
printWriter.print(" #"); printWriter.print(j); printWriter.print(": ");
|
||||
printWriter.println(modeChangedListenerSet.valueAt(j).toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
return needSep;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.appop;
|
||||
|
||||
import android.os.RemoteException;
|
||||
|
||||
/**
|
||||
* Listener for mode changes, encapsulates methods that should be triggered in the event of a mode
|
||||
* change.
|
||||
*/
|
||||
abstract class OnOpModeChangedListener {
|
||||
|
||||
// Constant meaning that any UID should be matched when dispatching callbacks
|
||||
private static final int UID_ANY = -2;
|
||||
|
||||
private int mWatchingUid;
|
||||
private int mFlags;
|
||||
private int mWatchedOpCode;
|
||||
private int mCallingUid;
|
||||
private int mCallingPid;
|
||||
|
||||
OnOpModeChangedListener(int watchingUid, int flags, int watchedOpCode, int callingUid,
|
||||
int callingPid) {
|
||||
this.mWatchingUid = watchingUid;
|
||||
this.mFlags = flags;
|
||||
this.mWatchedOpCode = watchedOpCode;
|
||||
this.mCallingUid = callingUid;
|
||||
this.mCallingPid = callingPid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user id that is watching for the mode change.
|
||||
*/
|
||||
public int getWatchingUid() {
|
||||
return mWatchingUid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the flags associated with the mode change listener.
|
||||
*/
|
||||
public int getFlags() {
|
||||
return mFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the app-op whose mode change should trigger the callback.
|
||||
*/
|
||||
public int getWatchedOpCode() {
|
||||
return mWatchedOpCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user-id that triggered the app-op mode change to be watched.
|
||||
*/
|
||||
public int getCallingUid() {
|
||||
return mCallingUid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the process-id that triggered the app-op mode change to be watched.
|
||||
*/
|
||||
public int getCallingPid() {
|
||||
return mCallingPid;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if the user id passed in the param is the one that is watching for op mode
|
||||
* changed.
|
||||
*/
|
||||
public boolean isWatchingUid(int uid) {
|
||||
return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that should be triggered when the app-op's mode is changed.
|
||||
* @param op app-op whose mode-change is being listened to.
|
||||
* @param uid user-is associated with the app-op.
|
||||
* @param packageName package name associated with the app-op.
|
||||
*/
|
||||
public abstract void onOpModeChanged(int op, int uid, String packageName)
|
||||
throws RemoteException;
|
||||
|
||||
/**
|
||||
* Return human readable string representing the listener.
|
||||
*/
|
||||
public abstract String toString();
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user