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/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 65de4ca..00bba2d 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -327,12 +327,39 @@
/** @hide Process is being cached for later use and is empty. */
public static final int PROCESS_STATE_CACHED_EMPTY = 16;
+ /** @hide Should this process state be considered a background state? */
+ public static final boolean isProcStateBackground(int procState) {
+ return procState >= PROCESS_STATE_BACKUP;
+ }
+
/** @hide requestType for assist context: only basic information. */
public static final int ASSIST_CONTEXT_BASIC = 0;
/** @hide requestType for assist context: generate full AssistStructure. */
public static final int ASSIST_CONTEXT_FULL = 1;
+ /** @hide Flag for registerUidObserver: report changes in process state. */
+ public static final int UID_OBSERVER_PROCSTATE = 1<<0;
+
+ /** @hide Flag for registerUidObserver: report uid gone. */
+ public static final int UID_OBSERVER_GONE = 1<<1;
+
+ /** @hide Flag for registerUidObserver: report uid has become idle. */
+ public static final int UID_OBSERVER_IDLE = 1<<2;
+
+ /** @hide Flag for registerUidObserver: report uid has become active. */
+ public static final int UID_OBSERVER_ACTIVE = 1<<3;
+
+ /** @hide Mode for {@link IActivityManager#getAppStartMode}: normal free-to-run operation. */
+ public static final int APP_START_MODE_NORMAL = 0;
+
+ /** @hide Mode for {@link IActivityManager#getAppStartMode}: delay running until later. */
+ public static final int APP_START_MODE_DELAYED = 1;
+
+ /** @hide Mode for {@link IActivityManager#getAppStartMode}: disable/cancel pending
+ * launches. */
+ public static final int APP_START_MODE_DISABLED = 2;
+
/**
* Lock task mode is not active.
*/
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 4449e4f..e246e620 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -756,7 +756,7 @@
return true;
}
- case MOVE_TOP_ACTIVITY_TO_PINNED_STACK: {
+ case MOVE_TOP_ACTIVITY_TO_PINNED_STACK_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
final int stackId = data.readInt();
final Rect r = Rect.CREATOR.createFromParcel(data);
@@ -2029,7 +2029,8 @@
data.enforceInterface(IActivityManager.descriptor);
IUidObserver observer = IUidObserver.Stub.asInterface(
data.readStrongBinder());
- registerUidObserver(observer);
+ int which = data.readInt();
+ registerUidObserver(observer, which);
return true;
}
@@ -2698,13 +2699,22 @@
reply.writeNoException();
return true;
}
- case REMOVE_STACK: {
+ case REMOVE_STACK_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
final int stackId = data.readInt();
removeStack(stackId);
reply.writeNoException();
return true;
}
+ case GET_APP_START_MODE_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ final int uid = data.readInt();
+ final String pkg = data.readString();
+ int res = getAppStartMode(uid, pkg);
+ reply.writeNoException();
+ reply.writeInt(res);
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -3579,7 +3589,7 @@
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeInt(stackId);
r.writeToParcel(data, 0);
- mRemote.transact(MOVE_TOP_ACTIVITY_TO_PINNED_STACK, data, reply, 0);
+ mRemote.transact(MOVE_TOP_ACTIVITY_TO_PINNED_STACK_TRANSACTION, data, reply, 0);
reply.readException();
final boolean res = reply.readInt() != 0;
data.recycle();
@@ -5326,11 +5336,12 @@
reply.recycle();
}
- public void registerUidObserver(IUidObserver observer) throws RemoteException {
+ public void registerUidObserver(IUidObserver observer, int which) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(observer != null ? observer.asBinder() : null);
+ data.writeInt(which);
mRemote.transact(REGISTER_UID_OBSERVER_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
@@ -6292,11 +6303,26 @@
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeInt(stackId);
- mRemote.transact(REMOVE_STACK, data, reply, 0);
+ mRemote.transact(REMOVE_STACK_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}
+ @Override
+ public int getAppStartMode(int uid, String packageName) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeInt(uid);
+ data.writeString(packageName);
+ mRemote.transact(GET_APP_START_MODE_TRANSACTION, data, reply, 0);
+ reply.readException();
+ int res = reply.readInt();
+ data.recycle();
+ reply.recycle();
+ return res;
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 77a9795..f0453e9 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -237,8 +237,10 @@
public static final int OP_TURN_SCREEN_ON = 61;
/** @hide Get device accounts. */
public static final int OP_GET_ACCOUNTS = 62;
+ /** @hide Control whether an application is allowed to run in the background. */
+ public static final int OP_RUN_IN_BACKGROUND = 63;
/** @hide */
- public static final int _NUM_OP = 63;
+ public static final int _NUM_OP = 64;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -409,6 +411,7 @@
OP_WRITE_EXTERNAL_STORAGE,
OP_TURN_SCREEN_ON,
OP_GET_ACCOUNTS,
+ OP_RUN_IN_BACKGROUND,
};
/**
@@ -478,7 +481,8 @@
OPSTR_READ_EXTERNAL_STORAGE,
OPSTR_WRITE_EXTERNAL_STORAGE,
null,
- OPSTR_GET_ACCOUNTS
+ OPSTR_GET_ACCOUNTS,
+ null,
};
/**
@@ -549,6 +553,7 @@
"WRITE_EXTERNAL_STORAGE",
"TURN_ON_SCREEN",
"GET_ACCOUNTS",
+ "RUN_IN_BACKGROUND",
};
/**
@@ -618,7 +623,8 @@
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
null, // no permission for turning the screen on
- Manifest.permission.GET_ACCOUNTS
+ Manifest.permission.GET_ACCOUNTS,
+ null, // no permission for running in background
};
/**
@@ -690,6 +696,7 @@
null, // WRITE_EXTERNAL_STORAGE
null, // TURN_ON_SCREEN
null, // GET_ACCOUNTS
+ null, // RUN_IN_BACKGROUND
};
/**
@@ -760,6 +767,7 @@
false, // WRITE_EXTERNAL_STORAGE
false, // TURN_ON_SCREEN
false, // GET_ACCOUNTS
+ false, // RUN_IN_BACKGROUND
};
/**
@@ -829,6 +837,7 @@
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED, // OP_TURN_ON_SCREEN
AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED, // OP_RUN_IN_BACKGROUND
};
/**
@@ -901,7 +910,8 @@
false,
false,
false,
- false
+ false,
+ false,
};
/**
@@ -1329,7 +1339,7 @@
IAppOpsCallback cb = mModeWatchers.get(callback);
if (cb == null) {
cb = new IAppOpsCallback.Stub() {
- public void opChanged(int op, String packageName) {
+ public void opChanged(int op, int uid, String packageName) {
if (callback instanceof OnOpChangedInternalListener) {
((OnOpChangedInternalListener)callback).onOpChanged(op, packageName);
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index b69a480..3d0fc92 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -400,7 +400,7 @@
public void registerProcessObserver(IProcessObserver observer) throws RemoteException;
public void unregisterProcessObserver(IProcessObserver observer) throws RemoteException;
- public void registerUidObserver(IUidObserver observer) throws RemoteException;
+ public void registerUidObserver(IUidObserver observer, int which) throws RemoteException;
public void unregisterUidObserver(IUidObserver observer) throws RemoteException;
public boolean isIntentSenderTargetedToPackage(IIntentSender sender) throws RemoteException;
@@ -542,6 +542,8 @@
public void removeStack(int stackId) throws RemoteException;
+ public int getAppStartMode(int uid, String packageName) throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -899,6 +901,7 @@
int REPORT_SIZE_CONFIGURATIONS = IBinder.FIRST_CALL_TRANSACTION + 345;
int MOVE_TASK_TO_DOCKED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 346;
int SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 347;
- int REMOVE_STACK = IBinder.FIRST_CALL_TRANSACTION + 348;
- int MOVE_TOP_ACTIVITY_TO_PINNED_STACK = IBinder.FIRST_CALL_TRANSACTION + 349;
+ int REMOVE_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 348;
+ int MOVE_TOP_ACTIVITY_TO_PINNED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 349;
+ int GET_APP_START_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 350;
}
diff --git a/core/java/android/app/IUidObserver.aidl b/core/java/android/app/IUidObserver.aidl
index 308cb94..fa8d0c9 100644
--- a/core/java/android/app/IUidObserver.aidl
+++ b/core/java/android/app/IUidObserver.aidl
@@ -18,6 +18,24 @@
/** {@hide} */
oneway interface IUidObserver {
+ /**
+ * General report of a state change of an uid.
+ */
void onUidStateChanged(int uid, int procState);
+
+ /**
+ * Report that there are no longer any processes running for a uid.
+ */
void onUidGone(int uid);
+
+ /**
+ * Report that a uid is now active (no longer idle).
+ */
+ void onUidActive(int uid);
+
+ /**
+ * Report that a uid is idle -- it has either been running in the background for
+ * a sufficient period of time, or all of its processes have gone away.
+ */
+ void onUidIdle(int uid);
}