summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/ActivityThread.java98
-rw-r--r--core/java/android/app/ApplicationThreadNative.java66
-rw-r--r--core/java/android/app/IApplicationThread.java4
-rw-r--r--core/java/android/os/Debug.java39
-rw-r--r--core/jni/android_os_Debug.cpp219
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java84
6 files changed, 378 insertions, 132 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 8994b1761ece..c6a746b237f1 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -413,10 +413,10 @@ public final class ActivityThread {
native private void dumpGraphicsInfo(FileDescriptor fd);
private final class ApplicationThread extends ApplicationThreadNative {
- private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s";
- private static final String ONE_COUNT_COLUMN = "%17s %8d";
- private static final String TWO_COUNT_COLUMNS = "%17s %8d %17s %8d";
- private static final String TWO_COUNT_COLUMNS_DB = "%20s %8d %20s %8d";
+ private static final String HEAP_COLUMN = "%13s %8s %8s %8s %8s %8s %8s";
+ private static final String ONE_COUNT_COLUMN = "%21s %8d";
+ private static final String TWO_COUNT_COLUMNS = "%21s %8d %21s %8d";
+ private static final String TWO_COUNT_COLUMNS_DB = "%21s %8d %21s %8d";
private static final String DB_INFO_FORMAT = " %8s %8s %14s %14s %s";
// Formatting for checkin service - update version if row format changes
@@ -729,12 +729,17 @@ public final class ActivityThread {
}
@Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (args != null && args.length == 1 && args[0].equals("graphics")) {
+ public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, String[] args) {
+ FileOutputStream fout = new FileOutputStream(fd);
+ PrintWriter pw = new PrintWriter(fout);
+ try {
+ return dumpMemInfo(fd, pw, args);
+ } finally {
pw.flush();
- dumpGraphicsInfo(fd);
- return;
}
+ }
+
+ private Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, PrintWriter pw, String[] args) {
long nativeMax = Debug.getNativeHeapSize() / 1024;
long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024;
long nativeFree = Debug.getNativeHeapFreeSize() / 1024;
@@ -742,14 +747,6 @@ public final class ActivityThread {
Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
Debug.getMemoryInfo(memInfo);
- final int nativeShared = memInfo.nativeSharedDirty;
- final int dalvikShared = memInfo.dalvikSharedDirty;
- final int otherShared = memInfo.otherSharedDirty;
-
- final int nativePrivate = memInfo.nativePrivateDirty;
- final int dalvikPrivate = memInfo.dalvikPrivateDirty;
- final int otherPrivate = memInfo.otherPrivateDirty;
-
Runtime runtime = Runtime.getRuntime();
long dalvikMax = runtime.totalMemory() / 1024;
@@ -813,16 +810,18 @@ public final class ActivityThread {
pw.print(memInfo.nativePss + memInfo.dalvikPss + memInfo.otherPss); pw.print(',');
// Heap info - shared
- pw.print(nativeShared); pw.print(',');
- pw.print(dalvikShared); pw.print(',');
- pw.print(otherShared); pw.print(',');
- pw.print(nativeShared + dalvikShared + otherShared); pw.print(',');
+ pw.print(memInfo.nativeSharedDirty); pw.print(',');
+ pw.print(memInfo.dalvikSharedDirty); pw.print(',');
+ pw.print(memInfo.otherSharedDirty); pw.print(',');
+ pw.print(memInfo.nativeSharedDirty + memInfo.dalvikSharedDirty
+ + memInfo.otherSharedDirty); pw.print(',');
// Heap info - private
- pw.print(nativePrivate); pw.print(',');
- pw.print(dalvikPrivate); pw.print(',');
- pw.print(otherPrivate); pw.print(',');
- pw.print(nativePrivate + dalvikPrivate + otherPrivate); pw.print(',');
+ pw.print(memInfo.nativePrivateDirty); pw.print(',');
+ pw.print(memInfo.dalvikPrivateDirty); pw.print(',');
+ pw.print(memInfo.otherPrivateDirty); pw.print(',');
+ pw.print(memInfo.nativePrivateDirty + memInfo.dalvikPrivateDirty
+ + memInfo.otherPrivateDirty); pw.print(',');
// Object counts
pw.print(viewInstanceCount); pw.print(',');
@@ -850,24 +849,38 @@ public final class ActivityThread {
pw.print(',');
}
- return;
+ return memInfo;
}
// otherwise, show human-readable format
- printRow(pw, HEAP_COLUMN, "", "native", "dalvik", "other", "total");
- printRow(pw, HEAP_COLUMN, "size:", nativeMax, dalvikMax, "N/A", nativeMax + dalvikMax);
- printRow(pw, HEAP_COLUMN, "allocated:", nativeAllocated, dalvikAllocated, "N/A",
- nativeAllocated + dalvikAllocated);
- printRow(pw, HEAP_COLUMN, "free:", nativeFree, dalvikFree, "N/A",
- nativeFree + dalvikFree);
-
- printRow(pw, HEAP_COLUMN, "(Pss):", memInfo.nativePss, memInfo.dalvikPss,
- memInfo.otherPss, memInfo.nativePss + memInfo.dalvikPss + memInfo.otherPss);
-
- printRow(pw, HEAP_COLUMN, "(shared dirty):", nativeShared, dalvikShared, otherShared,
- nativeShared + dalvikShared + otherShared);
- printRow(pw, HEAP_COLUMN, "(priv dirty):", nativePrivate, dalvikPrivate, otherPrivate,
- nativePrivate + dalvikPrivate + otherPrivate);
+ printRow(pw, HEAP_COLUMN, "", "", "Shared", "Private", "Heap", "Heap", "Heap");
+ printRow(pw, HEAP_COLUMN, "", "Pss", "Dirty", "Dirty", "Size", "Alloc", "Free");
+ printRow(pw, HEAP_COLUMN, "", "------", "------", "------", "------", "------",
+ "------");
+ printRow(pw, HEAP_COLUMN, "Native", memInfo.nativePss, memInfo.nativeSharedDirty,
+ memInfo.nativePrivateDirty, nativeMax, nativeAllocated, nativeFree);
+ printRow(pw, HEAP_COLUMN, "Dalvik", memInfo.dalvikPss, memInfo.dalvikSharedDirty,
+ memInfo.dalvikPrivateDirty, dalvikMax, dalvikAllocated, dalvikFree);
+
+ int otherPss = memInfo.otherPss;
+ int otherSharedDirty = memInfo.otherSharedDirty;
+ int otherPrivateDirty = memInfo.otherPrivateDirty;
+
+ for (int i=0; i<Debug.MemoryInfo.NUM_OTHER_STATS; i++) {
+ printRow(pw, HEAP_COLUMN, memInfo.getOtherLabel(i),
+ memInfo.getOtherPss(i), memInfo.getOtherSharedDirty(i),
+ memInfo.getOtherPrivateDirty(i), "", "", "");
+ otherPss -= memInfo.getOtherPss(i);
+ otherSharedDirty -= memInfo.getOtherSharedDirty(i);
+ otherPrivateDirty -= memInfo.getOtherPrivateDirty(i);
+ }
+
+ printRow(pw, HEAP_COLUMN, "Unknown", otherPss, otherSharedDirty,
+ otherPrivateDirty, "", "", "");
+ printRow(pw, HEAP_COLUMN, "TOTAL", memInfo.getTotalPss(),
+ memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(),
+ nativeMax+dalvikMax, nativeAllocated+dalvikAllocated,
+ nativeFree+dalvikFree);
pw.println(" ");
pw.println(" Objects");
@@ -916,6 +929,13 @@ public final class ActivityThread {
pw.println(" Asset Allocations");
pw.print(assetAlloc);
}
+
+ return memInfo;
+ }
+
+ @Override
+ public void dumpGfxInfo(FileDescriptor fd, String[] args) {
+ dumpGraphicsInfo(fd);
}
private void printRow(PrintWriter pw, String format, Object...objs) {
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 16181e0e8742..942f245bebf8 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -485,6 +485,48 @@ public abstract class ApplicationThreadNative extends Binder
scheduleTrimMemory(level);
return true;
}
+
+ case DUMP_MEM_INFO_TRANSACTION:
+ {
+ data.enforceInterface(IApplicationThread.descriptor);
+ ParcelFileDescriptor fd = data.readFileDescriptor();
+ String[] args = data.readStringArray();
+ Debug.MemoryInfo mi = null;
+ if (fd != null) {
+ try {
+ mi = dumpMemInfo(fd.getFileDescriptor(), args);
+ } finally {
+ try {
+ fd.close();
+ } catch (IOException e) {
+ // swallowed, not propagated back to the caller
+ }
+ }
+ }
+ reply.writeNoException();
+ mi.writeToParcel(reply, 0);
+ return true;
+ }
+
+ case DUMP_GFX_INFO_TRANSACTION:
+ {
+ data.enforceInterface(IApplicationThread.descriptor);
+ ParcelFileDescriptor fd = data.readFileDescriptor();
+ String[] args = data.readStringArray();
+ if (fd != null) {
+ try {
+ dumpGfxInfo(fd.getFileDescriptor(), args);
+ } finally {
+ try {
+ fd.close();
+ } catch (IOException e) {
+ // swallowed, not propagated back to the caller
+ }
+ }
+ }
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -1004,4 +1046,28 @@ class ApplicationThreadProxy implements IApplicationThread {
mRemote.transact(SCHEDULE_TRIM_MEMORY_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
}
+
+ public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, String[] args) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeFileDescriptor(fd);
+ data.writeStringArray(args);
+ mRemote.transact(DUMP_MEM_INFO_TRANSACTION, data, reply, 0);
+ reply.readException();
+ Debug.MemoryInfo info = new Debug.MemoryInfo();
+ info.readFromParcel(reply);
+ data.recycle();
+ reply.recycle();
+ return info;
+ }
+
+ public void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeFileDescriptor(fd);
+ data.writeStringArray(args);
+ mRemote.transact(DUMP_GFX_INFO_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
+ data.recycle();
+ }
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 94c2c86739da..9de0bf4ffa0e 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -120,6 +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;
+ void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException;
String descriptor = "android.app.IApplicationThread";
@@ -164,4 +166,6 @@ public interface IApplicationThread extends IInterface {
int SET_CORE_SETTINGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+39;
int UPDATE_PACKAGE_COMPATIBILITY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+40;
int SCHEDULE_TRIM_MEMORY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+41;
+ int DUMP_MEM_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+42;
+ int DUMP_GFX_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+43;
}
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index ba692469d9f5..da2afb6e5c06 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -129,6 +129,11 @@ public final class Debug
/** The shared dirty pages used by everything else. */
public int otherSharedDirty;
+ /** @hide */
+ public static final int NUM_OTHER_STATS = 9;
+
+ private int[] otherStats = new int[NUM_OTHER_STATS*3];
+
public MemoryInfo() {
}
@@ -153,6 +158,38 @@ public final class Debug
return dalvikSharedDirty + nativeSharedDirty + otherSharedDirty;
}
+ /* @hide */
+ public int getOtherPss(int which) {
+ return otherStats[which*3];
+ }
+
+ /* @hide */
+ public int getOtherPrivateDirty(int which) {
+ return otherStats[which*3 + 1];
+ }
+
+ /* @hide */
+ public int getOtherSharedDirty(int which) {
+ return otherStats[which*3 + 2];
+ }
+
+
+ /* @hide */
+ public static String getOtherLabel(int which) {
+ switch (which) {
+ case 0: return "Cursor";
+ case 1: return "Ashmem";
+ case 2: return "Other dev";
+ case 3: return ".so mmap";
+ case 4: return ".jar mmap";
+ case 5: return ".apk mmap";
+ case 6: return ".ttf mmap";
+ case 7: return ".dex mmap";
+ case 8: return "Other mmap";
+ default: return "????";
+ }
+ }
+
public int describeContents() {
return 0;
}
@@ -167,6 +204,7 @@ public final class Debug
dest.writeInt(otherPss);
dest.writeInt(otherPrivateDirty);
dest.writeInt(otherSharedDirty);
+ dest.writeIntArray(otherStats);
}
public void readFromParcel(Parcel source) {
@@ -179,6 +217,7 @@ public final class Debug
otherPss = source.readInt();
otherPrivateDirty = source.readInt();
otherSharedDirty = source.readInt();
+ otherStats = source.createIntArray();
}
public static final Creator<MemoryInfo> CREATOR = new Creator<MemoryInfo>() {
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index a4432c38c32a..3a3f07e0dacf 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -27,6 +27,7 @@
#include <sys/time.h>
#include <errno.h>
#include <assert.h>
+#include <ctype.h>
#ifdef HAVE_MALLOC_H
#include <malloc.h>
@@ -35,28 +36,50 @@
namespace android
{
-static jfieldID dalvikPss_field;
-static jfieldID dalvikPrivateDirty_field;
-static jfieldID dalvikSharedDirty_field;
-static jfieldID nativePss_field;
-static jfieldID nativePrivateDirty_field;
-static jfieldID nativeSharedDirty_field;
-static jfieldID otherPss_field;
-static jfieldID otherPrivateDirty_field;
-static jfieldID otherSharedDirty_field;
+enum {
+ HEAP_UNKNOWN,
+ HEAP_DALVIK,
+ HEAP_NATIVE,
+ HEAP_CURSOR,
+ HEAP_ASHMEM,
+ HEAP_UNKNOWN_DEV,
+ HEAP_SO,
+ HEAP_JAR,
+ HEAP_APK,
+ HEAP_TTF,
+ HEAP_DEX,
+ HEAP_UNKNOWN_MAP,
+
+ _NUM_HEAP,
+ _NUM_CORE_HEAP = HEAP_NATIVE+1
+};
+
+struct stat_fields {
+ jfieldID pss_field;
+ jfieldID privateDirty_field;
+ jfieldID sharedDirty_field;
+};
+
+struct stat_field_names {
+ const char* pss_name;
+ const char* privateDirty_name;
+ const char* sharedDirty_name;
+};
+
+static stat_fields stat_fields[_NUM_CORE_HEAP];
+
+static stat_field_names stat_field_names[_NUM_CORE_HEAP] = {
+ { "otherPss", "otherPrivateDirty", "otherSharedDirty" },
+ { "dalvikPss", "dalvikPrivateDirty", "dalvikSharedDirty" },
+ { "nativePss", "nativePrivateDirty", "nativeSharedDirty" }
+};
+
+jfieldID otherStats_field;
struct stats_t {
- int dalvikPss;
- int dalvikPrivateDirty;
- int dalvikSharedDirty;
-
- int nativePss;
- int nativePrivateDirty;
- int nativeSharedDirty;
-
- int otherPss;
- int otherPrivateDirty;
- int otherSharedDirty;
+ int pss;
+ int privateDirty;
+ int sharedDirty;
};
#define BINDER_STATS "/proc/binder/stats"
@@ -94,48 +117,71 @@ static jlong android_os_Debug_getNativeHeapFreeSize(JNIEnv *env, jobject clazz)
static void read_mapinfo(FILE *fp, stats_t* stats)
{
char line[1024];
- int len;
+ int len, nameLen;
bool skip, done = false;
- unsigned start = 0, size = 0, resident = 0, pss = 0;
+ unsigned size = 0, resident = 0, pss = 0;
unsigned shared_clean = 0, shared_dirty = 0;
unsigned private_clean = 0, private_dirty = 0;
unsigned referenced = 0;
unsigned temp;
- int isNativeHeap;
- int isDalvikHeap;
- int isSqliteHeap;
+ unsigned long int start;
+ unsigned long int end = 0;
+ unsigned long int prevEnd = 0;
+ char* name;
+ int name_pos;
+
+ int whichHeap = HEAP_UNKNOWN;
+ int prevHeap = HEAP_UNKNOWN;
- if(fgets(line, 1024, fp) == 0) return;
+ if(fgets(line, sizeof(line), fp) == 0) return;
while (!done) {
- isNativeHeap = 0;
- isDalvikHeap = 0;
- isSqliteHeap = 0;
+ prevHeap = whichHeap;
+ prevEnd = end;
+ whichHeap = HEAP_UNKNOWN;
skip = false;
len = strlen(line);
if (len < 1) return;
line[--len] = 0;
- /* ignore guard pages */
- if (len > 18 && line[17] == '-') skip = true;
-
- start = strtoul(line, 0, 16);
-
- if (strstr(line, "[heap]")) {
- isNativeHeap = 1;
- } else if (strstr(line, "/dalvik-LinearAlloc")) {
- isDalvikHeap = 1;
- } else if (strstr(line, "/mspace/dalvik-heap")) {
- isDalvikHeap = 1;
- } else if (strstr(line, "/dalvik-heap-bitmap/")) {
- isDalvikHeap = 1;
- } else if (strstr(line, "/data/dalvik-cache/")) {
- isDalvikHeap = 1;
- } else if (strstr(line, "/tmp/sqlite-heap")) {
- isSqliteHeap = 1;
+ if (sscanf(line, "%lx-%lx %*s %*x %*x:%*x %*d%n", &start, &end, &name_pos) != 2) {
+ skip = true;
+ } else {
+ while (isspace(line[name_pos])) {
+ name_pos += 1;
+ }
+ name = line + name_pos;
+ nameLen = strlen(name);
+
+ if (strstr(name, "[heap]") == name) {
+ whichHeap = HEAP_NATIVE;
+ } else if (strstr(name, "/dev/ashmem/dalvik-") == name) {
+ whichHeap = HEAP_DALVIK;
+ } else if (strstr(name, "/dev/ashmem/CursorWindow") == name) {
+ whichHeap = HEAP_CURSOR;
+ } else if (strstr(name, "/dev/ashmem/") == name) {
+ whichHeap = HEAP_ASHMEM;
+ } else if (strstr(name, "/dev/") == name) {
+ whichHeap = HEAP_UNKNOWN_DEV;
+ } else if (nameLen > 3 && strcmp(name+nameLen-3, ".so") == 0) {
+ whichHeap = HEAP_SO;
+ } else if (nameLen > 4 && strcmp(name+nameLen-4, ".jar") == 0) {
+ whichHeap = HEAP_JAR;
+ } else if (nameLen > 4 && strcmp(name+nameLen-4, ".apk") == 0) {
+ whichHeap = HEAP_APK;
+ } else if (nameLen > 4 && strcmp(name+nameLen-4, ".ttf") == 0) {
+ whichHeap = HEAP_TTF;
+ } else if (nameLen > 4 && strcmp(name+nameLen-4, ".dex") == 0) {
+ whichHeap = HEAP_DEX;
+ } else if (nameLen > 0) {
+ whichHeap = HEAP_UNKNOWN_MAP;
+ } else if (start == prevEnd && prevHeap == HEAP_SO) {
+ // bss section of a shared library.
+ whichHeap = HEAP_SO;
+ }
}
//LOGI("native=%d dalvik=%d sqlite=%d: %s\n", isNativeHeap, isDalvikHeap,
@@ -171,21 +217,9 @@ static void read_mapinfo(FILE *fp, stats_t* stats)
}
if (!skip) {
- if (isNativeHeap) {
- stats->nativePss += pss;
- stats->nativePrivateDirty += private_dirty;
- stats->nativeSharedDirty += shared_dirty;
- } else if (isDalvikHeap) {
- stats->dalvikPss += pss;
- stats->dalvikPrivateDirty += private_dirty;
- stats->dalvikSharedDirty += shared_dirty;
- } else if ( isSqliteHeap) {
- // ignore
- } else {
- stats->otherPss += pss;
- stats->otherPrivateDirty += private_dirty;
- stats->otherSharedDirty += shared_dirty;
- }
+ stats[whichHeap].pss += pss;
+ stats[whichHeap].privateDirty += private_dirty;
+ stats[whichHeap].sharedDirty += shared_dirty;
}
}
}
@@ -206,22 +240,38 @@ static void load_maps(int pid, stats_t* stats)
static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
jint pid, jobject object)
{
- stats_t stats;
- memset(&stats, 0, sizeof(stats_t));
+ stats_t stats[_NUM_HEAP];
+ memset(&stats, 0, sizeof(stats));
- load_maps(pid, &stats);
+ load_maps(pid, stats);
+
+ for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) {
+ stats[HEAP_UNKNOWN].pss += stats[i].pss;
+ stats[HEAP_UNKNOWN].privateDirty += stats[i].privateDirty;
+ stats[HEAP_UNKNOWN].sharedDirty += stats[i].sharedDirty;
+ }
- env->SetIntField(object, dalvikPss_field, stats.dalvikPss);
- env->SetIntField(object, dalvikPrivateDirty_field, stats.dalvikPrivateDirty);
- env->SetIntField(object, dalvikSharedDirty_field, stats.dalvikSharedDirty);
+ for (int i=0; i<_NUM_CORE_HEAP; i++) {
+ env->SetIntField(object, stat_fields[i].pss_field, stats[i].pss);
+ env->SetIntField(object, stat_fields[i].privateDirty_field, stats[i].privateDirty);
+ env->SetIntField(object, stat_fields[i].sharedDirty_field, stats[i].sharedDirty);
+ }
- env->SetIntField(object, nativePss_field, stats.nativePss);
- env->SetIntField(object, nativePrivateDirty_field, stats.nativePrivateDirty);
- env->SetIntField(object, nativeSharedDirty_field, stats.nativeSharedDirty);
+ jintArray otherIntArray = (jintArray)env->GetObjectField(object, otherStats_field);
- env->SetIntField(object, otherPss_field, stats.otherPss);
- env->SetIntField(object, otherPrivateDirty_field, stats.otherPrivateDirty);
- env->SetIntField(object, otherSharedDirty_field, stats.otherSharedDirty);
+ jint* otherArray = (jint*)env->GetPrimitiveArrayCritical(otherIntArray, 0);
+ if (otherArray == NULL) {
+ return;
+ }
+
+ int j=0;
+ for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) {
+ otherArray[j++] = stats[i].pss;
+ otherArray[j++] = stats[i].privateDirty;
+ otherArray[j++] = stats[i].sharedDirty;
+ }
+
+ env->ReleasePrimitiveArrayCritical(otherIntArray, otherArray, 0);
}
static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject object)
@@ -487,19 +537,18 @@ static JNINativeMethod gMethods[] = {
int register_android_os_Debug(JNIEnv *env)
{
jclass clazz = env->FindClass("android/os/Debug$MemoryInfo");
-
- dalvikPss_field = env->GetFieldID(clazz, "dalvikPss", "I");
- dalvikPrivateDirty_field = env->GetFieldID(clazz, "dalvikPrivateDirty", "I");
- dalvikSharedDirty_field = env->GetFieldID(clazz, "dalvikSharedDirty", "I");
- nativePss_field = env->GetFieldID(clazz, "nativePss", "I");
- nativePrivateDirty_field = env->GetFieldID(clazz, "nativePrivateDirty", "I");
- nativeSharedDirty_field = env->GetFieldID(clazz, "nativeSharedDirty", "I");
-
- otherPss_field = env->GetFieldID(clazz, "otherPss", "I");
- otherPrivateDirty_field = env->GetFieldID(clazz, "otherPrivateDirty", "I");
- otherSharedDirty_field = env->GetFieldID(clazz, "otherSharedDirty", "I");
-
+ for (int i=0; i<_NUM_CORE_HEAP; i++) {
+ stat_fields[i].pss_field =
+ env->GetFieldID(clazz, stat_field_names[i].pss_name, "I");
+ stat_fields[i].privateDirty_field =
+ env->GetFieldID(clazz, stat_field_names[i].privateDirty_name, "I");
+ stat_fields[i].sharedDirty_field =
+ env->GetFieldID(clazz, stat_field_names[i].sharedDirty_name, "I");
+ }
+
+ otherStats_field = env->GetFieldID(clazz, "otherStats", "[I");
+
return jniRegisterNativeMethods(env, "android/os/Debug", gMethods, NELEM(gMethods));
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index f546cf1fe402..a8fb1ed65640 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -8885,25 +8885,59 @@ public final class ActivityManagerService extends ActivityManagerNative
pw.println("Applications Graphics Acceleration Info:");
pw.println("Uptime: " + uptime + " Realtime: " + realtime);
- String callArgs[] = {"graphics"};
for (int i = procs.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = procs.get(i);
if (r.thread != null) {
pw.println("\n** Graphics info for pid " + r.pid + " [" + r.processName + "] **");
pw.flush();
try {
- TransferPipe.goDump(r.thread.asBinder(), fd, callArgs);
+ TransferPipe tp = new TransferPipe();
+ try {
+ r.thread.dumpGfxInfo(tp.getWriteFd().getFileDescriptor(), args);
+ tp.go(fd);
+ } finally {
+ tp.kill();
+ }
} catch (IOException e) {
- pw.println("Failure: " + e);
+ pw.println("Failure while dumping the app: " + r);
pw.flush();
} catch (RemoteException e) {
- pw.println("Got RemoteException!");
+ pw.println("Got a RemoteException while dumping the app " + r);
pw.flush();
}
}
}
}
+ final static class MemItem {
+ final String label;
+ final long pss;
+
+ public MemItem(String _label, long _pss) {
+ label = _label;
+ pss = _pss;
+ }
+ }
+
+ 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;
+ }
+ return 0;
+ }
+ });
+
+ for (int i=0; i<items.size(); i++) {
+ MemItem mi = items.get(i);
+ pw.print(prefix); pw.printf("%8d Kb: ", mi.pss); pw.println(mi.label);
+ }
+ }
+
final void dumpApplicationMemoryUsage(FileDescriptor fd,
PrintWriter pw, String prefix, String[] args) {
ArrayList<ProcessRecord> procs = collectProcesses(pw, args);
@@ -8923,6 +8957,11 @@ public final class ActivityManagerService extends ActivityManagerNative
pw.println("Applications Memory Usage (kB):");
pw.println("Uptime: " + uptime + " Realtime: " + realtime);
}
+
+ ArrayList<MemItem> procMems = new ArrayList<MemItem>();
+ long nativePss=0, dalvikPss=0, otherPss=0;
+ long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
+
for (int i = procs.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = procs.get(i);
if (r.thread != null) {
@@ -8930,18 +8969,47 @@ public final class ActivityManagerService extends ActivityManagerNative
pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
pw.flush();
}
+ Debug.MemoryInfo mi = null;
try {
- TransferPipe.goDump(r.thread.asBinder(), fd, args);
- } catch (IOException e) {
- pw.println("Failure: " + e);
- pw.flush();
+ mi = r.thread.dumpMemInfo(fd, args);
} catch (RemoteException e) {
if (!isCheckinRequest) {
pw.println("Got RemoteException!");
pw.flush();
}
}
+ if (!isCheckinRequest && mi != null) {
+ procMems.add(new MemItem(r.processName + " (pid " + r.pid + ")",
+ mi.getTotalPss()));
+
+ nativePss += mi.nativePss;
+ dalvikPss += mi.dalvikPss;
+ otherPss += mi.otherPss;
+ for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
+ long mem = mi.getOtherPss(j);
+ miscPss[j] += mem;
+ otherPss -= mem;
+ }
+ }
+ }
+ }
+
+ if (!isCheckinRequest && procs.size() > 1) {
+ ArrayList<MemItem> catMems = new ArrayList<MemItem>();
+
+ catMems.add(new MemItem("Native", nativePss));
+ catMems.add(new MemItem("Dalvik", dalvikPss));
+ catMems.add(new MemItem("Unknown", otherPss));
+ for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
+ catMems.add(new MemItem(Debug.MemoryInfo.getOtherLabel(j), miscPss[j]));
}
+
+ pw.println();
+ pw.println("Total PSS by process:");
+ dumpMemItems(pw, " ", procMems);
+ pw.println();
+ pw.println("Total PSS by category:");
+ dumpMemItems(pw, " ", catMems);
}
}