Initial stab at background check.
Actually, this implementation is more what we want for ephemeral
apps. I am realizing the two are not really the same thing. :(
For this implementation, we now keep track of how long a uid has
been in the background, and after a certain amount of time
(currently 1 minute) we mark it as "idle". Any packages associated
with that uid are then no longer allowed to run in the background.
This means, until the app next goes in the foreground:
- No manifest broadcast receivers in the app will execute.
- No services can be started (binding services is still okay,
as this is outside dependencies on the app that should still
be represented).
- All alarms for the app are cancelled and no more can be set.
- All jobs for the app are cancelled and no more can be scheduled.
- All syncs for the app are cancelled and no more can be requested.
Change-Id: If53714ca4beed35faf2e89f916ce9eaaabd9290d
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 96c1e2a..c131628 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -54,7 +54,6 @@
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;
@@ -557,12 +556,12 @@
ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
try {
if (reportedPackageNames == null) {
- callback.mCallback.opChanged(code, null);
+ callback.mCallback.opChanged(code, uid, null);
} else {
final int reportedPackageCount = reportedPackageNames.size();
for (int j = 0; j < reportedPackageCount; j++) {
String reportedPackageName = reportedPackageNames.valueAt(j);
- callback.mCallback.opChanged(code, reportedPackageName);
+ callback.mCallback.opChanged(code, uid, reportedPackageName);
}
}
} catch (RemoteException e) {
@@ -620,7 +619,7 @@
try {
for (int i = 0; i < repCbs.size(); i++) {
try {
- repCbs.get(i).mCallback.opChanged(code, packageName);
+ repCbs.get(i).mCallback.opChanged(code, uid, packageName);
} catch (RemoteException e) {
}
}
@@ -630,39 +629,51 @@
}
}
- private static HashMap<Callback, ArrayList<Pair<String, Integer>>> addCallbacks(
- HashMap<Callback, ArrayList<Pair<String, Integer>>> callbacks,
- String packageName, int op, ArrayList<Callback> cbs) {
+ private static HashMap<Callback, ArrayList<ChangeRec>> addCallbacks(
+ HashMap<Callback, ArrayList<ChangeRec>> callbacks,
+ int op, int uid, String packageName, ArrayList<Callback> cbs) {
if (cbs == null) {
return callbacks;
}
if (callbacks == null) {
- callbacks = new HashMap<Callback, ArrayList<Pair<String, Integer>>>();
+ callbacks = new HashMap<>();
}
boolean duplicate = false;
for (int i=0; i<cbs.size(); i++) {
Callback cb = cbs.get(i);
- ArrayList<Pair<String, Integer>> reports = callbacks.get(cb);
+ ArrayList<ChangeRec> reports = callbacks.get(cb);
if (reports == null) {
- reports = new ArrayList<Pair<String, Integer>>();
+ reports = new ArrayList<>();
callbacks.put(cb, reports);
} else {
final int reportCount = reports.size();
for (int j = 0; j < reportCount; j++) {
- Pair<String, Integer> report = reports.get(j);
- if (report.second == op && report.first.equals(packageName)) {
+ ChangeRec report = reports.get(j);
+ if (report.op == op && report.pkg.equals(packageName)) {
duplicate = true;
break;
}
}
}
if (!duplicate) {
- reports.add(new Pair<>(packageName, op));
+ reports.add(new ChangeRec(op, uid, packageName));
}
}
return callbacks;
}
+ static final class ChangeRec {
+ final int op;
+ final int uid;
+ final String pkg;
+
+ ChangeRec(int _op, int _uid, String _pkg) {
+ op = _op;
+ uid = _uid;
+ pkg = _pkg;
+ }
+ }
+
@Override
public void resetAllModes(int reqUserId, String reqPackageName) {
final int callingPid = Binder.getCallingPid();
@@ -682,7 +693,7 @@
}
}
- HashMap<Callback, ArrayList<Pair<String, Integer>>> callbacks = null;
+ HashMap<Callback, ArrayList<ChangeRec>> callbacks = null;
synchronized (this) {
boolean changed = false;
for (int i = mUidStates.size() - 1; i >= 0; i--) {
@@ -699,9 +710,9 @@
uidState.opModes = null;
}
for (String packageName : getPackagesForUid(uidState.uid)) {
- callbacks = addCallbacks(callbacks, packageName, code,
+ callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
mOpModeWatchers.get(code));
- callbacks = addCallbacks(callbacks, packageName, code,
+ callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
mPackageModeWatchers.get(packageName));
}
}
@@ -734,9 +745,9 @@
&& curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
changed = true;
- callbacks = addCallbacks(callbacks, packageName, curOp.op,
+ callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
mOpModeWatchers.get(curOp.op));
- callbacks = addCallbacks(callbacks, packageName, curOp.op,
+ callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
mPackageModeWatchers.get(packageName));
if (curOp.time == 0 && curOp.rejectTime == 0) {
pkgOps.removeAt(j);
@@ -757,13 +768,13 @@
}
}
if (callbacks != null) {
- for (Map.Entry<Callback, ArrayList<Pair<String, Integer>>> ent : callbacks.entrySet()) {
+ for (Map.Entry<Callback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) {
Callback cb = ent.getKey();
- ArrayList<Pair<String, Integer>> reports = ent.getValue();
+ ArrayList<ChangeRec> reports = ent.getValue();
for (int i=0; i<reports.size(); i++) {
- Pair<String, Integer> rep = reports.get(i);
+ ChangeRec rep = reports.get(i);
try {
- cb.mCallback.opChanged(rep.second, rep.first);
+ cb.mCallback.opChanged(rep.op, rep.uid, rep.pkg);
} catch (RemoteException e) {
}
}
@@ -1163,8 +1174,10 @@
if (pkgUid != uid) {
// Oops! The package name is not valid for the uid they are calling
// under. Abort.
+ RuntimeException ex = new RuntimeException("here");
+ ex.fillInStackTrace();
Slog.w(TAG, "Bad call: specified package " + packageName
- + " under uid " + uid + " but it is really " + pkgUid);
+ + " under uid " + uid + " but it is really " + pkgUid, ex);
return null;
}
} finally {