diff options
-rw-r--r-- | cmds/am/src/com/android/commands/am/Am.java | 67 | ||||
-rw-r--r-- | core/java/android/app/ActivityManager.java | 149 | ||||
-rw-r--r-- | core/java/android/app/ActivityManagerNative.java | 70 | ||||
-rw-r--r-- | core/java/android/app/IActivityManager.java | 16 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ActivityManagerService.java | 20 |
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) { |