From 598e9a277daa7a1cbbcf264754cb5605f097bd55 Mon Sep 17 00:00:00 2001 From: Kweku Adams Date: Thu, 2 Nov 2017 17:12:20 -0700 Subject: [PATCH] incidentd: dumping native process mem info to proto. Bug: 65750823 Test: flash device and check proto dump output. Change-Id: Ic584f78153fbbb507cdd41e699a541e3351467bb --- core/java/android/app/ActivityThread.java | 163 +++++++++++++++++++ core/proto/android/os/incident.proto | 5 + .../android/server/activitymanagerservice.proto | 71 +++++++- .../android/server/am/ActivityManagerService.java | 179 ++++++++++++++------- 4 files changed, 358 insertions(+), 60 deletions(-) diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index ffd012d9502f..b84833b973b9 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -108,6 +108,7 @@ import android.util.PrintWriterPrinter; import android.util.Slog; import android.util.SparseIntArray; import android.util.SuperNotCalledException; +import android.util.proto.ProtoOutputStream; import android.view.ContextThemeWrapper; import android.view.Display; import android.view.ThreadedRenderer; @@ -131,6 +132,7 @@ import com.android.internal.util.FastPrintWriter; import com.android.internal.util.IndentingPrintWriter; import com.android.org.conscrypt.OpenSSLSocketImpl; import com.android.org.conscrypt.TrustedCertificateStore; +import com.android.server.am.proto.MemInfoProto; import dalvik.system.BaseDexClassLoader; import dalvik.system.CloseGuard; @@ -2259,6 +2261,167 @@ public final class ActivityThread extends ClientTransactionHandler { } } + /** + * Dump heap info to proto. + * + * @param hasSwappedOutPss determines whether to use dirtySwap or dirtySwapPss + */ + private static void dumpHeap(ProtoOutputStream proto, long fieldId, String name, + int pss, int cleanPss, int sharedDirty, int privateDirty, + int sharedClean, int privateClean, + boolean hasSwappedOutPss, int dirtySwap, int dirtySwapPss) { + final long token = proto.start(fieldId); + + proto.write(MemInfoProto.NativeProcess.MemoryInfo.NAME, name); + proto.write(MemInfoProto.NativeProcess.MemoryInfo.TOTAL_PSS_KB, pss); + proto.write(MemInfoProto.NativeProcess.MemoryInfo.CLEAN_PSS_KB, cleanPss); + proto.write(MemInfoProto.NativeProcess.MemoryInfo.SHARED_DIRTY_KB, sharedDirty); + proto.write(MemInfoProto.NativeProcess.MemoryInfo.PRIVATE_DIRTY_KB, privateDirty); + proto.write(MemInfoProto.NativeProcess.MemoryInfo.SHARED_CLEAN_KB, sharedClean); + proto.write(MemInfoProto.NativeProcess.MemoryInfo.PRIVATE_CLEAN_KB, privateClean); + if (hasSwappedOutPss) { + proto.write(MemInfoProto.NativeProcess.MemoryInfo.DIRTY_SWAP_PSS_KB, dirtySwapPss); + } else { + proto.write(MemInfoProto.NativeProcess.MemoryInfo.DIRTY_SWAP_KB, dirtySwap); + } + + proto.end(token); + } + + /** + * Dump mem info data to proto. + */ + public static void dumpMemInfoTable(ProtoOutputStream proto, Debug.MemoryInfo memInfo, + boolean dumpDalvik, boolean dumpSummaryOnly, + long nativeMax, long nativeAllocated, long nativeFree, + long dalvikMax, long dalvikAllocated, long dalvikFree) { + + if (!dumpSummaryOnly) { + final long nhToken = proto.start(MemInfoProto.NativeProcess.NATIVE_HEAP); + dumpHeap(proto, MemInfoProto.NativeProcess.HeapInfo.MEM_INFO, "Native Heap", + memInfo.nativePss, memInfo.nativeSwappablePss, memInfo.nativeSharedDirty, + memInfo.nativePrivateDirty, memInfo.nativeSharedClean, + memInfo.nativePrivateClean, memInfo.hasSwappedOutPss, + memInfo.nativeSwappedOut, memInfo.nativeSwappedOutPss); + proto.write(MemInfoProto.NativeProcess.HeapInfo.HEAP_SIZE_KB, nativeMax); + proto.write(MemInfoProto.NativeProcess.HeapInfo.HEAP_ALLOC_KB, nativeAllocated); + proto.write(MemInfoProto.NativeProcess.HeapInfo.HEAP_FREE_KB, nativeFree); + proto.end(nhToken); + + final long dvToken = proto.start(MemInfoProto.NativeProcess.DALVIK_HEAP); + dumpHeap(proto, MemInfoProto.NativeProcess.HeapInfo.MEM_INFO, "Dalvik Heap", + memInfo.dalvikPss, memInfo.dalvikSwappablePss, memInfo.dalvikSharedDirty, + memInfo.dalvikPrivateDirty, memInfo.dalvikSharedClean, + memInfo.dalvikPrivateClean, memInfo.hasSwappedOutPss, + memInfo.dalvikSwappedOut, memInfo.dalvikSwappedOutPss); + proto.write(MemInfoProto.NativeProcess.HeapInfo.HEAP_SIZE_KB, dalvikMax); + proto.write(MemInfoProto.NativeProcess.HeapInfo.HEAP_ALLOC_KB, dalvikAllocated); + proto.write(MemInfoProto.NativeProcess.HeapInfo.HEAP_FREE_KB, dalvikFree); + proto.end(dvToken); + + int otherPss = memInfo.otherPss; + int otherSwappablePss = memInfo.otherSwappablePss; + int otherSharedDirty = memInfo.otherSharedDirty; + int otherPrivateDirty = memInfo.otherPrivateDirty; + int otherSharedClean = memInfo.otherSharedClean; + int otherPrivateClean = memInfo.otherPrivateClean; + int otherSwappedOut = memInfo.otherSwappedOut; + int otherSwappedOutPss = memInfo.otherSwappedOutPss; + + for (int i = 0; i < Debug.MemoryInfo.NUM_OTHER_STATS; i++) { + final int myPss = memInfo.getOtherPss(i); + final int mySwappablePss = memInfo.getOtherSwappablePss(i); + final int mySharedDirty = memInfo.getOtherSharedDirty(i); + final int myPrivateDirty = memInfo.getOtherPrivateDirty(i); + final int mySharedClean = memInfo.getOtherSharedClean(i); + final int myPrivateClean = memInfo.getOtherPrivateClean(i); + final int mySwappedOut = memInfo.getOtherSwappedOut(i); + final int mySwappedOutPss = memInfo.getOtherSwappedOutPss(i); + if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0 + || mySharedClean != 0 || myPrivateClean != 0 + || (memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut) != 0) { + dumpHeap(proto, MemInfoProto.NativeProcess.OTHER_HEAPS, + Debug.MemoryInfo.getOtherLabel(i), + myPss, mySwappablePss, mySharedDirty, myPrivateDirty, + mySharedClean, myPrivateClean, + memInfo.hasSwappedOutPss, mySwappedOut, mySwappedOutPss); + + otherPss -= myPss; + otherSwappablePss -= mySwappablePss; + otherSharedDirty -= mySharedDirty; + otherPrivateDirty -= myPrivateDirty; + otherSharedClean -= mySharedClean; + otherPrivateClean -= myPrivateClean; + otherSwappedOut -= mySwappedOut; + otherSwappedOutPss -= mySwappedOutPss; + } + } + + dumpHeap(proto, MemInfoProto.NativeProcess.UNKNOWN_HEAP, "Unknown", + otherPss, otherSwappablePss, + otherSharedDirty, otherPrivateDirty, otherSharedClean, otherPrivateClean, + memInfo.hasSwappedOutPss, otherSwappedOut, otherSwappedOutPss); + final long tToken = proto.start(MemInfoProto.NativeProcess.TOTAL_HEAP); + dumpHeap(proto, MemInfoProto.NativeProcess.HeapInfo.MEM_INFO, "TOTAL", + memInfo.getTotalPss(), memInfo.getTotalSwappablePss(), + memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(), + memInfo.getTotalSharedClean(), memInfo.getTotalPrivateClean(), + memInfo.hasSwappedOutPss, memInfo.getTotalSwappedOut(), + memInfo.getTotalSwappedOutPss()); + proto.write(MemInfoProto.NativeProcess.HeapInfo.HEAP_SIZE_KB, nativeMax + dalvikMax); + proto.write(MemInfoProto.NativeProcess.HeapInfo.HEAP_ALLOC_KB, + nativeAllocated + dalvikAllocated); + proto.write(MemInfoProto.NativeProcess.HeapInfo.HEAP_FREE_KB, nativeFree + dalvikFree); + proto.end(tToken); + + if (dumpDalvik) { + for (int i = Debug.MemoryInfo.NUM_OTHER_STATS; + i < Debug.MemoryInfo.NUM_OTHER_STATS + Debug.MemoryInfo.NUM_DVK_STATS; + i++) { + final int myPss = memInfo.getOtherPss(i); + final int mySwappablePss = memInfo.getOtherSwappablePss(i); + final int mySharedDirty = memInfo.getOtherSharedDirty(i); + final int myPrivateDirty = memInfo.getOtherPrivateDirty(i); + final int mySharedClean = memInfo.getOtherSharedClean(i); + final int myPrivateClean = memInfo.getOtherPrivateClean(i); + final int mySwappedOut = memInfo.getOtherSwappedOut(i); + final int mySwappedOutPss = memInfo.getOtherSwappedOutPss(i); + if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0 + || mySharedClean != 0 || myPrivateClean != 0 + || (memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut) != 0) { + dumpHeap(proto, MemInfoProto.NativeProcess.DALVIK_DETAILS, + Debug.MemoryInfo.getOtherLabel(i), + myPss, mySwappablePss, mySharedDirty, myPrivateDirty, + mySharedClean, myPrivateClean, + memInfo.hasSwappedOutPss, mySwappedOut, mySwappedOutPss); + } + } + } + } + + final long asToken = proto.start(MemInfoProto.NativeProcess.APP_SUMMARY); + proto.write(MemInfoProto.NativeProcess.AppSummary.JAVA_HEAP_PSS_KB, + memInfo.getSummaryJavaHeap()); + proto.write(MemInfoProto.NativeProcess.AppSummary.NATIVE_HEAP_PSS_KB, + memInfo.getSummaryNativeHeap()); + proto.write(MemInfoProto.NativeProcess.AppSummary.CODE_PSS_KB, memInfo.getSummaryCode()); + proto.write(MemInfoProto.NativeProcess.AppSummary.STACK_PSS_KB, memInfo.getSummaryStack()); + proto.write(MemInfoProto.NativeProcess.AppSummary.GRAPHICS_PSS_KB, + memInfo.getSummaryGraphics()); + proto.write(MemInfoProto.NativeProcess.AppSummary.PRIVATE_OTHER_PSS_KB, + memInfo.getSummaryPrivateOther()); + proto.write(MemInfoProto.NativeProcess.AppSummary.SYSTEM_PSS_KB, + memInfo.getSummarySystem()); + if (memInfo.hasSwappedOutPss) { + proto.write(MemInfoProto.NativeProcess.AppSummary.TOTAL_SWAP_PSS, + memInfo.getSummaryTotalSwapPss()); + } else { + proto.write(MemInfoProto.NativeProcess.AppSummary.TOTAL_SWAP_PSS, + memInfo.getSummaryTotalSwap()); + } + proto.end(asToken); + } + public void registerOnActivityPausedListener(Activity activity, OnActivityPausedListener listener) { synchronized (mOnPauseListeners) { diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto index ecdabcf98f39..73a9fbb32493 100644 --- a/core/proto/android/os/incident.proto +++ b/core/proto/android/os/incident.proto @@ -164,4 +164,9 @@ message IncidentProto { (section).type = SECTION_DUMPSYS, (section).args = "window --proto" ]; + + optional com.android.server.am.proto.MemInfoProto meminfo = 3018 [ + (section).type = SECTION_DUMPSYS, + (section).args = "meminfo --proto" + ]; } diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto index 889842ccc99e..3af6f51fffc9 100644 --- a/core/proto/android/server/activitymanagerservice.proto +++ b/core/proto/android/server/activitymanagerservice.proto @@ -16,16 +16,16 @@ syntax = "proto2"; +package com.android.server.am.proto; + import "frameworks/base/core/proto/android/app/notification.proto"; import "frameworks/base/core/proto/android/content/intent.proto"; -import "frameworks/base/core/proto/android/server/intentresolver.proto"; -import "frameworks/base/core/proto/android/server/windowmanagerservice.proto"; import "frameworks/base/core/proto/android/graphics/rect.proto"; import "frameworks/base/core/proto/android/os/looper.proto"; +import "frameworks/base/core/proto/android/server/intentresolver.proto"; +import "frameworks/base/core/proto/android/server/windowmanagerservice.proto"; import "frameworks/base/core/proto/android/util/common.proto"; -package com.android.server.am.proto; - option java_multiple_files = true; message ActivityManagerServiceProto { @@ -159,6 +159,69 @@ message BroadcastQueueProto { repeated BroadcastSummary historical_broadcasts_summary = 6; } +message MemInfoProto { + optional int64 uptime_duration_ms = 1; + optional int64 elapsed_realtime_ms = 2; + + message NativeProcess { + optional int32 pid = 1; + optional string process_name = 2; + + message MemoryInfo { + optional string name = 1; + // The proportional set size for the heap. + optional int32 total_pss_kb = 2; + // The proportional set size that is swappable for the heap. + optional int32 clean_pss_kb = 3; + // The private dirty pages used by the heap. + optional int32 shared_dirty_kb = 4; + // The shared dirty pages used by the heap. + optional int32 private_dirty_kb = 5; + // The shared clean pages used by the heap. + optional int32 shared_clean_kb = 6; + // The private clean pages used by the heap. + optional int32 private_clean_kb = 7; + oneof dirty_swap { + // The dirty the pages that have been swapped out. + int32 dirty_swap_kb = 8; + // The dirty the pages that have been swapped out, proportional. + int32 dirty_swap_pss_kb = 9; + } + } + message HeapInfo { + optional MemoryInfo mem_info = 1; + optional int32 heap_size_kb = 2; + optional int32 heap_alloc_kb = 3; + optional int32 heap_free_kb = 4; + } + optional HeapInfo native_heap = 3; + optional HeapInfo dalvik_heap = 4; + repeated MemoryInfo other_heaps = 5; + optional HeapInfo unknown_heap = 6; + // Summation of native_heap, dalvik_heap, and other_heaps. + optional HeapInfo total_heap = 7; + + repeated MemoryInfo dalvik_details = 8; + + message AppSummary { + optional int32 java_heap_pss_kb = 1; + optional int32 native_heap_pss_kb = 2; + optional int32 code_pss_kb = 3; + optional int32 stack_pss_kb = 4; + optional int32 graphics_pss_kb = 5; + optional int32 private_other_pss_kb = 6; + optional int32 system_pss_kb = 7; + + oneof total_swap { + int32 total_swap_pss = 8; + int32 total_swap_kb = 9; + } + } + optional AppSummary app_summary = 9; + } + repeated NativeProcess native_processes = 3; +} + message StickyBroadcastProto { optional int32 user = 1; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index fe992daf7d04..e6d70474a5e5 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -417,6 +417,7 @@ import com.android.server.am.ActivityStack.ActivityState; import com.android.server.am.proto.ActivityManagerServiceProto; import com.android.server.am.proto.BroadcastProto; import com.android.server.am.proto.GrantUriProto; +import com.android.server.am.proto.MemInfoProto; import com.android.server.am.proto.NeededUriGrantsProto; import com.android.server.am.proto.StickyBroadcastProto; import com.android.server.firewall.IntentFirewall; @@ -2569,14 +2570,13 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void dumpHigh(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) { - if (asProto) return; - mActivityManagerService.dumpApplicationMemoryUsage(fd, - pw, " ", new String[] {"-a"}, false, null); + dump(fd, pw, new String[] {"-a"}, asProto); } + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) { - if (asProto) return; - mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args, false, null); + mActivityManagerService.dumpApplicationMemoryUsage( + fd, pw, " ", args, false, null, asProto); } }; @@ -17207,8 +17207,8 @@ public class ActivityManagerService extends IActivityManager.Stub boolean dumpProto; } - final void dumpApplicationMemoryUsage(FileDescriptor fd, - PrintWriter pw, String prefix, String[] args, boolean brief, PrintWriter categoryPw) { + final void dumpApplicationMemoryUsage(FileDescriptor fd, PrintWriter pw, String prefix, + String[] args, boolean brief, PrintWriter categoryPw, boolean asProto) { MemoryUsageDumpOptions opts = new MemoryUsageDumpOptions(); opts.dumpDetails = false; opts.dumpFullDetails = false; @@ -17221,7 +17221,7 @@ public class ActivityManagerService extends IActivityManager.Stub opts.packages = false; opts.isCheckinRequest = false; opts.dumpSwapPss = false; - opts.dumpProto = false; + opts.dumpProto = asProto; int opti = 0; while (opti < args.length) { @@ -17289,7 +17289,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } - final void dumpApplicationMemoryUsage(FileDescriptor fd, PrintWriter pw, String prefix, + private final void dumpApplicationMemoryUsage(FileDescriptor fd, PrintWriter pw, String prefix, MemoryUsageDumpOptions opts, String[] innerArgs, boolean brief, ArrayList procs, PrintWriter categoryPw) { long uptime = SystemClock.uptimeMillis(); @@ -17298,54 +17298,59 @@ public class ActivityManagerService extends IActivityManager.Stub if (procs == null) { // No Java processes. Maybe they want to print a native process. - if (innerArgs.length > 0 && innerArgs[0].charAt(0) != '-') { - ArrayList nativeProcs - = new ArrayList(); - updateCpuStatsNow(); - int findPid = -1; - try { - findPid = Integer.parseInt(innerArgs[0]); - } catch (NumberFormatException e) { - } - synchronized (mProcessCpuTracker) { - final int N = mProcessCpuTracker.countStats(); - for (int i=0; i 0) { + proc = innerArgs[0]; + if (proc.charAt(0) != '-') { + ArrayList nativeProcs + = new ArrayList(); + updateCpuStatsNow(); + int findPid = -1; + try { + findPid = Integer.parseInt(innerArgs[0]); + } catch (NumberFormatException e) { } - } - if (nativeProcs.size() > 0) { - dumpApplicationMemoryUsageHeader(pw, uptime, realtime, opts.isCheckinRequest, - opts.isCompact); - Debug.MemoryInfo mi = null; - for (int i = nativeProcs.size() - 1 ; i >= 0 ; i--) { - final ProcessCpuTracker.Stats r = nativeProcs.get(i); - final int pid = r.pid; - if (!opts.isCheckinRequest && opts.dumpDetails) { - pw.println("\n** MEMINFO in pid " + pid + " [" + r.baseName + "] **"); - } - if (mi == null) { - mi = new Debug.MemoryInfo(); - } - if (opts.dumpDetails || (!brief && !opts.oomOnly)) { - Debug.getMemoryInfo(pid, mi); - } else { - mi.dalvikPss = (int)Debug.getPss(pid, tmpLong, null); - mi.dalvikPrivateDirty = (int)tmpLong[0]; + synchronized (mProcessCpuTracker) { + final int N = mProcessCpuTracker.countStats(); + for (int i=0; i 0) { + dumpApplicationMemoryUsageHeader(pw, uptime, realtime, + opts.isCheckinRequest, opts.isCompact); + Debug.MemoryInfo mi = null; + for (int i = nativeProcs.size() - 1 ; i >= 0 ; i--) { + final ProcessCpuTracker.Stats r = nativeProcs.get(i); + final int pid = r.pid; + if (!opts.isCheckinRequest && opts.dumpDetails) { + pw.println("\n** MEMINFO in pid " + pid + " [" + r.baseName + "] **"); + } + if (mi == null) { + mi = new Debug.MemoryInfo(); + } + if (opts.dumpDetails || (!brief && !opts.oomOnly)) { + Debug.getMemoryInfo(pid, mi); + } else { + mi.dalvikPss = (int)Debug.getPss(pid, tmpLong, null); + mi.dalvikPrivateDirty = (int)tmpLong[0]; + } + ActivityThread.dumpMemInfoTable(pw, mi, opts.isCheckinRequest, + opts.dumpFullDetails, opts.dumpDalvik, opts.dumpSummaryOnly, + pid, r.baseName, 0, 0, 0, 0, 0, 0); + if (opts.isCheckinRequest) { + pw.println(); + } } + return; } - return; } } - pw.println("No process found for: " + innerArgs[0]); + pw.println("No process found for: " + proc); return; } @@ -17768,15 +17773,77 @@ public class ActivityManagerService extends IActivityManager.Stub } } - final void dumpApplicationMemoryUsage(FileDescriptor fd, PrintWriter pw, + private final void dumpApplicationMemoryUsage(FileDescriptor fd, PrintWriter pw, MemoryUsageDumpOptions opts, String[] innerArgs, boolean brief, ArrayList procs) { - ProtoOutputStream proto = new ProtoOutputStream(fd); + final long uptimeMs = SystemClock.uptimeMillis(); + final long realtimeMs = SystemClock.elapsedRealtime(); + final long[] tmpLong = new long[1]; + + if (procs == null) { + // No Java processes. Maybe they want to print a native process. + String proc = "N/A"; + if (innerArgs.length > 0) { + proc = innerArgs[0]; + if (proc.charAt(0) != '-') { + ArrayList nativeProcs + = new ArrayList(); + updateCpuStatsNow(); + int findPid = -1; + try { + findPid = Integer.parseInt(innerArgs[0]); + } catch (NumberFormatException e) { + } + synchronized (mProcessCpuTracker) { + final int N = mProcessCpuTracker.countStats(); + for (int i=0; i 0) { + ProtoOutputStream proto = new ProtoOutputStream(fd); - // TODO: implement - pw.println("Not yet implemented. Have a cookie instead! :]"); + proto.write(MemInfoProto.UPTIME_DURATION_MS, uptimeMs); + proto.write(MemInfoProto.ELAPSED_REALTIME_MS, realtimeMs); + Debug.MemoryInfo mi = null; + for (int i = nativeProcs.size() - 1 ; i >= 0 ; i--) { + final ProcessCpuTracker.Stats r = nativeProcs.get(i); + final int pid = r.pid; + final long nToken = proto.start(MemInfoProto.NATIVE_PROCESSES); + + proto.write(MemInfoProto.NativeProcess.PID, pid); + proto.write(MemInfoProto.NativeProcess.PROCESS_NAME, r.baseName); + + if (mi == null) { + mi = new Debug.MemoryInfo(); + } + if (opts.dumpDetails || (!brief && !opts.oomOnly)) { + Debug.getMemoryInfo(pid, mi); + } else { + mi.dalvikPss = (int)Debug.getPss(pid, tmpLong, null); + mi.dalvikPrivateDirty = (int)tmpLong[0]; + } + ActivityThread.dumpMemInfoTable(proto, mi, opts.dumpDalvik, + opts.dumpSummaryOnly, 0, 0, 0, 0, 0, 0); + + proto.end(nToken); + } + + proto.flush(); + return; + } + } + } + Log.d(TAG, "No process found for: " + innerArgs[0]); + return; + } - proto.flush(); + // TODO: finish + pw.println("Java processes aren't implemented yet. Have a coffee instead! :]"); } private void appendBasicMemEntry(StringBuilder sb, int oomAdj, int procState, long pss, -- 2.11.0