diff options
| -rw-r--r-- | core/java/android/app/ActivityThread.java | 98 | ||||
| -rw-r--r-- | core/java/android/app/ApplicationThreadNative.java | 66 | ||||
| -rw-r--r-- | core/java/android/app/IApplicationThread.java | 4 | ||||
| -rw-r--r-- | core/java/android/os/Debug.java | 39 | ||||
| -rw-r--r-- | core/jni/android_os_Debug.cpp | 219 | ||||
| -rw-r--r-- | services/java/com/android/server/am/ActivityManagerService.java | 84 |
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); } } |