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

Commit 8e69257a authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Implement #10749688: Improve low memory reporting

This significantly reworks the logging we do when
all cached processes are killed:

- We now collect the list of processes in-place so we
  have a snapshot of exactly when the low memory situation
  happened.
- In that snapshot we include the key process state: oom
  adj, proc state, adj reasons.
- The report then asynchronously collects pss information
  for those processes.
- The ultimate data printed to the log looks like a mix
  between the "dumpsys meminfo" and "dumpsys activity"
  output.  This code no longer uses "dumpsys meminfo"
  itself, so some of that data is no longer included,
  in particular pss organized by allocation type.

In doing this, I realized that the existing code that is
supposed to run "procstats" is not currently working.  And
at that point I realized, really, when we are collecting
this pss data we'd really like to include all those native
processes using ghod-only-knows how much RAM.  And guess
what, we have a list of processes available in
ProcessCpuTracker.

So we now also collect and print information for native
processes, and we also do this for "dumpsys meminfo" which
really seems like a good thing when we are printing summaries
of all pss and such.

I also improved the code for reading /proc/meminfo to be
able to load all the interesting fields from there, and
am now printing that as well.

Change-Id: I9e7d13e9c07a8249c7a7e12e5433973b2c0fdc11
parent 9210bc85
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -1018,6 +1018,28 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
     */
    public static native long getPss(int pid, long[] outUss);

    /** @hide */
    public static final int MEMINFO_TOTAL = 0;
    /** @hide */
    public static final int MEMINFO_FREE = 1;
    /** @hide */
    public static final int MEMINFO_BUFFERS = 2;
    /** @hide */
    public static final int MEMINFO_CACHED = 3;
    /** @hide */
    public static final int MEMINFO_SHMEM = 4;
    /** @hide */
    public static final int MEMINFO_SLAB = 5;
    /** @hide */
    public static final int MEMINFO_COUNT = 6;

    /**
     * Retrieves /proc/meminfo.  outSizes is filled with fields
     * as defined by MEMINFO_* offsets.
     * @hide
     */
    public static native void getMemInfo(long[] outSizes);

    /**
     * Establish an object allocation limit in the current thread.
     * This feature was never enabled in release builds.  The
+16 −10
Original line number Diff line number Diff line
@@ -49,12 +49,12 @@ public class ProcessCpuTracker {
        PROC_SPACE_TERM,
        PROC_SPACE_TERM,
        PROC_SPACE_TERM,
        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 9: minor faults
        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 10: minor faults
        PROC_SPACE_TERM,
        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 11: major faults
        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 12: major faults
        PROC_SPACE_TERM,
        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 13: utime
        PROC_SPACE_TERM|PROC_OUT_LONG                   // 14: stime
        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 14: utime
        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 15: stime
    };

    static final int PROCESS_STAT_MINOR_FAULTS = 0;
@@ -69,7 +69,7 @@ public class ProcessCpuTracker {

    private static final int[] PROCESS_FULL_STATS_FORMAT = new int[] {
        PROC_SPACE_TERM,
        PROC_SPACE_TERM|PROC_PARENS|PROC_OUT_STRING,    // 1: name
        PROC_SPACE_TERM|PROC_PARENS|PROC_OUT_STRING,    // 2: name
        PROC_SPACE_TERM,
        PROC_SPACE_TERM,
        PROC_SPACE_TERM,
@@ -77,19 +77,20 @@ public class ProcessCpuTracker {
        PROC_SPACE_TERM,
        PROC_SPACE_TERM,
        PROC_SPACE_TERM,
        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 9: minor faults
        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 10: minor faults
        PROC_SPACE_TERM,
        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 11: major faults
        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 12: major faults
        PROC_SPACE_TERM,
        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 13: utime
        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 14: stime
        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 14: utime
        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 15: stime
        PROC_SPACE_TERM,
        PROC_SPACE_TERM,
        PROC_SPACE_TERM,
        PROC_SPACE_TERM,
        PROC_SPACE_TERM,
        PROC_SPACE_TERM,
        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 21: vsize
        PROC_SPACE_TERM,
        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 23: vsize
    };

    static final int PROCESS_FULL_STAT_MINOR_FAULTS = 1;
@@ -190,6 +191,10 @@ public class ProcessCpuTracker {
        public String name;
        public int nameWidth;

        // vsize capture when process first detected; can be used to
        // filter out kernel processes.
        public long vsize;

        public long base_uptime;
        public long rel_uptime;

@@ -444,6 +449,7 @@ public class ProcessCpuTracker {
                    // are actually kernel threads...  do we want to?  Some
                    // of them do use CPU, but there can be a *lot* that are
                    // not doing anything.
                    st.vsize = procStats[PROCESS_FULL_STAT_VSIZE];
                    if (true || procStats[PROCESS_FULL_STAT_VSIZE] != 0) {
                        st.interesting = true;
                        st.baseName = procStatsString[0];
+6 −28
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.internal.util;

import java.io.FileInputStream;

import android.os.Debug;
import android.os.StrictMode;

public class MemInfoReader {
@@ -63,34 +64,11 @@ public class MemInfoReader {
        // /proc/ and /sys/ files perhaps?
        StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
        try {
            mTotalSize = 0;
            mFreeSize = 0;
            mCachedSize = 0;
            FileInputStream is = new FileInputStream("/proc/meminfo");
            int len = is.read(mBuffer);
            is.close();
            final int BUFLEN = mBuffer.length;
            int count = 0;
            for (int i=0; i<len && count < 3; i++) {
                if (matchText(mBuffer, i, "MemTotal")) {
                    i += 8;
                    mTotalSize = extractMemValue(mBuffer, i);
                    count++;
                } else if (matchText(mBuffer, i, "MemFree")) {
                    i += 7;
                    mFreeSize = extractMemValue(mBuffer, i);
                    count++;
                } else if (matchText(mBuffer, i, "Cached")) {
                    i += 6;
                    mCachedSize = extractMemValue(mBuffer, i);
                    count++;
                }
                while (i < BUFLEN && mBuffer[i] != '\n') {
                    i++;
                }
            }
        } catch (java.io.FileNotFoundException e) {
        } catch (java.io.IOException e) {
            long[] infos = new long[Debug.MEMINFO_COUNT];
            Debug.getMemInfo(infos);
            mTotalSize = infos[Debug.MEMINFO_TOTAL] * 1024;
            mFreeSize = infos[Debug.MEMINFO_FREE] * 1024;
            mCachedSize = infos[Debug.MEMINFO_CACHED] * 1024;
        } finally {
            StrictMode.setThreadPolicy(savedPolicy);
        }
+83 −0
Original line number Diff line number Diff line
@@ -516,6 +516,87 @@ static jlong android_os_Debug_getPss(JNIEnv *env, jobject clazz)
    return android_os_Debug_getPssPid(env, clazz, getpid(), NULL);
}

static void android_os_Debug_getMemInfo(JNIEnv *env, jobject clazz, jlongArray out)
{
    char buffer[1024];
    int numFound = 0;

    if (out == NULL) {
        jniThrowNullPointerException(env, "out == null");
        return;
    }

    int fd = open("/proc/meminfo", O_RDONLY);

    if (fd < 0) {
        printf("Unable to open /proc/meminfo: %s\n", strerror(errno));
        return;
    }

    const int len = read(fd, buffer, sizeof(buffer)-1);
    close(fd);

    if (len < 0) {
        printf("Empty /proc/meminfo");
        return;
    }
    buffer[len] = 0;

    static const char* const tags[] = {
            "MemTotal:",
            "MemFree:",
            "Buffers:",
            "Cached:",
            "Shmem:",
            "Slab:",
            NULL
    };
    static const int tagsLen[] = {
            9,
            8,
            8,
            7,
            6,
            5,
            0
    };
    long mem[] = { 0, 0, 0, 0, 0, 0 };

    char* p = buffer;
    while (*p && numFound < 6) {
        int i = 0;
        while (tags[i]) {
            if (strncmp(p, tags[i], tagsLen[i]) == 0) {
                p += tagsLen[i];
                while (*p == ' ') p++;
                char* num = p;
                while (*p >= '0' && *p <= '9') p++;
                if (*p != 0) {
                    *p = 0;
                    p++;
                }
                mem[i] = atoll(num);
                numFound++;
                break;
            }
            i++;
        }
        while (*p && *p != '\n') {
            p++;
        }
        if (*p) p++;
    }

    int maxNum = env->GetArrayLength(out);
    jlong* outArray = env->GetLongArrayElements(out, 0);
    if (outArray != NULL) {
        for (int i=0; i<maxNum && tags[i]; i++) {
            outArray[i] = mem[i];
        }
    }
    env->ReleaseLongArrayElements(out, outArray, 0);
}

static jint read_binder_stat(const char* stat)
{
    FILE* fp = fopen(BINDER_STATS, "r");
@@ -790,6 +871,8 @@ static JNINativeMethod gMethods[] = {
            (void*) android_os_Debug_getPss },
    { "getPss",                 "(I[J)J",
            (void*) android_os_Debug_getPssPid },
    { "getMemInfo",             "([J)V",
            (void*) android_os_Debug_getMemInfo },
    { "dumpNativeHeap",         "(Ljava/io/FileDescriptor;)V",
            (void*) android_os_Debug_dumpNativeHeap },
    { "getBinderSentTransactions", "()I",
+11 −2
Original line number Diff line number Diff line
@@ -328,8 +328,17 @@ public final class ActiveServices {
                addToStarting = true;
                if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Not delaying, but counting as bg: " + r);
            } else if (DEBUG_DELAYED_STATS) {
                Slog.v(TAG, "Not potential delay (state=" + proc.curProcState
                        + " " + proc.makeAdjReason() + "): " + r);
                StringBuilder sb = new StringBuilder(128);
                sb.append("Not potential delay (state=").append(proc.curProcState)
                        .append(' ').append(proc.adjType);
                String reason = proc.makeAdjReason();
                if (reason != null) {
                    sb.append(' ');
                    sb.append(reason);
                }
                sb.append("): ");
                sb.append(r.toString());
                Slog.v(TAG, sb.toString());
            }
        } else if (DEBUG_DELAYED_STATS) {
            if (callerFg) {
Loading