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

Commit 91ecb36d authored by Todd Poynor's avatar Todd Poynor
Browse files

ActivityManagerService use lmkd low memory killer daemon -- DO NOT MERGE

Change-Id: Ie2f8af1e411c28d7f03be56c356ec39e1d71558e
parent d59c6151
Loading
Loading
Loading
Loading
+0 −13
Original line number Diff line number Diff line
@@ -891,19 +891,6 @@ public class Process {
        return true;
    }

    /**
     * Set the out-of-memory badness adjustment for a process.
     * 
     * @param pid The process identifier to set.
     * @param amt Adjustment value -- linux allows -16 to +15.
     * 
     * @return Returns true if the underlying system supports this
     *         feature, else false.
     *         
     * {@hide}
     */
    public static final native boolean setOomAdj(int pid, int amt);

    /**
     * Adjust the swappiness level for a process.
     *
+0 −18
Original line number Diff line number Diff line
@@ -344,23 +344,6 @@ jint android_os_Process_getThreadPriority(JNIEnv* env, jobject clazz,
    return pri;
}

jboolean android_os_Process_setOomAdj(JNIEnv* env, jobject clazz,
                                      jint pid, jint adj)
{
#ifdef HAVE_OOM_ADJ
    char text[64];
    sprintf(text, "/proc/%d/oom_adj", pid);
    int fd = open(text, O_WRONLY);
    if (fd >= 0) {
        sprintf(text, "%d", adj);
        write(fd, text, strlen(text));
        close(fd);
    }
    return true;
#endif
    return false;
}

jboolean android_os_Process_setSwappiness(JNIEnv *env, jobject clazz,
                                          jint pid, jboolean is_increased)
{
@@ -1023,7 +1006,6 @@ static const JNINativeMethod methods[] = {
    {"setThreadGroup",      "(II)V", (void*)android_os_Process_setThreadGroup},
    {"setProcessGroup",     "(II)V", (void*)android_os_Process_setProcessGroup},
    {"getProcessGroup",     "(I)I", (void*)android_os_Process_getProcessGroup},
    {"setOomAdj",   "(II)Z", (void*)android_os_Process_setOomAdj},
    {"setSwappiness",   "(IZ)Z", (void*)android_os_Process_setSwappiness},
    {"setArgV0",    "(Ljava/lang/String;)V", (void*)android_os_Process_setArgV0},
    {"setUid", "(I)I", (void*)android_os_Process_setUid},
+11 −9
Original line number Diff line number Diff line
@@ -3603,9 +3603,13 @@ public final class ActivityManagerService extends ActivityManagerNative
     */
    private final void handleAppDiedLocked(ProcessRecord app,
            boolean restarting, boolean allowRestart) {
        int pid = app.pid;
        cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1);
        if (!restarting) {
            removeLruProcessLocked(app);
            if (pid > 0) {
                ProcessList.remove(pid);
            }
        }
        if (mProfileProc == app) {
@@ -12388,6 +12392,7 @@ public final class ActivityManagerService extends ActivityManagerNative
            boolean restarting, boolean allowRestart, int index) {
        if (index >= 0) {
            removeLruProcessLocked(app);
            ProcessList.remove(app.pid);
        }
        mProcessesToGc.remove(app);
@@ -15250,16 +15255,13 @@ public final class ActivityManagerService extends ActivityManagerNative
        }
        if (app.curAdj != app.setAdj) {
            if (Process.setOomAdj(app.pid, app.curAdj)) {
            ProcessList.setOomAdj(app.pid, app.curAdj);
            if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
                TAG, "Set " + app.pid + " " + app.processName +
                " adj " + app.curAdj + ": " + app.adjType);
            app.setAdj = app.curAdj;
            } else {
                success = false;
                Slog.w(TAG, "Failed setting oom adj of " + app + " to " + app.curAdj);
            }
        }
        if (app.setSchedGroup != app.curSchedGroup) {
            app.setSchedGroup = app.curSchedGroup;
            if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+102 −33
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.server.am;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;

import android.app.ActivityManager;
import com.android.internal.util.MemInfoReader;
@@ -26,6 +28,8 @@ import com.android.server.wm.WindowManagerService;
import android.content.res.Resources;
import android.graphics.Point;
import android.os.SystemProperties;
import android.net.LocalSocketAddress;
import android.net.LocalSocket;
import android.util.Slog;
import android.view.Display;

@@ -141,6 +145,16 @@ final class ProcessList {
    // Threshold of number of cached+empty where we consider memory critical.
    static final int TRIM_LOW_THRESHOLD = 5;

    // Low Memory Killer Daemon command codes.
    // These must be kept in sync with the definitions in lmkd.c
    //
    // LMK_TARGET <minfree> <minkillprio> ... (up to 6 pairs)
    // LMK_PROCPRIO <pid> <prio>
    // LMK_PROCREMOVE <pid>
    static final byte LMK_TARGET = 0;
    static final byte LMK_PROCPRIO = 1;
    static final byte LMK_PROCREMOVE = 2;

    // These are the various interesting memory levels that we will give to
    // the OOM killer.  Note that the OOM killer only supports 6 slots, so we
    // can't give it a different value for every possible kind of process.
@@ -150,18 +164,18 @@ final class ProcessList {
    };
    // These are the low-end OOM level limits.  This is appropriate for an
    // HVGA or smaller phone with less than 512MB.  Values are in KB.
    private final long[] mOomMinFreeLow = new long[] {
    private final int[] mOomMinFreeLow = new int[] {
            8192, 12288, 16384,
            24576, 28672, 32768
    };
    // These are the high-end OOM level limits.  This is appropriate for a
    // 1280x800 or larger screen with around 1GB RAM.  Values are in KB.
    private final long[] mOomMinFreeHigh = new long[] {
    private final int[] mOomMinFreeHigh = new int[] {
            49152, 61440, 73728,
            86016, 98304, 122880
    };
    // The actual OOM killer memory levels we are using.
    private final long[] mOomMinFree = new long[mOomAdj.length];
    private final int[] mOomMinFree = new int[mOomAdj.length];

    private final long mTotalMemMb;

@@ -169,6 +183,9 @@ final class ProcessList {

    private boolean mHaveDisplaySize;

    private static LocalSocket sLmkdSocket;
    private static OutputStream sLmkdOutputStream;

    ProcessList() {
        MemInfoReader minfo = new MemInfoReader();
        minfo.readMemInfo();
@@ -202,9 +219,6 @@ final class ProcessList {
                    + " dh=" + displayHeight);
        }

        StringBuilder adjString = new StringBuilder();
        StringBuilder memString = new StringBuilder();

        float scale = scaleMem > scaleDisp ? scaleMem : scaleDisp;
        if (scale < 0) scale = 0;
        else if (scale > 1) scale = 1;
@@ -217,20 +231,20 @@ final class ProcessList {
        }

        for (int i=0; i<mOomAdj.length; i++) {
            long low = mOomMinFreeLow[i];
            long high = mOomMinFreeHigh[i];
            mOomMinFree[i] = (long)(low + ((high-low)*scale));
            int low = mOomMinFreeLow[i];
            int high = mOomMinFreeHigh[i];
            mOomMinFree[i] = (int)(low + ((high-low)*scale));
        }

        if (minfree_abs >= 0) {
            for (int i=0; i<mOomAdj.length; i++) {
                mOomMinFree[i] = (long)((float)minfree_abs * mOomMinFree[i] / mOomMinFree[mOomAdj.length - 1]);
                mOomMinFree[i] = (int)((float)minfree_abs * mOomMinFree[i] / mOomMinFree[mOomAdj.length - 1]);
            }
        }

        if (minfree_adj != 0) {
            for (int i=0; i<mOomAdj.length; i++) {
                mOomMinFree[i] += (long)((float)minfree_adj * mOomMinFree[i] / mOomMinFree[mOomAdj.length - 1]);
                mOomMinFree[i] += (int)((float)minfree_adj * mOomMinFree[i] / mOomMinFree[mOomAdj.length - 1]);
                if (mOomMinFree[i] < 0) {
                    mOomMinFree[i] = 0;
                }
@@ -242,15 +256,6 @@ final class ProcessList {
        // before killing background processes.
        mCachedRestoreLevel = (getMemLevel(ProcessList.CACHED_APP_MAX_ADJ)/1024) / 3;

        for (int i=0; i<mOomAdj.length; i++) {
            if (i > 0) {
                adjString.append(',');
                memString.append(',');
            }
            adjString.append(mOomAdj[i]);
            memString.append((mOomMinFree[i]*1024)/PAGE_SIZE);
        }

        // Ask the kernel to try to keep enough memory free to allocate 3 full
        // screen 32bpp buffers without entering direct reclaim.
        int reserve = displayWidth * displayHeight * 4 * 3 / 1024;
@@ -268,10 +273,15 @@ final class ProcessList {
            }
        }

        //Slog.i("XXXXXXX", "******************************* MINFREE: " + memString);
        if (write) {
            writeFile("/sys/module/lowmemorykiller/parameters/adj", adjString.toString());
            writeFile("/sys/module/lowmemorykiller/parameters/minfree", memString.toString());
            ByteBuffer buf = ByteBuffer.allocate(4 * (2*mOomAdj.length + 1));
            buf.putInt(LMK_TARGET);
            for (int i=0; i<mOomAdj.length; i++) {
                buf.putInt((mOomMinFree[i]*1024)/PAGE_SIZE);
                buf.putInt(mOomAdj[i]);
            }

            writeLmkd(buf);
            SystemProperties.set("sys.sysctl.extra_free_kbytes", Integer.toString(reserve));
        }
        // GB: 2048,3072,4096,6144,7168,8192
@@ -506,19 +516,78 @@ final class ProcessList {
        return mCachedRestoreLevel;
    }

    private void writeFile(String path, String data) {
        FileOutputStream fos = null;
    /**
     * Set the out-of-memory badness adjustment for a process.
     *
     * @param pid The process identifier to set.
     * @param amt Adjustment value -- lmkd allows -16 to +15.
     *
     * {@hide}
     */
    public static final void setOomAdj(int pid, int amt) {
        if (amt == UNKNOWN_ADJ)
            return;

        ByteBuffer buf = ByteBuffer.allocate(4 * 3);
        buf.putInt(LMK_PROCPRIO);
        buf.putInt(pid);
        buf.putInt(amt);
        writeLmkd(buf);
    }

    /*
     * {@hide}
     */
    public static final void remove(int pid) {
        ByteBuffer buf = ByteBuffer.allocate(4 * 2);
        buf.putInt(LMK_PROCREMOVE);
        buf.putInt(pid);
        writeLmkd(buf);
    }

    private static boolean openLmkdSocket() {
        try {
            fos = new FileOutputStream(path);
            fos.write(data.getBytes());
        } catch (IOException e) {
            Slog.w(ActivityManagerService.TAG, "Unable to write " + path);
        } finally {
            if (fos != null) {
            sLmkdSocket = new LocalSocket(LocalSocket.SOCKET_SEQPACKET);
            sLmkdSocket.connect(
                new LocalSocketAddress("lmkd",
                        LocalSocketAddress.Namespace.RESERVED));
            sLmkdOutputStream = sLmkdSocket.getOutputStream();
        } catch (IOException ex) {
            Slog.w(ActivityManagerService.TAG,
                   "lowmemorykiller daemon socket open failed");
            sLmkdSocket = null;
            return false;
        }

        return true;
    }

    private static void writeLmkd(ByteBuffer buf) {

        for (int i = 0; i < 3; i++) {
            if (sLmkdSocket == null) {
                    if (openLmkdSocket() == false) {
                        try {
                    fos.close();
                } catch (IOException e) {
                            Thread.sleep(1000);
                        } catch (InterruptedException ie) {
                        }
                        continue;
                    }
            }

            try {
                sLmkdOutputStream.write(buf.array(), 0, buf.position());
                return;
            } catch (IOException ex) {
                Slog.w(ActivityManagerService.TAG,
                       "Error writing to lowmemorykiller socket");

                try {
                    sLmkdSocket.close();
                } catch (IOException ex2) {
                }

                sLmkdSocket = null;
            }
        }
    }