Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 11418733 authored by Daniel Sandler's avatar Daniel Sandler Committed by android-build-merger
Browse files

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

am: 9bffff95

Change-Id: I86fbcda58bd8907cf3b63110db7cc32819fcb826
parents a277618a 9bffff95
Loading
Loading
Loading
Loading
+20 −4
Original line number Diff line number Diff line
@@ -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;
    }
+103 −18
Original line number Diff line number Diff line
@@ -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() {
            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();
            mHandler.post(gm::dumpHprofAndShare);
                        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;
        }
    }

    public static class Service extends SystemUI {
        @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 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 {