Merge "Add PSS info to dumpsys output." into qt-dev

This commit is contained in:
Daniel Sandler
2019-06-14 20:34:52 +00:00
committed by Android (Google) Code Review
2 changed files with 123 additions and 22 deletions

View File

@@ -16,6 +16,8 @@
package com.android.systemui.util.leak;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
@@ -47,10 +49,11 @@ public class DumpTruck {
private static final String FILEPROVIDER_PATH = "leak";
private static final String TAG = "DumpTruck";
private static final int BUFSIZ = 512 * 1024; // 512K
private static final int BUFSIZ = 1024 * 1024; // 1MB
private final Context context;
private Uri hprofUri;
private long pss;
final StringBuilder body = new StringBuilder();
public DumpTruck(Context context) {
@@ -89,6 +92,7 @@ public class DumpTruck {
.append(info.currentPss)
.append(" uss=")
.append(info.currentUss);
pss = info.currentPss;
}
}
if (pid == myPid) {
@@ -114,6 +118,7 @@ public class DumpTruck {
if (DumpTruck.zipUp(zipfile, paths)) {
final File pathFile = new File(zipfile);
hprofUri = FileProvider.getUriForFile(context, FILEPROVIDER_AUTHORITY, pathFile);
Log.v(TAG, "Heap dump accessible at URI: " + hprofUri);
}
} catch (IOException e) {
Log.e(TAG, "unable to zip up heapdumps", e);
@@ -138,16 +143,27 @@ public class DumpTruck {
* @return share intent
*/
public Intent createShareIntent() {
Intent shareIntent = new Intent(Intent.ACTION_SEND);
Intent shareIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
shareIntent.putExtra(Intent.EXTRA_SUBJECT, "SystemUI memory dump");
shareIntent.putExtra(Intent.EXTRA_SUBJECT,
String.format("SystemUI memory dump (pss=%dM)", pss / 1024));
shareIntent.putExtra(Intent.EXTRA_TEXT, body.toString());
if (hprofUri != null) {
final ArrayList<Uri> uriList = new ArrayList<>();
uriList.add(hprofUri);
shareIntent.setType("application/zip");
shareIntent.putExtra(Intent.EXTRA_STREAM, hprofUri);
shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uriList);
// Include URI in ClipData also, so that grantPermission picks it up.
// We don't use setData here because some apps interpret this as "to:".
ClipData clipdata = new ClipData(new ClipDescription("content",
new String[]{ClipDescription.MIMETYPE_TEXT_PLAIN}),
new ClipData.Item(hprofUri));
shareIntent.setClipData(clipdata);
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
return shareIntent;
}

View File

@@ -16,9 +16,13 @@
package com.android.systemui.util.leak;
import static android.service.quicksettings.Tile.STATE_ACTIVE;
import static android.telephony.ims.feature.ImsFeature.STATE_UNAVAILABLE;
import static com.android.internal.logging.MetricsLogger.VIEW_UNKNOWN;
import static com.android.systemui.Dependency.BG_LOOPER_NAME;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
@@ -38,11 +42,11 @@ import android.os.Message;
import android.os.Process;
import android.os.SystemProperties;
import android.provider.Settings;
import android.service.quicksettings.Tile;
import android.text.format.DateUtils;
import android.util.Log;
import android.util.LongSparseArray;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.SystemUIFactory;
@@ -50,6 +54,8 @@ import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import javax.inject.Inject;
@@ -59,7 +65,7 @@ import javax.inject.Singleton;
/**
*/
@Singleton
public class GarbageMonitor {
public class GarbageMonitor implements Dumpable {
private static final boolean LEAK_REPORTING_ENABLED =
Build.IS_DEBUGGABLE
&& SystemProperties.getBoolean("debug.enable_leak_reporting", false);
@@ -77,12 +83,15 @@ public class GarbageMonitor {
private static final long GARBAGE_INSPECTION_INTERVAL =
15 * DateUtils.MINUTE_IN_MILLIS; // 15 min
private static final long HEAP_TRACK_INTERVAL = 1 * DateUtils.MINUTE_IN_MILLIS; // 1 min
private static final int HEAP_TRACK_HISTORY_LEN = 720; // 12 hours
private static final int DO_GARBAGE_INSPECTION = 1000;
private static final int DO_HEAP_TRACK = 3000;
private static final int GARBAGE_ALLOWANCE = 5;
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final Handler mHandler;
private final TrackedGarbage mTrackedGarbage;
private final LeakReporter mLeakReporter;
@@ -180,7 +189,7 @@ public class GarbageMonitor {
sb.append(p);
sb.append(" ");
}
Log.v(TAG, sb.toString());
if (DEBUG) Log.v(TAG, sb.toString());
}
private void update() {
@@ -189,18 +198,18 @@ public class GarbageMonitor {
for (int i = 0; i < dinfos.length; i++) {
Debug.MemoryInfo dinfo = dinfos[i];
if (i > mPids.size()) {
Log.e(TAG, "update: unknown process info received: " + dinfo);
if (DEBUG) Log.e(TAG, "update: unknown process info received: " + dinfo);
break;
}
final long pid = mPids.get(i).intValue();
final ProcessMemInfo info = mData.get(pid);
info.head = (info.head + 1) % info.pss.length;
info.pss[info.head] = info.currentPss = dinfo.getTotalPss();
info.uss[info.head] = info.currentUss = dinfo.getTotalPrivateDirty();
info.head = (info.head + 1) % info.pss.length;
if (info.currentPss > info.max) info.max = info.currentPss;
if (info.currentUss > info.max) info.max = info.currentUss;
if (info.currentPss == 0) {
Log.v(TAG, "update: pid " + pid + " has pss=0, it probably died");
if (DEBUG) Log.v(TAG, "update: pid " + pid + " has pss=0, it probably died");
mData.remove(pid);
}
}
@@ -230,11 +239,36 @@ public class GarbageMonitor {
return b + SUFFIXES[i];
}
private void dumpHprofAndShare() {
final Intent share = mDumpTruck.captureHeaps(getTrackedProcesses()).createShareIntent();
mContext.startActivity(share);
private Intent dumpHprofAndGetShareIntent() {
return mDumpTruck.captureHeaps(getTrackedProcesses()).createShareIntent();
}
@Override
public void dump(@Nullable FileDescriptor fd, PrintWriter pw, @Nullable String[] args) {
pw.println("GarbageMonitor params:");
pw.println(String.format(" mHeapLimit=%d KB", mHeapLimit));
pw.println(String.format(" GARBAGE_INSPECTION_INTERVAL=%d (%.1f mins)",
GARBAGE_INSPECTION_INTERVAL,
(float) GARBAGE_INSPECTION_INTERVAL / DateUtils.MINUTE_IN_MILLIS));
final float htiMins = HEAP_TRACK_INTERVAL / DateUtils.MINUTE_IN_MILLIS;
pw.println(String.format(" HEAP_TRACK_INTERVAL=%d (%.1f mins)",
HEAP_TRACK_INTERVAL,
htiMins));
pw.println(String.format(" HEAP_TRACK_HISTORY_LEN=%d (%.1f hr total)",
HEAP_TRACK_HISTORY_LEN,
(float) HEAP_TRACK_HISTORY_LEN * htiMins / 60f));
pw.println("GarbageMonitor tracked processes:");
for (long pid : mPids) {
final ProcessMemInfo pmi = mData.get(pid);
if (pmi != null) {
pmi.dump(fd, pw, args);
}
}
}
private static class MemoryIconDrawable extends Drawable {
long pss, limit;
final Drawable baseIcon;
@@ -244,7 +278,7 @@ public class GarbageMonitor {
MemoryIconDrawable(Context context) {
baseIcon = context.getDrawable(R.drawable.ic_memory).mutate();
dp = context.getResources().getDisplayMetrics().density;
paint.setColor(QSTileImpl.getColorForState(context, Tile.STATE_ACTIVE));
paint.setColor(QSTileImpl.getColorForState(context, STATE_ACTIVE));
}
public void setPss(long pss) {
@@ -354,6 +388,7 @@ public class GarbageMonitor {
private final GarbageMonitor gm;
private ProcessMemInfo pmi;
private boolean dumpInProgress;
@Inject
public MemoryTile(QSHost host) {
@@ -373,8 +408,26 @@ public class GarbageMonitor {
@Override
protected void handleClick() {
getHost().collapsePanels();
mHandler.post(gm::dumpHprofAndShare);
if (dumpInProgress) return;
dumpInProgress = true;
refreshState();
new Thread("HeapDumpThread") {
@Override
public void run() {
try {
// wait for animations & state changes
Thread.sleep(500);
} catch (InterruptedException ignored) { }
final Intent shareIntent = gm.dumpHprofAndGetShareIntent();
mHandler.post(() -> {
dumpInProgress = false;
refreshState();
getHost().collapsePanels();
mContext.startActivity(shareIntent);
});
}
}.start();
}
@Override
@@ -404,9 +457,12 @@ public class GarbageMonitor {
pmi = gm.getMemInfo(Process.myPid());
final MemoryGraphIcon icon = new MemoryGraphIcon();
icon.setHeapLimit(gm.mHeapLimit);
state.state = dumpInProgress ? STATE_UNAVAILABLE : STATE_ACTIVE;
state.label = dumpInProgress
? "Dumping..."
: mContext.getString(R.string.heap_dump_tile_name);
if (pmi != null) {
icon.setPss(pmi.currentPss);
state.label = mContext.getString(R.string.heap_dump_tile_name);
state.secondaryLabel =
String.format(
"pss: %s / %s",
@@ -414,7 +470,6 @@ public class GarbageMonitor {
formatBytes(gm.mHeapLimit * 1024));
} else {
icon.setPss(0);
state.label = "Dump SysUI";
state.secondaryLabel = null;
}
state.icon = icon;
@@ -433,13 +488,14 @@ public class GarbageMonitor {
}
}
public static class ProcessMemInfo {
/** */
public static class ProcessMemInfo implements Dumpable {
public long pid;
public String name;
public long startTime;
public long currentPss, currentUss;
public long[] pss = new long[256];
public long[] uss = new long[256];
public long[] pss = new long[HEAP_TRACK_HISTORY_LEN];
public long[] uss = new long[HEAP_TRACK_HISTORY_LEN];
public long max = 1;
public int head = 0;
@@ -452,9 +508,33 @@ public class GarbageMonitor {
public long getUptime() {
return System.currentTimeMillis() - startTime;
}
@Override
public void dump(@Nullable FileDescriptor fd, PrintWriter pw, @Nullable String[] args) {
pw.print("{ \"pid\": ");
pw.print(pid);
pw.print(", \"name\": \"");
pw.print(name.replace('"', '-'));
pw.print("\", \"start\": ");
pw.print(startTime);
pw.print(", \"pss\": [");
// write pss values starting from the oldest, which is pss[head], wrapping around to
// pss[(head-1) % pss.length]
for (int i = 0; i < pss.length; i++) {
if (i > 0) pw.print(",");
pw.print(pss[(head + i) % pss.length]);
}
pw.print("], \"uss\": [");
for (int i = 0; i < uss.length; i++) {
if (i > 0) pw.print(",");
pw.print(uss[(head + i) % uss.length]);
}
pw.println("] }");
}
}
public static class Service extends SystemUI {
/** */
public static class Service extends SystemUI implements Dumpable {
private GarbageMonitor mGarbageMonitor;
@Override
@@ -472,6 +552,11 @@ public class GarbageMonitor {
mGarbageMonitor.startHeapTracking();
}
}
@Override
public void dump(@Nullable FileDescriptor fd, PrintWriter pw, @Nullable String[] args) {
if (mGarbageMonitor != null) mGarbageMonitor.dump(fd, pw, args);
}
}
private class BackgroundHeapCheckHandler extends Handler {