Fix issue #34327404: AppOpsManager.stopWatchingMode(callback)...

...does not remove all references to callback

Keep the callbacks in a set, so each callback can only appear once.

Test: none currently, not sure how to do a CTS test for this.
(But verifying the system boots and runs.)

Change-Id: I01c8ea2a662e09ad0a0cdf713f0ea7f175182e82
This commit is contained in:
Dianne Hackborn
2017-02-27 15:32:03 -08:00
parent eb422ead0c
commit 68d7655558

View File

@@ -167,14 +167,10 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
final SparseArray<ArrayList<Callback>> mOpModeWatchers
= new SparseArray<ArrayList<Callback>>();
final ArrayMap<String, ArrayList<Callback>> mPackageModeWatchers
= new ArrayMap<String, ArrayList<Callback>>();
final ArrayMap<IBinder, Callback> mModeWatchers
= new ArrayMap<IBinder, Callback>();
final SparseArray<SparseArray<Restriction>> mAudioRestrictions
= new SparseArray<SparseArray<Restriction>>();
final SparseArray<ArraySet<Callback>> mOpModeWatchers = new SparseArray<>();
final ArrayMap<String, ArraySet<Callback>> mPackageModeWatchers = new ArrayMap<>();
final ArrayMap<IBinder, Callback> mModeWatchers = new ArrayMap<>();
final SparseArray<SparseArray<Restriction>> mAudioRestrictions = new SparseArray<>();
public final class Callback implements DeathRecipient {
final IAppOpsCallback mCallback;
@@ -545,11 +541,11 @@ public class AppOpsService extends IAppOpsService.Stub {
ArrayMap<Callback, ArraySet<String>> callbackSpecs = null;
synchronized (this) {
ArrayList<Callback> callbacks = mOpModeWatchers.get(code);
ArraySet<Callback> callbacks = mOpModeWatchers.get(code);
if (callbacks != null) {
final int callbackCount = callbacks.size();
for (int i = 0; i < callbackCount; i++) {
Callback callback = callbacks.get(i);
Callback callback = callbacks.valueAt(i);
ArraySet<String> changedPackages = new ArraySet<>();
Collections.addAll(changedPackages, uidPackageNames);
callbackSpecs = new ArrayMap<>();
@@ -565,7 +561,7 @@ public class AppOpsService extends IAppOpsService.Stub {
}
final int callbackCount = callbacks.size();
for (int i = 0; i < callbackCount; i++) {
Callback callback = callbacks.get(i);
Callback callback = callbacks.valueAt(i);
ArraySet<String> changedPackages = callbackSpecs.get(callback);
if (changedPackages == null) {
changedPackages = new ArraySet<>();
@@ -623,17 +619,17 @@ public class AppOpsService extends IAppOpsService.Stub {
if (op != null) {
if (op.mode != mode) {
op.mode = mode;
ArrayList<Callback> cbs = mOpModeWatchers.get(code);
ArraySet<Callback> cbs = mOpModeWatchers.get(code);
if (cbs != null) {
if (repCbs == null) {
repCbs = new ArrayList<Callback>();
repCbs = new ArrayList<>();
}
repCbs.addAll(cbs);
}
cbs = mPackageModeWatchers.get(packageName);
if (cbs != null) {
if (repCbs == null) {
repCbs = new ArrayList<Callback>();
repCbs = new ArrayList<>();
}
repCbs.addAll(cbs);
}
@@ -666,7 +662,7 @@ public class AppOpsService extends IAppOpsService.Stub {
private static HashMap<Callback, ArrayList<ChangeRec>> addCallbacks(
HashMap<Callback, ArrayList<ChangeRec>> callbacks,
int op, int uid, String packageName, ArrayList<Callback> cbs) {
int op, int uid, String packageName, ArraySet<Callback> cbs) {
if (cbs == null) {
return callbacks;
}
@@ -674,8 +670,9 @@ public class AppOpsService extends IAppOpsService.Stub {
callbacks = new HashMap<>();
}
boolean duplicate = false;
for (int i=0; i<cbs.size(); i++) {
Callback cb = cbs.get(i);
final int N = cbs.size();
for (int i=0; i<N; i++) {
Callback cb = cbs.valueAt(i);
ArrayList<ChangeRec> reports = callbacks.get(cb);
if (reports == null) {
reports = new ArrayList<>();
@@ -830,17 +827,17 @@ public class AppOpsService extends IAppOpsService.Stub {
mModeWatchers.put(callback.asBinder(), cb);
}
if (op != AppOpsManager.OP_NONE) {
ArrayList<Callback> cbs = mOpModeWatchers.get(op);
ArraySet<Callback> cbs = mOpModeWatchers.get(op);
if (cbs == null) {
cbs = new ArrayList<Callback>();
cbs = new ArraySet<>();
mOpModeWatchers.put(op, cbs);
}
cbs.add(cb);
}
if (packageName != null) {
ArrayList<Callback> cbs = mPackageModeWatchers.get(packageName);
ArraySet<Callback> cbs = mPackageModeWatchers.get(packageName);
if (cbs == null) {
cbs = new ArrayList<Callback>();
cbs = new ArraySet<>();
mPackageModeWatchers.put(packageName, cbs);
}
cbs.add(cb);
@@ -858,14 +855,14 @@ public class AppOpsService extends IAppOpsService.Stub {
if (cb != null) {
cb.unlinkToDeath();
for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
ArrayList<Callback> cbs = mOpModeWatchers.valueAt(i);
ArraySet<Callback> cbs = mOpModeWatchers.valueAt(i);
cbs.remove(cb);
if (cbs.size() <= 0) {
mOpModeWatchers.removeAt(i);
}
}
for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
ArrayList<Callback> cbs = mPackageModeWatchers.valueAt(i);
ArraySet<Callback> cbs = mPackageModeWatchers.valueAt(i);
cbs.remove(cb);
if (cbs.size() <= 0) {
mPackageModeWatchers.removeAt(i);
@@ -2066,10 +2063,10 @@ public class AppOpsService extends IAppOpsService.Stub {
for (int i=0; i<mOpModeWatchers.size(); i++) {
pw.print(" Op "); pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
pw.println(":");
ArrayList<Callback> callbacks = mOpModeWatchers.valueAt(i);
ArraySet<Callback> callbacks = mOpModeWatchers.valueAt(i);
for (int j=0; j<callbacks.size(); j++) {
pw.print(" #"); pw.print(j); pw.print(": ");
pw.println(callbacks.get(j));
pw.println(callbacks.valueAt(j));
}
}
}
@@ -2079,10 +2076,10 @@ public class AppOpsService extends IAppOpsService.Stub {
for (int i=0; i<mPackageModeWatchers.size(); i++) {
pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
pw.println(":");
ArrayList<Callback> callbacks = mPackageModeWatchers.valueAt(i);
ArraySet<Callback> callbacks = mPackageModeWatchers.valueAt(i);
for (int j=0; j<callbacks.size(); j++) {
pw.print(" #"); pw.print(j); pw.print(": ");
pw.println(callbacks.get(j));
pw.println(callbacks.valueAt(j));
}
}
}
@@ -2310,23 +2307,23 @@ public class AppOpsService extends IAppOpsService.Stub {
}
private void notifyWatchersOfChange(int code) {
final ArrayList<Callback> clonedCallbacks;
final ArraySet<Callback> clonedCallbacks;
synchronized (this) {
ArrayList<Callback> callbacks = mOpModeWatchers.get(code);
ArraySet<Callback> callbacks = mOpModeWatchers.get(code);
if (callbacks == null) {
return;
}
clonedCallbacks = new ArrayList<>(callbacks);
clonedCallbacks = new ArraySet<>(callbacks);
}
// There are components watching for mode changes such as window manager
// and location manager which are in our process. The callbacks in these
// components may require permissions our remote caller does not have.s
// components may require permissions our remote caller does not have.
final long identity = Binder.clearCallingIdentity();
try {
final int callbackCount = clonedCallbacks.size();
for (int i = 0; i < callbackCount; i++) {
Callback callback = clonedCallbacks.get(i);
Callback callback = clonedCallbacks.valueAt(i);
try {
callback.mCallback.opChanged(code, -1, null);
} catch (RemoteException e) {