summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/ActivityManager.java9
-rw-r--r--core/java/android/os/Debug.java39
-rw-r--r--core/jni/android_os_Debug.cpp2
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerConstants.java17
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java58
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java6
6 files changed, 122 insertions, 9 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index c12d8e21b5e8..61df7cb8dbc4 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -3266,6 +3266,15 @@ public class ActivityManager {
* <p><b>Note: this method is only intended for debugging or building
* a user-facing process management UI.</b></p>
*
+ * <p>This method is different from
+ * {@link android.os.Debug#getMemoryInfo(int, Debug.MemoryInfo)} in that it will
+ * (a) include additional low-level system allocation (via memtrack), and (b)
+ * be significantly limited in the frequency at which data can be sampled.</p>
+ *
+ * As of {@link android.os.Build.VERSION_CODES#Q Android Q}, for regular apps this method
+ * will only return information about the memory info for the processes running as the
+ * caller's uid; no other process memory info is available and will be zero.
+ *
* @param pids The pids of the processes whose memory usage is to be
* retrieved.
* @return Returns an array of memory information, one for each
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 6ddcbe0b3b64..aba81af00282 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -321,6 +321,45 @@ public final class Debug
}
/**
+ * @hide Copy contents from another object.
+ */
+ public void set(MemoryInfo other) {
+ dalvikPss = other.dalvikPss;
+ dalvikSwappablePss = other.dalvikSwappablePss;
+ dalvikRss = other.dalvikRss;
+ dalvikPrivateDirty = other.dalvikPrivateDirty;
+ dalvikSharedDirty = other.dalvikSharedDirty;
+ dalvikPrivateClean = other.dalvikPrivateClean;
+ dalvikSharedClean = other.dalvikSharedClean;
+ dalvikSwappedOut = other.dalvikSwappedOut;
+ dalvikSwappedOutPss = other.dalvikSwappedOutPss;
+
+ nativePss = other.nativePss;
+ nativeSwappablePss = other.nativeSwappablePss;
+ nativeRss = other.nativeRss;
+ nativePrivateDirty = other.nativePrivateDirty;
+ nativeSharedDirty = other.nativeSharedDirty;
+ nativePrivateClean = other.nativePrivateClean;
+ nativeSharedClean = other.nativeSharedClean;
+ nativeSwappedOut = other.nativeSwappedOut;
+ nativeSwappedOutPss = other.nativeSwappedOutPss;
+
+ otherPss = other.otherPss;
+ otherSwappablePss = other.otherSwappablePss;
+ otherRss = other.otherRss;
+ otherPrivateDirty = other.otherPrivateDirty;
+ otherSharedDirty = other.otherSharedDirty;
+ otherPrivateClean = other.otherPrivateClean;
+ otherSharedClean = other.otherSharedClean;
+ otherSwappedOut = other.otherSwappedOut;
+ otherSwappedOutPss = other.otherSwappedOutPss;
+
+ hasSwappedOutPss = other.hasSwappedOutPss;
+
+ System.arraycopy(other.otherStats, 0, otherStats, 0, otherStats.length);
+ }
+
+ /**
* Return total PSS memory usage in kB.
*/
public int getTotalPss() {
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 638b3ea71d83..26367c200a94 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -602,7 +602,7 @@ static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid,
struct graphics_memory_pss graphics_mem;
if (read_memtrack_memory(pid, &graphics_mem) == 0) {
- pss = uss = memtrack = graphics_mem.graphics + graphics_mem.gl + graphics_mem.other;
+ pss = uss = rss = memtrack = graphics_mem.graphics + graphics_mem.gl + graphics_mem.other;
}
{
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 9bf72fb86cd6..2c8f2fcd8af1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -67,6 +67,7 @@ final class ActivityManagerConstants extends ContentObserver {
static final String KEY_BOUND_SERVICE_CRASH_RESTART_DURATION = "service_crash_restart_duration";
static final String KEY_BOUND_SERVICE_CRASH_MAX_RETRY = "service_crash_max_retry";
static final String KEY_PROCESS_START_ASYNC = "process_start_async";
+ static final String KEY_MEMORY_INFO_THROTTLE_TIME = "memory_info_throttle_time";
private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
@@ -95,7 +96,7 @@ final class ActivityManagerConstants extends ContentObserver {
private static final long DEFAULT_BOUND_SERVICE_CRASH_RESTART_DURATION = 30*60_000;
private static final int DEFAULT_BOUND_SERVICE_CRASH_MAX_RETRY = 16;
private static final boolean DEFAULT_PROCESS_START_ASYNC = true;
-
+ private static final long DEFAULT_MEMORY_INFO_THROTTLE_TIME = 5*60*1000;
// Maximum number of cached processes we will allow.
public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
@@ -207,6 +208,10 @@ final class ActivityManagerConstants extends ContentObserver {
// Indicates if the processes need to be started asynchronously.
public boolean FLAG_PROCESS_START_ASYNC = DEFAULT_PROCESS_START_ASYNC;
+ // The minimum time we allow between requests for the MemoryInfo of a process to
+ // throttle requests from apps.
+ public long MEMORY_INFO_THROTTLE_TIME = DEFAULT_MEMORY_INFO_THROTTLE_TIME;
+
// Indicates whether the activity starts logging is enabled.
// Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED
boolean mFlagActivityStartsLoggingEnabled;
@@ -348,6 +353,8 @@ final class ActivityManagerConstants extends ContentObserver {
DEFAULT_BOUND_SERVICE_CRASH_MAX_RETRY);
FLAG_PROCESS_START_ASYNC = mParser.getBoolean(KEY_PROCESS_START_ASYNC,
DEFAULT_PROCESS_START_ASYNC);
+ MEMORY_INFO_THROTTLE_TIME = mParser.getLong(KEY_MEMORY_INFO_THROTTLE_TIME,
+ DEFAULT_MEMORY_INFO_THROTTLE_TIME);
updateMaxCachedProcesses();
}
@@ -423,6 +430,14 @@ final class ActivityManagerConstants extends ContentObserver {
pw.println(MAX_SERVICE_INACTIVITY);
pw.print(" "); pw.print(KEY_BG_START_TIMEOUT); pw.print("=");
pw.println(BG_START_TIMEOUT);
+ pw.print(" "); pw.print(KEY_BOUND_SERVICE_CRASH_RESTART_DURATION); pw.print("=");
+ pw.println(BOUND_SERVICE_CRASH_RESTART_DURATION);
+ pw.print(" "); pw.print(KEY_BOUND_SERVICE_CRASH_MAX_RETRY); pw.print("=");
+ pw.println(BOUND_SERVICE_MAX_CRASH_RETRY);
+ pw.print(" "); pw.print(KEY_PROCESS_START_ASYNC); pw.print("=");
+ pw.println(FLAG_PROCESS_START_ASYNC);
+ pw.print(" "); pw.print(KEY_MEMORY_INFO_THROTTLE_TIME); pw.print("=");
+ pw.println(MEMORY_INFO_THROTTLE_TIME);
pw.println();
if (mOverrideMaxCachedProcesses >= 0) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a8269824da0e..82805eda1562 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5196,27 +5196,56 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids) {
enforceNotIsolatedCaller("getProcessMemoryInfo");
+
+ final long now = SystemClock.uptimeMillis();
+ final long lastNow = now - mConstants.MEMORY_INFO_THROTTLE_TIME;
+
+ final int callingPid = Binder.getCallingPid();
+ final int callingUid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(callingUid);
+ final boolean allUsers = ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL,
+ callingUid) == PackageManager.PERMISSION_GRANTED;
+ // Check REAL_GET_TASKS to see if they are allowed to access other uids
+ final boolean allUids = mAtmInternal.isGetTasksAllowed(
+ "getProcessMemoryInfo", callingPid, callingUid);
+
Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
for (int i=pids.length-1; i>=0; i--) {
- ProcessRecord proc;
- int oomAdj;
+ infos[i] = new Debug.MemoryInfo();
+ final ProcessRecord proc;
+ final int oomAdj;
synchronized (this) {
synchronized (mPidsSelfLocked) {
proc = mPidsSelfLocked.get(pids[i]);
oomAdj = proc != null ? proc.setAdj : 0;
}
}
- infos[i] = new Debug.MemoryInfo();
- long startTime = SystemClock.currentThreadTimeMillis();
- Debug.getMemoryInfo(pids[i], infos[i]);
- long endTime = SystemClock.currentThreadTimeMillis();
+ if (!allUids || (!allUsers && (proc == null
+ || UserHandle.getUserId(proc.uid) != userId))) {
+ // The caller is not allow to get information about this other process...
+ // just leave it empty.
+ continue;
+ }
+ if (proc != null && proc.lastMemInfoTime >= lastNow && proc.lastMemInfo != null) {
+ // It hasn't been long enough that we want to take another sample; return
+ // the last one.
+ infos[i].set(proc.lastMemInfo);
+ continue;
+ }
+ final long startTime = SystemClock.currentThreadTimeMillis();
+ final Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
+ Debug.getMemoryInfo(pids[i], memInfo);
+ final long endTime = SystemClock.currentThreadTimeMillis();
+ infos[i].set(memInfo);
if (proc != null) {
synchronized (this) {
+ proc.lastMemInfo = memInfo;
+ proc.lastMemInfoTime = SystemClock.uptimeMillis();
if (proc.thread != null && proc.setAdj == oomAdj) {
// Record this for posterity if the process has been stable.
proc.baseProcessTracker.addPss(infos[i].getTotalPss(),
infos[i].getTotalUss(), infos[i].getTotalRss(), false,
- ProcessStats.ADD_PSS_EXTERNAL_SLOW, endTime-startTime,
+ ProcessStats.ADD_PSS_EXTERNAL_SLOW, endTime - startTime,
proc.pkgList.mPkgList);
for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) {
ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg);
@@ -5241,6 +5270,16 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public long[] getProcessPss(int[] pids) {
enforceNotIsolatedCaller("getProcessPss");
+
+ final int callingPid = Binder.getCallingPid();
+ final int callingUid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(callingUid);
+ final boolean allUsers = ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL,
+ callingUid) == PackageManager.PERMISSION_GRANTED;
+ // Check REAL_GET_TASKS to see if they are allowed to access other uids
+ final boolean allUids = mAtmInternal.isGetTasksAllowed(
+ "getProcessPss", callingPid, callingUid);
+
long[] pss = new long[pids.length];
for (int i=pids.length-1; i>=0; i--) {
ProcessRecord proc;
@@ -5251,6 +5290,11 @@ public class ActivityManagerService extends IActivityManager.Stub
oomAdj = proc != null ? proc.setAdj : 0;
}
}
+ if (!allUids || (!allUsers && UserHandle.getUserId(proc.uid) != userId)) {
+ // The caller is not allow to get information about this other process...
+ // just leave it empty.
+ continue;
+ }
long[] tmpUss = new long[3];
long startTime = SystemClock.currentThreadTimeMillis();
pss[i] = Debug.getPss(pids[i], tmpUss, null);
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 8c552b98698a..144f18b219dc 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -20,6 +20,7 @@ import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import android.os.Debug;
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.EventLog;
@@ -207,6 +208,11 @@ final class ProcessRecord implements WindowProcessListener {
Object adjTarget; // Debugging: target component impacting oom_adj.
Runnable crashHandler; // Optional local handler to be invoked in the process crash.
+ // Cache of last retrieve memory info and uptime, to throttle how frequently
+ // apps can requyest it.
+ Debug.MemoryInfo lastMemInfo;
+ long lastMemInfoTime;
+
// Controller for driving the process state on the window manager side.
final private WindowProcessController mWindowProcessController;
// all ServiceRecord running in this process