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

Commit 9bffff95 authored by Daniel Sandler's avatar Daniel Sandler Committed by Android (Google) Code Review
Browse files

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

parents 2ea2a58d 646d66b0
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 {