summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Kuhne <skuhne@google.com>2015-06-05 07:18:06 -0700
committerStefan Kuhne <skuhne@google.com>2015-06-05 16:30:29 -0700
commit16045c24fe10cc92329ede099923f1223f49b17d (patch)
tree1418cfb06abbef32f95c8dfa23ce9f1d704e7964
parente7f68c18bf1a1da5d0aa129674fe4f9ecf06ac8c (diff)
downloadframeworks_base-16045c24fe10cc92329ede099923f1223f49b17d.zip
frameworks_base-16045c24fe10cc92329ede099923f1223f49b17d.tar.gz
frameworks_base-16045c24fe10cc92329ede099923f1223f49b17d.tar.bz2
Adding am send-trim-memory command
This patch adds a send-trim-memory command to the ActivityManager to allow for better debugging&testing. The command is adb shell am send-trim-memory [--user <USER_ID>] <PROCESS> <LEVEL> whereas LEVEL can be one of the following: [HIDDEN|RUNNING_MODERATE|BACKGROUND|RUNNING_LOW|MODERATE| RUNNING_CRITICAL|COMPLETE] Bug: 21633189 Change-Id: I7a41ce02c3c9043ffd3e5aaa791f7b7306a9de49
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java67
-rw-r--r--core/java/android/app/ActivityManager.java149
-rw-r--r--core/java/android/app/ActivityManagerNative.java70
-rw-r--r--core/java/android/app/IActivityManager.java16
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java20
5 files changed, 224 insertions, 98 deletions
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 808e124..b0a7dc7 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -31,6 +31,7 @@ import android.app.UiAutomationConnection;
import android.app.usage.ConfigurationStats;
import android.app.usage.IUsageStatsManager;
import android.app.usage.UsageStatsManager;
+import android.content.ComponentCallbacks2;
import android.content.ComponentName;
import android.content.Context;
import android.content.IIntentReceiver;
@@ -144,6 +145,8 @@ public class Am extends BaseCommand {
" am get-config\n" +
" am set-inactive [--user <USER_ID>] <PACKAGE> true|false\n" +
" am get-inactive [--user <USER_ID>] <PACKAGE>\n" +
+ " am send-trim-memory [--user <USER_ID>] <PROCESS>\n" +
+ " [HIDDEN|RUNNING_MODERATE|BACKGROUND|RUNNING_LOW|MODERATE|RUNNING_CRITICAL|COMPLETE]\n" +
"\n" +
"am start: start an Activity. Options are:\n" +
" -D: enable debugging\n" +
@@ -271,9 +274,9 @@ public class Am extends BaseCommand {
"\n" +
"am stack info: display the information about activity stack <STACK_ID>.\n" +
"\n" +
- "am task lock: bring <TASK_ID> to the front and don't allow other tasks to run\n" +
+ "am task lock: bring <TASK_ID> to the front and don't allow other tasks to run.\n" +
"\n" +
- "am task lock stop: end the current task lock\n" +
+ "am task lock stop: end the current task lock.\n" +
"\n" +
"am task resizeable: change if <TASK_ID> is resizeable (true) or not (false).\n" +
"\n" +
@@ -282,12 +285,13 @@ public class Am extends BaseCommand {
" has the specified bounds.\n" +
"\n" +
"am get-config: retrieve the configuration and any recent configurations\n" +
- " of the device\n" +
+ " of the device.\n" +
"\n" +
- "am set-inactive: sets the inactive state of an app\n" +
+ "am set-inactive: sets the inactive state of an app.\n" +
"\n" +
- "am get-inactive: returns the inactive state of an app\n" +
+ "am get-inactive: returns the inactive state of an app.\n" +
"\n" +
+ " am send-trim-memory: Send a memory trim event to a <PROCESS>.\n" +
"\n" +
"<INTENT> specifications include these flags and arguments:\n" +
" [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
@@ -399,6 +403,8 @@ public class Am extends BaseCommand {
runSetInactive();
} else if (op.equals("get-inactive")) {
runGetInactive();
+ } else if (op.equals("send-trim-memory")) {
+ runSendTrimMemory();
} else {
showError("Error: unknown command '" + op + "'");
}
@@ -2070,6 +2076,57 @@ public class Am extends BaseCommand {
System.out.println("Idle=" + isIdle);
}
+ private void runSendTrimMemory() throws Exception {
+ int userId = UserHandle.USER_CURRENT;
+ String opt;
+ while ((opt = nextOption()) != null) {
+ if (opt.equals("--user")) {
+ userId = parseUserArg(nextArgRequired());
+ if (userId == UserHandle.USER_ALL) {
+ System.err.println("Error: Can't use user 'all'");
+ return;
+ }
+ } else {
+ System.err.println("Error: Unknown option: " + opt);
+ return;
+ }
+ }
+
+ String proc = nextArgRequired();
+ String levelArg = nextArgRequired();
+ int level;
+ switch (levelArg) {
+ case "HIDDEN":
+ level = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
+ break;
+ case "RUNNING_MODERATE":
+ level = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
+ break;
+ case "BACKGROUND":
+ level = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
+ break;
+ case "RUNNING_LOW":
+ level = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
+ break;
+ case "MODERATE":
+ level = ComponentCallbacks2.TRIM_MEMORY_MODERATE;
+ break;
+ case "RUNNING_CRITICAL":
+ level = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
+ break;
+ case "COMPLETE":
+ level = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
+ break;
+ default:
+ System.err.println("Error: Unknown level option: " + levelArg);
+ return;
+ }
+ if (!mAm.setProcessMemoryTrimLevel(proc, userId, level)) {
+ System.err.println("Error: Failure to set the level - probably Unknown Process: " +
+ proc);
+ }
+ }
+
/**
* Open the given file for sending into the system process. This verifies
* with SELinux that the system will have access to the file.
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index edebc28..3892dd9 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -462,7 +462,7 @@ public class ActivityManager {
public int getMemoryClass() {
return staticGetMemoryClass();
}
-
+
/** @hide */
static public int staticGetMemoryClass() {
// Really brain dead right now -- just take this from the configured
@@ -473,7 +473,7 @@ public class ActivityManager {
}
return staticGetLargeMemoryClass();
}
-
+
/**
* Return the approximate per-application memory class of the current
* device when an application is running with a large heap. This is the
@@ -490,7 +490,7 @@ public class ActivityManager {
public int getLargeMemoryClass() {
return staticGetLargeMemoryClass();
}
-
+
/** @hide */
static public int staticGetLargeMemoryClass() {
// Really brain dead right now -- just take this from the configured
@@ -809,7 +809,7 @@ public class ActivityManager {
* The true identifier of this task, valid even if it is not running.
*/
public int persistentId;
-
+
/**
* The original Intent used to launch the task. You can use this
* Intent to re-launch the task (if it is no longer running) or bring
@@ -1014,7 +1014,7 @@ public class ActivityManager {
* user has started and the maximum number the system can remember.
* @param flags Information about what to return. May be any combination
* of {@link #RECENT_WITH_EXCLUDED} and {@link #RECENT_IGNORE_UNAVAILABLE}.
- *
+ *
* @return Returns a list of RecentTaskInfo records describing each of
* the recent tasks.
*/
@@ -1146,7 +1146,7 @@ public class ActivityManager {
numActivities = source.readInt();
numRunning = source.readInt();
}
-
+
public static final Creator<RunningTaskInfo> CREATOR = new Creator<RunningTaskInfo>() {
public RunningTaskInfo createFromParcel(Parcel source) {
return new RunningTaskInfo(source);
@@ -1469,100 +1469,100 @@ public class ActivityManager {
* If non-zero, this is the process the service is running in.
*/
public int pid;
-
+
/**
* The UID that owns this service.
*/
public int uid;
-
+
/**
* The name of the process this service runs in.
*/
public String process;
-
+
/**
* Set to true if the service has asked to run as a foreground process.
*/
public boolean foreground;
-
+
/**
* The time when the service was first made active, either by someone
* starting or binding to it. This
* is in units of {@link android.os.SystemClock#elapsedRealtime()}.
*/
public long activeSince;
-
+
/**
* Set to true if this service has been explicitly started.
*/
public boolean started;
-
+
/**
* Number of clients connected to the service.
*/
public int clientCount;
-
+
/**
* Number of times the service's process has crashed while the service
* is running.
*/
public int crashCount;
-
+
/**
* The time when there was last activity in the service (either
* explicit requests to start it or clients binding to it). This
* is in units of {@link android.os.SystemClock#uptimeMillis()}.
*/
public long lastActivityTime;
-
+
/**
* If non-zero, this service is not currently running, but scheduled to
* restart at the given time.
*/
public long restarting;
-
+
/**
* Bit for {@link #flags}: set if this service has been
* explicitly started.
*/
public static final int FLAG_STARTED = 1<<0;
-
+
/**
* Bit for {@link #flags}: set if the service has asked to
* run as a foreground process.
*/
public static final int FLAG_FOREGROUND = 1<<1;
-
+
/**
* Bit for {@link #flags): set if the service is running in a
* core system process.
*/
public static final int FLAG_SYSTEM_PROCESS = 1<<2;
-
+
/**
* Bit for {@link #flags): set if the service is running in a
* persistent process.
*/
public static final int FLAG_PERSISTENT_PROCESS = 1<<3;
-
+
/**
* Running flags.
*/
public int flags;
-
+
/**
* For special services that are bound to by system code, this is
* the package that holds the binding.
*/
public String clientPackage;
-
+
/**
* For special services that are bound to by system code, this is
* a string resource providing a user-visible label for who the
* client is.
*/
public int clientLabel;
-
+
public RunningServiceInfo() {
}
@@ -1603,7 +1603,7 @@ public class ActivityManager {
clientPackage = source.readString();
clientLabel = source.readInt();
}
-
+
public static final Creator<RunningServiceInfo> CREATOR = new Creator<RunningServiceInfo>() {
public RunningServiceInfo createFromParcel(Parcel source) {
return new RunningServiceInfo(source);
@@ -1627,7 +1627,7 @@ public class ActivityManager {
* @param maxNum The maximum number of entries to return in the list. The
* actual number returned may be smaller, depending on how many services
* are running.
- *
+ *
* @return Returns a list of RunningServiceInfo records describing each of
* the running tasks.
*/
@@ -1641,7 +1641,7 @@ public class ActivityManager {
return null;
}
}
-
+
/**
* Returns a PendingIntent you can start to show a control panel for the
* given running service. If the service does not have a control panel,
@@ -1657,7 +1657,7 @@ public class ActivityManager {
return null;
}
}
-
+
/**
* Information you can retrieve about the available memory through
* {@link ActivityManager#getMemoryInfo}.
@@ -1684,7 +1684,7 @@ public class ActivityManager {
* processes.
*/
public long threshold;
-
+
/**
* Set to true if the system considers itself to currently be in a low
* memory situation.
@@ -1717,7 +1717,7 @@ public class ActivityManager {
dest.writeLong(visibleAppThreshold);
dest.writeLong(foregroundAppThreshold);
}
-
+
public void readFromParcel(Parcel source) {
availMem = source.readLong();
totalMem = source.readLong();
@@ -1841,7 +1841,7 @@ public class ActivityManager {
*/
public boolean clearApplicationUserData(String packageName, IPackageDataObserver observer) {
try {
- return ActivityManagerNative.getDefault().clearApplicationUserData(packageName,
+ return ActivityManagerNative.getDefault().clearApplicationUserData(packageName,
observer, UserHandle.myUserId());
} catch (RemoteException e) {
return false;
@@ -1882,7 +1882,7 @@ public class ActivityManager {
* The process name in which the crash or error occurred.
*/
public String processName;
-
+
/**
* The pid of this process; 0 if none
*/
@@ -1894,7 +1894,7 @@ public class ActivityManager {
* the same uid).
*/
public int uid;
-
+
/**
* The activity name associated with the error, if known. May be null.
*/
@@ -1950,8 +1950,8 @@ public class ActivityManager {
longMsg = source.readString();
stackTrace = source.readString();
}
-
- public static final Creator<ProcessErrorStateInfo> CREATOR =
+
+ public static final Creator<ProcessErrorStateInfo> CREATOR =
new Creator<ProcessErrorStateInfo>() {
public ProcessErrorStateInfo createFromParcel(Parcel source) {
return new ProcessErrorStateInfo(source);
@@ -1965,11 +1965,11 @@ public class ActivityManager {
readFromParcel(source);
}
}
-
+
/**
- * Returns a list of any processes that are currently in an error condition. The result
+ * Returns a list of any processes that are currently in an error condition. The result
* will be null if all processes are running properly at this time.
- *
+ *
* @return Returns a list of ProcessErrorStateInfo records, or null if there are no
* current error conditions (it will not return an empty list). This list ordering is not
* specified.
@@ -1985,7 +1985,7 @@ public class ActivityManager {
/**
* Information you can retrieve about a running process.
*/
- public static class RunningAppProcessInfo implements Parcelable {
+ public static class RunningAppProcessInfo implements Parcelable {
/**
* The name of the process that this object is associated with
*/
@@ -1995,17 +1995,17 @@ public class ActivityManager {
* The pid of this process; 0 if none
*/
public int pid;
-
+
/**
* The user id of this process.
*/
public int uid;
-
+
/**
* All packages that have been loaded into the process.
*/
public String pkgList[];
-
+
/**
* Constant for {@link #flags}: this is an app that is unable to
* correctly save its state when going to the background,
@@ -2013,7 +2013,7 @@ public class ActivityManager {
* @hide
*/
public static final int FLAG_CANT_SAVE_STATE = 1<<0;
-
+
/**
* Constant for {@link #flags}: this process is associated with a
* persistent system app.
@@ -2048,7 +2048,7 @@ public class ActivityManager {
* that the user is interacting with.
*/
public static final int IMPORTANCE_FOREGROUND = 100;
-
+
/**
* Constant for {@link #importance}: This process is running a foreground
* service, for example to perform music playback even while the user is
@@ -2075,13 +2075,13 @@ public class ActivityManager {
* other services under the system's control that it inconsiders important.
*/
public static final int IMPORTANCE_VISIBLE = 200;
-
+
/**
* Constant for {@link #importance}: This process is not something the user
* is directly aware of, but is otherwise perceptable to them to some degree.
*/
public static final int IMPORTANCE_PERCEPTIBLE = 130;
-
+
/**
* Constant for {@link #importance}: This process is running an
* application that can not save its state, and thus can't be killed
@@ -2089,7 +2089,7 @@ public class ActivityManager {
* @hide
*/
public static final int IMPORTANCE_CANT_SAVE_STATE = 170;
-
+
/**
* Constant for {@link #importance}: This process is contains services
* that should remain running. These are background services apps have
@@ -2098,13 +2098,13 @@ public class ActivityManager {
* stay running as long as they want to).
*/
public static final int IMPORTANCE_SERVICE = 300;
-
+
/**
* Constant for {@link #importance}: This process process contains
* background code that is expendable.
*/
public static final int IMPORTANCE_BACKGROUND = 400;
-
+
/**
* Constant for {@link #importance}: This process is empty of any
* actively running code.
@@ -2148,7 +2148,7 @@ public class ActivityManager {
* smaller than "less important" values.
*/
public int importance;
-
+
/**
* An additional ordering within a particular {@link #importance}
* category, providing finer-grained information about the relative
@@ -2165,7 +2165,7 @@ public class ActivityManager {
* been specified for the reason for this level.
*/
public static final int REASON_UNKNOWN = 0;
-
+
/**
* Constant for {@link #importanceReasonCode}: one of the application's
* content providers is being used by another process. The pid of
@@ -2174,7 +2174,7 @@ public class ActivityManager {
* {@link #importanceReasonComponent}.
*/
public static final int REASON_PROVIDER_IN_USE = 1;
-
+
/**
* Constant for {@link #importanceReasonCode}: one of the application's
* content providers is being used by another process. The pid of
@@ -2183,25 +2183,25 @@ public class ActivityManager {
* {@link #importanceReasonComponent}.
*/
public static final int REASON_SERVICE_IN_USE = 2;
-
+
/**
* The reason for {@link #importance}, if any.
*/
public int importanceReasonCode;
-
+
/**
* For the specified values of {@link #importanceReasonCode}, this
* is the process ID of the other process that is a client of this
* process. This will be 0 if no other process is using this one.
*/
public int importanceReasonPid;
-
+
/**
* For the specified values of {@link #importanceReasonCode}, this
* is the name of the component that is being used in this process.
*/
public ComponentName importanceReasonComponent;
-
+
/**
* When {@link #importanceReasonPid} is non-0, this is the importance
* of the other pid. @hide
@@ -2219,7 +2219,7 @@ public class ActivityManager {
importanceReasonCode = REASON_UNKNOWN;
processState = PROCESS_STATE_IMPORTANT_FOREGROUND;
}
-
+
public RunningAppProcessInfo(String pProcessName, int pPid, String pArr[]) {
processName = pProcessName;
pid = pPid;
@@ -2262,7 +2262,7 @@ public class ActivityManager {
processState = source.readInt();
}
- public static final Creator<RunningAppProcessInfo> CREATOR =
+ public static final Creator<RunningAppProcessInfo> CREATOR =
new Creator<RunningAppProcessInfo>() {
public RunningAppProcessInfo createFromParcel(Parcel source) {
return new RunningAppProcessInfo(source);
@@ -2276,7 +2276,7 @@ public class ActivityManager {
readFromParcel(source);
}
}
-
+
/**
* Returns a list of application processes installed on external media
* that are running on the device.
@@ -2297,6 +2297,23 @@ public class ActivityManager {
}
/**
+ * Sets the memory trim mode for a process and schedules a memory trim operation.
+ *
+ * <p><b>Note: this method is only intended for testing framework.</b></p>
+ *
+ * @return Returns true if successful.
+ * @hide
+ */
+ public boolean setProcessMemoryTrimLevel(String process, int userId, int level) {
+ try {
+ return ActivityManagerNative.getDefault().setProcessMemoryTrimLevel(process, userId,
+ level);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
* Returns a list of application processes that are running on the device.
*
* <p><b>Note: this method is only intended for debugging or building
@@ -2368,7 +2385,7 @@ public class ActivityManager {
return null;
}
}
-
+
/**
* @deprecated This is now just a wrapper for
* {@link #killBackgroundProcesses(String)}; the previous behavior here
@@ -2380,17 +2397,17 @@ public class ActivityManager {
public void restartPackage(String packageName) {
killBackgroundProcesses(packageName);
}
-
+
/**
* Have the system immediately kill all background processes associated
* with the given package. This is the same as the kernel killing those
* processes to reclaim memory; the system will take care of restarting
* these processes in the future as needed.
- *
+ *
* <p>You must hold the permission
* {@link android.Manifest.permission#KILL_BACKGROUND_PROCESSES} to be able to
* call this method.
- *
+ *
* @param packageName The name of the package whose processes are to
* be killed.
*/
@@ -2426,14 +2443,14 @@ public class ActivityManager {
* removed, etc. In addition, a {@link Intent#ACTION_PACKAGE_RESTARTED}
* broadcast will be sent, so that any of its registered alarms can
* be stopped, notifications removed, etc.
- *
+ *
* <p>You must hold the permission
* {@link android.Manifest.permission#FORCE_STOP_PACKAGES} to be able to
* call this method.
- *
+ *
* @param packageName The name of the package to be stopped.
* @param userId The user for which the running package is to be stopped.
- *
+ *
* @hide This is not available to third party applications due to
* it allowing them to break other applications by stopping their
* services, removing their alarms, etc.
@@ -2697,7 +2714,7 @@ public class ActivityManager {
}
/**
- * @param userid the user's id. Zero indicates the default user
+ * @param userid the user's id. Zero indicates the default user.
* @hide
*/
public boolean switchUser(int userid) {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index e4def1e..ff52e67 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1546,21 +1546,21 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
reply.writeInt(res ? 1 : 0);
return true;
}
-
+
case STOP_APP_SWITCHES_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
stopAppSwitches();
reply.writeNoException();
return true;
}
-
+
case RESUME_APP_SWITCHES_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
resumeAppSwitches();
reply.writeNoException();
return true;
}
-
+
case PEEK_SERVICE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
Intent service = Intent.CREATOR.createFromParcel(data);
@@ -1570,7 +1570,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
reply.writeStrongBinder(binder);
return true;
}
-
+
case START_BACKUP_AGENT_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
ApplicationInfo info = ApplicationInfo.CREATOR.createFromParcel(data);
@@ -1623,7 +1623,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
reply.writeNoException();
return true;
}
-
+
case GET_PROCESS_MEMORY_INFO_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int[] pids = data.createIntArray();
@@ -1641,7 +1641,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
reply.writeNoException();
return true;
}
-
+
case OVERRIDE_PENDING_TRANSITION_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
@@ -1652,7 +1652,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
reply.writeNoException();
return true;
}
-
+
case IS_USER_A_MONKEY_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
boolean areThey = isUserAMonkey();
@@ -1660,7 +1660,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
reply.writeInt(areThey ? 1 : 0);
return true;
}
-
+
case SET_USER_IS_MONKEY_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
final boolean monkey = (data.readInt() == 1);
@@ -1736,7 +1736,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
reply.writeNoException();
return true;
}
-
+
case IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
boolean isit = isTopActivityImmersive();
@@ -1888,7 +1888,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
reply.writeNoException();
return true;
}
-
+
case SWITCH_USER_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int userid = data.readInt();
@@ -2548,6 +2548,17 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
reply.writeInt(res);
return true;
}
+
+ case SET_PROCESS_MEMORY_TRIM_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ String process = data.readString();
+ int userId = data.readInt();
+ int level = data.readInt();
+ boolean res = setProcessMemoryTrimLevel(process, userId, level);
+ reply.writeNoException();
+ reply.writeInt(res ? 1 : 0);
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -3619,7 +3630,7 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
return res;
}
-
+
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, int userId) throws RemoteException
{
@@ -3722,7 +3733,7 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
return res;
}
-
+
public void publishService(IBinder token,
Intent intent, IBinder service) throws RemoteException {
Parcel data = Parcel.obtain();
@@ -3765,7 +3776,7 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
reply.recycle();
}
-
+
public IBinder peekService(Intent service, String resolvedType) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -4455,7 +4466,7 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
reply.recycle();
}
-
+
public void getMyMemoryState(ActivityManager.RunningAppProcessInfo outInfo)
throws RemoteException
{
@@ -4519,7 +4530,7 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
return res;
}
-
+
public void stopAppSwitches() throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -4529,7 +4540,7 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
data.recycle();
}
-
+
public void resumeAppSwitches() throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -4564,7 +4575,7 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
reply.recycle();
}
-
+
public void closeSystemDialogs(String reason) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -4575,7 +4586,7 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
reply.recycle();
}
-
+
public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
throws RemoteException {
Parcel data = Parcel.obtain();
@@ -4601,7 +4612,7 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
reply.recycle();
}
-
+
public void overridePendingTransition(IBinder token, String packageName,
int enterAnim, int exitAnim) throws RemoteException {
Parcel data = Parcel.obtain();
@@ -4616,7 +4627,7 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
reply.recycle();
}
-
+
public boolean isUserAMonkey() throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -4872,7 +4883,7 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
return res;
}
-
+
public int startActivities(IApplicationThread caller, String callingPackage,
Intent[] intents, String[] resolvedTypes, IBinder resultTo,
Bundle options, int userId) throws RemoteException {
@@ -5880,5 +5891,22 @@ class ActivityManagerProxy implements IActivityManager
return res;
}
+ @Override
+ public boolean setProcessMemoryTrimLevel(String process, int userId, int level)
+ throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeString(process);
+ data.writeInt(userId);
+ data.writeInt(level);
+ mRemote.transact(SET_PROCESS_MEMORY_TRIM_TRANSACTION, data, reply, 0);
+ reply.readException();
+ int res = reply.readInt();
+ data.recycle();
+ reply.recycle();
+ return res != 0;
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 0a425ae..7fa4c40 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -240,14 +240,14 @@ public interface IActivityManager extends IInterface {
public void showWaitingForDebugger(IApplicationThread who, boolean waiting)
throws RemoteException;
-
+
public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) throws RemoteException;
-
+
public void killBackgroundProcesses(final String packageName, int userId)
throws RemoteException;
public void killAllBackgroundProcesses() throws RemoteException;
public void forceStopPackage(final String packageName, int userId) throws RemoteException;
-
+
// Note: probably don't want to allow applications access to these.
public void setLockScreenShown(boolean shown) throws RemoteException;
@@ -261,7 +261,7 @@ public interface IActivityManager extends IInterface {
throws RemoteException;
public void enterSafeMode() throws RemoteException;
-
+
public void noteWakeupAlarm(IIntentSender sender, int sourceUid, String sourcePkg, String tag)
throws RemoteException;
public void noteAlarmStart(IIntentSender sender, int sourceUid, String tag)
@@ -316,9 +316,9 @@ public interface IActivityManager extends IInterface {
public void killApplicationWithAppId(String pkg, int appid, String reason)
throws RemoteException;
-
+
public void closeSystemDialogs(String reason) throws RemoteException;
-
+
public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
throws RemoteException;
@@ -505,6 +505,9 @@ public interface IActivityManager extends IInterface {
public int getPackageProcessState(String packageName) throws RemoteException;
+ public boolean setProcessMemoryTrimLevel(String process, int uid, int level)
+ throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -790,6 +793,7 @@ public interface IActivityManager extends IInterface {
// Available
int GET_ACTIVITY_DISPLAY_ID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+184;
int DELETE_ACTIVITY_CONTAINER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+185;
+ int SET_PROCESS_MEMORY_TRIM_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+186;
// Start of L transactions
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 81b8457..754bb1d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3613,6 +3613,26 @@ public final class ActivityManagerService extends ActivityManagerNative
return procState;
}
+ @Override
+ public boolean setProcessMemoryTrimLevel(String process, int userId, int level) {
+ ProcessRecord app = getProcessRecordLocked(process, userId, true);
+ if (app == null) {
+ return false;
+ }
+ if (app.trimMemoryLevel < level && app.thread != null &&
+ (level < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN ||
+ app.trimMemoryLevel >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN)) {
+ try {
+ app.thread.scheduleTrimMemory(level);
+ app.trimMemoryLevel = level;
+ return true;
+ } catch (RemoteException e) {
+ // Fallthrough to failure case.
+ }
+ }
+ return false;
+ }
+
private void dispatchProcessesChanged() {
int N;
synchronized (this) {