summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2011-08-05 17:50:29 -0700
committerDianne Hackborn <hackbod@google.com>2011-08-05 18:18:05 -0700
commitb437e090ec03a2bab10bdfcb9484577a7f34e157 (patch)
tree86424e259db63fb8c7780a433b2eb808950fbc49
parent284585aa835096111c7129b330f458b75ed27a8d (diff)
downloadframeworks_base-b437e090ec03a2bab10bdfcb9484577a7f34e157.zip
frameworks_base-b437e090ec03a2bab10bdfcb9484577a7f34e157.tar.gz
frameworks_base-b437e090ec03a2bab10bdfcb9484577a7f34e157.tar.bz2
Improved memory use reporting.
Change-Id: I38e53e6228bba92a142bafeedb5af8df4e4e5724
-rw-r--r--api/current.txt1
-rw-r--r--core/java/android/app/ActivityManagerNative.java22
-rw-r--r--core/java/android/app/ActivityThread.java34
-rw-r--r--core/java/android/app/ApplicationThreadNative.java9
-rw-r--r--core/java/android/app/IActivityManager.java5
-rw-r--r--core/java/android/app/IApplicationThread.java3
-rw-r--r--core/java/android/os/Debug.java12
-rw-r--r--core/jni/android_os_Debug.cpp37
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java142
9 files changed, 214 insertions, 51 deletions
diff --git a/api/current.txt b/api/current.txt
index 035da89..a70e8a2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -14095,6 +14095,7 @@ package android.os {
method public static long getNativeHeapAllocatedSize();
method public static long getNativeHeapFreeSize();
method public static long getNativeHeapSize();
+ method public static long getPss();
method public static int getThreadAllocCount();
method public static int getThreadAllocSize();
method public static deprecated int getThreadExternalAllocCount();
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index b7cd829..a73e10a 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1523,6 +1523,15 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case GET_PROCESS_PSS_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ int[] pids = data.createIntArray();
+ long[] pss = getProcessPss(pids);
+ reply.writeNoException();
+ reply.writeLongArray(pss);
+ return true;
+ }
+
}
return super.onTransact(code, data, reply, flags);
@@ -3432,5 +3441,18 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
}
+ public long[] getProcessPss(int[] pids) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeIntArray(pids);
+ mRemote.transact(GET_PROCESS_PSS_TRANSACTION, data, reply, 0);
+ reply.readException();
+ long[] res = reply.createLongArray();
+ data.recycle();
+ reply.recycle();
+ return res;
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index c566104..d5f630a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -729,17 +729,19 @@ public final class ActivityThread {
}
@Override
- public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, String[] args) {
+ public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, boolean checkin,
+ boolean all, String[] args) {
FileOutputStream fout = new FileOutputStream(fd);
PrintWriter pw = new PrintWriter(fout);
try {
- return dumpMemInfo(pw, args);
+ return dumpMemInfo(pw, checkin, all, args);
} finally {
pw.flush();
}
}
- private Debug.MemoryInfo dumpMemInfo(PrintWriter pw, String[] args) {
+ private Debug.MemoryInfo dumpMemInfo(PrintWriter pw, boolean checkin, boolean all,
+ String[] args) {
long nativeMax = Debug.getNativeHeapSize() / 1024;
long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024;
long nativeFree = Debug.getNativeHeapFreeSize() / 1024;
@@ -747,6 +749,10 @@ public final class ActivityThread {
Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
Debug.getMemoryInfo(memInfo);
+ if (!all) {
+ return memInfo;
+ }
+
Runtime runtime = Runtime.getRuntime();
long dalvikMax = runtime.totalMemory() / 1024;
@@ -765,16 +771,8 @@ public final class ActivityThread {
long sqliteAllocated = SQLiteDebug.getHeapAllocatedSize() / 1024;
SQLiteDebug.PagerStats stats = SQLiteDebug.getDatabaseInfo();
- // Check to see if we were called by checkin server. If so, print terse format.
- boolean doCheckinFormat = false;
- if (args != null) {
- for (String arg : args) {
- if ("-c".equals(arg)) doCheckinFormat = true;
- }
- }
-
// For checkin, we print one long comma-separated list of values
- if (doCheckinFormat) {
+ if (checkin) {
// NOTE: if you change anything significant below, also consider changing
// ACTIVITY_THREAD_CHECKIN_VERSION.
String processName = (mBoundApplication != null)
@@ -841,13 +839,17 @@ public final class ActivityThread {
pw.print(sqliteAllocated); pw.print(',');
pw.print(stats.memoryUsed / 1024); pw.print(',');
pw.print(stats.pageCacheOverflo / 1024); pw.print(',');
- pw.print(stats.largestMemAlloc / 1024); pw.print(',');
+ pw.print(stats.largestMemAlloc / 1024);
for (int i = 0; i < stats.dbStats.size(); i++) {
DbStats dbStats = stats.dbStats.get(i);
- printRow(pw, DB_INFO_FORMAT, dbStats.pageSize, dbStats.dbSize,
- dbStats.lookaside, dbStats.cache, dbStats.dbName);
- pw.print(',');
+ pw.print(','); pw.print(dbStats.dbName);
+ pw.print(','); pw.print(dbStats.pageSize);
+ pw.print(','); pw.print(dbStats.dbSize);
+ pw.print(','); pw.print(dbStats.lookaside);
+ pw.print(','); pw.print(dbStats.cache);
+ pw.print(','); pw.print(dbStats.cache);
}
+ pw.println();
return memInfo;
}
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 9a5b527..bea057e 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -491,11 +491,13 @@ public abstract class ApplicationThreadNative extends Binder
{
data.enforceInterface(IApplicationThread.descriptor);
ParcelFileDescriptor fd = data.readFileDescriptor();
+ boolean checkin = data.readInt() != 0;
+ boolean all = data.readInt() != 0;
String[] args = data.readStringArray();
Debug.MemoryInfo mi = null;
if (fd != null) {
try {
- mi = dumpMemInfo(fd.getFileDescriptor(), args);
+ mi = dumpMemInfo(fd.getFileDescriptor(), checkin, all, args);
} finally {
try {
fd.close();
@@ -1049,11 +1051,14 @@ class ApplicationThreadProxy implements IApplicationThread {
IBinder.FLAG_ONEWAY);
}
- public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, String[] args) throws RemoteException {
+ public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, boolean checkin, boolean all,
+ String[] args) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeFileDescriptor(fd);
+ data.writeInt(checkin ? 1 : 0);
+ data.writeInt(all ? 1 : 0);
data.writeStringArray(args);
mRemote.transact(DUMP_MEM_INFO_TRANSACTION, data, reply, 0);
reply.readException();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 64d77e8..b1b0583 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -364,7 +364,9 @@ public interface IActivityManager extends IInterface {
public boolean isIntentSenderTargetedToPackage(IIntentSender sender) throws RemoteException;
public void updatePersistentConfiguration(Configuration values) throws RemoteException;
-
+
+ public long[] getProcessPss(int[] pids) throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -593,4 +595,5 @@ public interface IActivityManager extends IInterface {
int UNREGISTER_PROCESS_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+133;
int IS_INTENT_SENDER_TARGETED_TO_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+134;
int UPDATE_PERSISTENT_CONFIGURATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+135;
+ int GET_PROCESS_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+136;
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index d0607d0..3a8eb28 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -120,7 +120,8 @@ public interface IApplicationThread extends IInterface {
void setCoreSettings(Bundle coreSettings) throws RemoteException;
void updatePackageCompatibilityInfo(String pkg, CompatibilityInfo info) throws RemoteException;
void scheduleTrimMemory(int level) throws RemoteException;
- Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, String[] args) throws RemoteException;
+ Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, boolean checkin, boolean all,
+ String[] args) throws RemoteException;
void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException;
String descriptor = "android.app.IApplicationThread";
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index da2afb6..20a731e 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -818,6 +818,18 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
public static native void getMemoryInfo(int pid, MemoryInfo memoryInfo);
/**
+ * Retrieves the PSS memory used by the process as given by the
+ * smaps.
+ */
+ public static native long getPss();
+
+ /**
+ * Retrieves the PSS memory used by the process as given by the
+ * smaps. @hide
+ */
+ public static native long getPss(int pid);
+
+ /**
* Establish an object allocation limit in the current thread.
* This feature was never enabled in release builds. The
* allocation limits feature was removed in Honeycomb. This
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 3a3f07e..85fac5f 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -279,6 +279,39 @@ static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject o
android_os_Debug_getDirtyPagesPid(env, clazz, getpid(), object);
}
+static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid)
+{
+ char line[1024];
+ jlong pss = 0;
+ unsigned temp;
+
+ char tmp[128];
+ FILE *fp;
+
+ sprintf(tmp, "/proc/%d/smaps", pid);
+ fp = fopen(tmp, "r");
+ if (fp == 0) return 0;
+
+ while (true) {
+ if (fgets(line, 1024, fp) == 0) {
+ break;
+ }
+
+ if (sscanf(line, "Pss: %d kB", &temp) == 1) {
+ pss += temp;
+ }
+ }
+
+ fclose(fp);
+
+ return pss;
+}
+
+static jlong android_os_Debug_getPss(JNIEnv *env, jobject clazz)
+{
+ return android_os_Debug_getPssPid(env, clazz, getpid());
+}
+
static jint read_binder_stat(const char* stat)
{
FILE* fp = fopen(BINDER_STATS, "r");
@@ -520,6 +553,10 @@ static JNINativeMethod gMethods[] = {
(void*) android_os_Debug_getDirtyPages },
{ "getMemoryInfo", "(ILandroid/os/Debug$MemoryInfo;)V",
(void*) android_os_Debug_getDirtyPagesPid },
+ { "getPss", "()J",
+ (void*) android_os_Debug_getPss },
+ { "getPss", "(I)J",
+ (void*) android_os_Debug_getPssPid },
{ "dumpNativeHeap", "(Ljava/io/FileDescriptor;)V",
(void*) android_os_Debug_dumpNativeHeap },
{ "getBinderSentTransactions", "()I",
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 14c6306..ba8b58b 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -3317,6 +3317,14 @@ public final class ActivityManagerService extends ActivityManagerNative
return infos;
}
+ public long[] getProcessPss(int[] pids) throws RemoteException {
+ long[] pss = new long[pids.length];
+ for (int i=pids.length-1; i>=0; i--) {
+ pss[i] = Debug.getPss(pids[i]);
+ }
+ return pss;
+ }
+
public void killApplicationProcess(String processName, int uid) {
if (processName == null) {
return;
@@ -8868,15 +8876,15 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- ArrayList<ProcessRecord> collectProcesses(PrintWriter pw, String[] args) {
+ ArrayList<ProcessRecord> collectProcesses(PrintWriter pw, int start, String[] args) {
ArrayList<ProcessRecord> procs;
synchronized (this) {
- if (args != null && args.length > 0
- && args[0].charAt(0) != '-') {
+ if (args != null && args.length > start
+ && args[start].charAt(0) != '-') {
procs = new ArrayList<ProcessRecord>();
int pid = -1;
try {
- pid = Integer.parseInt(args[0]);
+ pid = Integer.parseInt(args[start]);
} catch (NumberFormatException e) {
}
@@ -8884,12 +8892,12 @@ public final class ActivityManagerService extends ActivityManagerNative
ProcessRecord proc = mLruProcesses.get(i);
if (proc.pid == pid) {
procs.add(proc);
- } else if (proc.processName.equals(args[0])) {
+ } else if (proc.processName.equals(args[start])) {
procs.add(proc);
}
}
if (procs.size() <= 0) {
- pw.println("No process found for: " + args[0]);
+ pw.println("No process found for: " + args[start]);
return null;
}
} else {
@@ -8901,7 +8909,7 @@ public final class ActivityManagerService extends ActivityManagerNative
final void dumpGraphicsHardwareUsage(FileDescriptor fd,
PrintWriter pw, String[] args) {
- ArrayList<ProcessRecord> procs = collectProcesses(pw, args);
+ ArrayList<ProcessRecord> procs = collectProcesses(pw, 0, args);
if (procs == null) {
return;
}
@@ -8945,18 +8953,21 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- final void dumpMemItems(PrintWriter pw, String prefix, ArrayList<MemItem> items) {
- Collections.sort(items, new Comparator<MemItem>() {
- @Override
- public int compare(MemItem lhs, MemItem rhs) {
- if (lhs.pss < rhs.pss) {
- return 1;
- } else if (lhs.pss > rhs.pss) {
- return -1;
+ final void dumpMemItems(PrintWriter pw, String prefix, ArrayList<MemItem> items,
+ boolean sort) {
+ if (sort) {
+ Collections.sort(items, new Comparator<MemItem>() {
+ @Override
+ public int compare(MemItem lhs, MemItem rhs) {
+ if (lhs.pss < rhs.pss) {
+ return 1;
+ } else if (lhs.pss > rhs.pss) {
+ return -1;
+ }
+ return 0;
}
- return 0;
- }
- });
+ });
+ }
for (int i=0; i<items.size(); i++) {
MemItem mi = items.get(i);
@@ -8966,7 +8977,29 @@ public final class ActivityManagerService extends ActivityManagerNative
final void dumpApplicationMemoryUsage(FileDescriptor fd,
PrintWriter pw, String prefix, String[] args) {
- ArrayList<ProcessRecord> procs = collectProcesses(pw, args);
+ boolean dumpAll = false;
+
+ int opti = 0;
+ while (opti < args.length) {
+ String opt = args[opti];
+ if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
+ break;
+ }
+ opti++;
+ if ("-a".equals(opt)) {
+ dumpAll = true;
+ } else if ("-h".equals(opt)) {
+ pw.println("meminfo dump options: [-a] [process]");
+ pw.println(" -a: include all available information for each process.");
+ pw.println("If [process] is specified it can be the name or ");
+ pw.println("pid of a specific process to dump.");
+ return;
+ } else {
+ pw.println("Unknown argument: " + opt + "; use -h for help");
+ }
+ }
+
+ ArrayList<ProcessRecord> procs = collectProcesses(pw, opti, args);
if (procs == null) {
return;
}
@@ -8974,7 +9007,11 @@ public final class ActivityManagerService extends ActivityManagerNative
final boolean isCheckinRequest = scanArgs(args, "--checkin");
long uptime = SystemClock.uptimeMillis();
long realtime = SystemClock.elapsedRealtime();
-
+
+ if (procs.size() == 1 || isCheckinRequest) {
+ dumpAll = true;
+ }
+
if (isCheckinRequest) {
// short checkin version
pw.println(uptime + "," + realtime);
@@ -8984,29 +9021,53 @@ public final class ActivityManagerService extends ActivityManagerNative
pw.println("Uptime: " + uptime + " Realtime: " + realtime);
}
+ String[] innerArgs = new String[args.length-opti];
+ System.arraycopy(args, opti, innerArgs, 0, args.length-opti);
+
ArrayList<MemItem> procMems = new ArrayList<MemItem>();
long nativePss=0, dalvikPss=0, otherPss=0;
long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
+ final int[] oomAdj = new int[] {
+ SYSTEM_ADJ, CORE_SERVER_ADJ, FOREGROUND_APP_ADJ,
+ VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ, HEAVY_WEIGHT_APP_ADJ,
+ BACKUP_APP_ADJ, SECONDARY_SERVER_ADJ, HOME_APP_ADJ, EMPTY_APP_ADJ
+ };
+ final String[] oomLabel = new String[] {
+ "System", "Persistent", "Foreground",
+ "Visible", "Perceptible", "Heavy Weight",
+ "Backup", "Services", "Home", "Background"
+ };
+ long oomPss[] = new long[oomLabel.length];
+
+ long totalPss = 0;
+
for (int i = procs.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = procs.get(i);
if (r.thread != null) {
- if (!isCheckinRequest) {
+ if (!isCheckinRequest && dumpAll) {
pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
pw.flush();
}
Debug.MemoryInfo mi = null;
- try {
- mi = r.thread.dumpMemInfo(fd, args);
- } catch (RemoteException e) {
- if (!isCheckinRequest) {
- pw.println("Got RemoteException!");
- pw.flush();
+ if (dumpAll) {
+ try {
+ mi = r.thread.dumpMemInfo(fd, isCheckinRequest, dumpAll, innerArgs);
+ } catch (RemoteException e) {
+ if (!isCheckinRequest) {
+ pw.println("Got RemoteException!");
+ pw.flush();
+ }
}
+ } else {
+ mi = new Debug.MemoryInfo();
+ Debug.getMemoryInfo(r.pid, mi);
}
+
if (!isCheckinRequest && mi != null) {
- procMems.add(new MemItem(r.processName + " (pid " + r.pid + ")",
- mi.getTotalPss()));
+ long myTotalPss = mi.getTotalPss();
+ totalPss += myTotalPss;
+ procMems.add(new MemItem(r.processName + " (pid " + r.pid + ")", myTotalPss));
nativePss += mi.nativePss;
dalvikPss += mi.dalvikPss;
@@ -9016,6 +9077,13 @@ public final class ActivityManagerService extends ActivityManagerNative
miscPss[j] += mem;
otherPss -= mem;
}
+
+ for (int oomIndex=0; oomIndex<oomPss.length; oomIndex++) {
+ if (r.setAdj <= oomAdj[oomIndex] || oomIndex == (oomPss.length-1)) {
+ oomPss[oomIndex] += myTotalPss;
+ break;
+ }
+ }
}
}
}
@@ -9030,12 +9098,24 @@ public final class ActivityManagerService extends ActivityManagerNative
catMems.add(new MemItem(Debug.MemoryInfo.getOtherLabel(j), miscPss[j]));
}
+ ArrayList<MemItem> oomMems = new ArrayList<MemItem>();
+ for (int j=0; j<oomPss.length; j++) {
+ if (oomPss[j] != 0) {
+ oomMems.add(new MemItem(oomLabel[j], oomPss[j]));
+ }
+ }
+
pw.println();
pw.println("Total PSS by process:");
- dumpMemItems(pw, " ", procMems);
+ dumpMemItems(pw, " ", procMems, true);
+ pw.println();
+ pw.println("Total PSS by OOM adjustment:");
+ dumpMemItems(pw, " ", oomMems, false);
pw.println();
pw.println("Total PSS by category:");
- dumpMemItems(pw, " ", catMems);
+ dumpMemItems(pw, " ", catMems, true);
+ pw.println();
+ pw.print("Total PSS: "); pw.print(totalPss); pw.println(" Kb");
}
}