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

Commit 247eb29c authored by Tim Murray's avatar Tim Murray Committed by android-build-merger
Browse files

Merge "psi support for low memory detection inside ActivityManagerService" into qt-dev

am: aaf62b99

Change-Id: I8cff66adeff97a33c3ba6e8242db5180c90984ba
parents efc271f5 aaf62b99
Loading
Loading
Loading
Loading
+22 −15
Original line number Diff line number Diff line
@@ -544,6 +544,7 @@ public class ActivityManagerService extends IActivityManager.Stub
    private static final int NATIVE_DUMP_TIMEOUT_MS = 2000; // 2 seconds;
    final OomAdjuster mOomAdjuster;
    final LowMemDetector mLowMemDetector;
    /** All system services */
    SystemServiceManager mSystemServiceManager;
@@ -2294,6 +2295,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                ? new ActivityManagerConstants(mContext, this, mHandler) : null;
        final ActiveUids activeUids = new ActiveUids(this, false /* postChangesToAtm */);
        mProcessList.init(this, activeUids);
        mLowMemDetector = null;
        mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids);
        mIntentFirewall = hasHandlerThread
@@ -2342,6 +2344,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        mConstants = new ActivityManagerConstants(mContext, this, mHandler);
        final ActiveUids activeUids = new ActiveUids(this, true /* postChangesToAtm */);
        mProcessList.init(this, activeUids);
        mLowMemDetector = new LowMemDetector(this);
        mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids);
        // Broadcast policy parameters
@@ -16524,16 +16527,19 @@ public class ActivityManagerService extends IActivityManager.Stub
    final boolean updateLowMemStateLocked(int numCached, int numEmpty, int numTrimming) {
        final int N = mProcessList.getLruSizeLocked();
        final long now = SystemClock.uptimeMillis();
        int memFactor;
        if (mLowMemDetector != null && mLowMemDetector.isAvailable()) {
            memFactor = mLowMemDetector.getMemFactor();
        } else {
            // Now determine the memory trimming level of background processes.
            // Unfortunately we need to start at the back of the list to do this
            // properly.  We only do this if the number of background apps we
            // are managing to keep around is less than half the maximum we desire;
            // if we are keeping a good number around, we'll let them use whatever
            // memory they want.
        final int numCachedAndEmpty = numCached + numEmpty;
        int memFactor;
            if (numCached <= mConstants.CUR_TRIM_CACHED_PROCESSES
                && numEmpty <= mConstants.CUR_TRIM_EMPTY_PROCESSES) {
                final int numCachedAndEmpty = numCached + numEmpty;
                if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {
                    memFactor = ProcessStats.ADJ_MEM_FACTOR_CRITICAL;
                } else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) {
@@ -16544,6 +16550,7 @@ public class ActivityManagerService extends IActivityManager.Stub
            } else {
                memFactor = ProcessStats.ADJ_MEM_FACTOR_NORMAL;
            }
        }
        // We always allow the memory level to go up (better).  We only allow it to go
        // down if we are in a state where that is allowed, *and* the total number of processes
        // has gone down since last time.
+92 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.am;

import com.android.internal.annotations.GuardedBy;

/**
 * Detects low memory using PSI.
 *
 * If the kernel doesn't support PSI, then this class is not available.
 */
public final class LowMemDetector {
    private static final String TAG = "LowMemDetector";
    private final ActivityManagerService mAm;
    private final LowMemThread mLowMemThread;
    private boolean mAvailable;

    private final Object mPressureStateLock = new Object();

    @GuardedBy("mPressureStateLock")
    private int mPressureState = MEM_PRESSURE_NONE;

    /* getPressureState return values */
    public static final int MEM_PRESSURE_NONE = 0;
    public static final int MEM_PRESSURE_LOW = 1;
    public static final int MEM_PRESSURE_MEDIUM = 2;
    public static final int MEM_PRESSURE_HIGH = 3;

    LowMemDetector(ActivityManagerService am) {
        mAm = am;
        mLowMemThread = new LowMemThread();
        if (init() != 0) {
            mAvailable = false;
        } else {
            mAvailable = true;
            mLowMemThread.start();
        }
    }

    public boolean isAvailable() {
        return mAvailable;
    }

    /**
     * Returns the current mem factor.
     * Note that getMemFactor returns LowMemDetector.MEM_PRESSURE_XXX
     * which match ProcessStats.ADJ_MEM_FACTOR_XXX values. If they deviate
     * there should be conversion performed here to translate pressure state
     * into memFactor.
     */
    public int getMemFactor() {
        synchronized (mPressureStateLock) {
            return mPressureState;
        }
    }

    private native int init();
    private native int waitForPressure();

    private final class LowMemThread extends Thread {
        public void run() {

            while (true) {
                // sleep waiting for a PSI event
                int newPressureState = waitForPressure();
                if (newPressureState == -1) {
                    // epoll broke, tear this down
                    mAvailable = false;
                    break;
                }
                // got a PSI event? let's update lowmem info
                synchronized (mPressureStateLock) {
                    mPressureState = newPressureState;
                }
            }
        }
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ cc_library_static {
        "com_android_server_PersistentDataBlockService.cpp",
        "com_android_server_GraphicsStatsService.cpp",
        "com_android_server_am_AppCompactor.cpp",
        "com_android_server_am_LowMemDetector.cpp",
        "onload.cpp",
        ":lib_networkStatsFactory_native",
    ],
@@ -104,6 +105,7 @@ cc_defaults {
        "libbpf_android",
        "libnetdbpf",
        "libnetdutils",
        "libpsi",
        "android.hardware.audio.common@2.0",
        "android.hardware.broadcastradio@1.0",
        "android.hardware.broadcastradio@1.1",
+156 −0
Original line number Diff line number Diff line
/**
** Copyright 2019, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/

#define LOG_TAG "LowMemDetector"

#include <errno.h>
#include <psi/psi.h>
#include <string.h>
#include <sys/epoll.h>

#include <jni.h>
#include <nativehelper/JNIHelp.h>
#include <utils/Log.h>

namespace android {

enum pressure_levels {
    PRESSURE_NONE,
    PRESSURE_LOW,
    PRESSURE_MEDIUM,
    PRESSURE_HIGH,
    PRESSURE_LEVEL_COUNT = PRESSURE_HIGH
};

// amount of stall in us for each level
static constexpr int PSI_LOW_STALL_US = 15000;
static constexpr int PSI_MEDIUM_STALL_US = 30000;
static constexpr int PSI_HIGH_STALL_US = 50000;

// stall tracking window size in us
static constexpr int PSI_WINDOW_SIZE_US = 1000000;

static int psi_epollfd = -1;

static jint android_server_am_LowMemDetector_init(JNIEnv*, jobject) {
    int epollfd;
    int low_psi_fd;
    int medium_psi_fd;
    int high_psi_fd;

    epollfd = epoll_create(PRESSURE_LEVEL_COUNT);
    if (epollfd == -1) {
        ALOGE("epoll_create failed: %s", strerror(errno));
        return -1;
    }

    low_psi_fd = init_psi_monitor(PSI_SOME, PSI_LOW_STALL_US, PSI_WINDOW_SIZE_US);
    if (low_psi_fd < 0 ||
        register_psi_monitor(epollfd, low_psi_fd, (void*)PRESSURE_LOW) != 0) {
        goto low_fail;
    }

    medium_psi_fd =
        init_psi_monitor(PSI_FULL, PSI_MEDIUM_STALL_US, PSI_WINDOW_SIZE_US);
    if (medium_psi_fd < 0 || register_psi_monitor(epollfd, medium_psi_fd,
                                                  (void*)PRESSURE_MEDIUM) != 0) {
        goto medium_fail;
    }

    high_psi_fd =
        init_psi_monitor(PSI_FULL, PSI_HIGH_STALL_US, PSI_WINDOW_SIZE_US);
    if (high_psi_fd < 0 ||
        register_psi_monitor(epollfd, high_psi_fd, (void*)PRESSURE_HIGH) != 0) {
        goto high_fail;
    }

    psi_epollfd = epollfd;
    return 0;

high_fail:
    unregister_psi_monitor(epollfd, medium_psi_fd);
medium_fail:
    unregister_psi_monitor(epollfd, low_psi_fd);
low_fail:
    ALOGE("Failed to register psi trigger");
    close(epollfd);
    return -1;
}

static jint android_server_am_LowMemDetector_waitForPressure(JNIEnv*, jobject) {
    static uint32_t pressure_level = PRESSURE_NONE;
    struct epoll_event events[PRESSURE_LEVEL_COUNT];
    int nevents = 0;

    if (psi_epollfd < 0) {
        ALOGE("Memory pressure detector is not initialized");
        return -1;
    }

    do {
        if (pressure_level == PRESSURE_NONE) {
            /* Wait for events with no timeout */
            nevents = epoll_wait(psi_epollfd, events, PRESSURE_LEVEL_COUNT, -1);
        } else {
            // This is simpler than lmkd. Assume that the memory pressure
            // state will stay high for at least 1s. Within that 1s window,
            // the memory pressure state can go up due to a different FD
            // becoming available or it can go down when that window expires.
            // Accordingly, there's no polling: just epoll_wait with a 1s timeout.
            nevents = epoll_wait(psi_epollfd, events, PRESSURE_LEVEL_COUNT, 1000);
            if (nevents == 0) {
                pressure_level = PRESSURE_NONE;
                return pressure_level;
            }
        }
        // keep waiting if interrupted
    } while (nevents == -1 && errno == EINTR);

    if (nevents == -1) {
        ALOGE("epoll_wait failed while waiting for psi events: %s", strerror(errno));
        return -1;
    }

    // reset pressure_level and raise it based on received events
    pressure_level = PRESSURE_NONE;
    for (int i = 0; i < nevents; i++) {
        if (events[i].events & (EPOLLERR | EPOLLHUP)) {
            // should never happen unless psi got disabled in kernel
            ALOGE("Memory pressure events are not available anymore");
            return -1;
        }
        // record the highest reported level
        if (events[i].data.u32 > pressure_level) {
            pressure_level = events[i].data.u32;
        }
    }

    return pressure_level;
}

static const JNINativeMethod sMethods[] = {
    /* name, signature, funcPtr */
    {"init", "()I", (void*)android_server_am_LowMemDetector_init},
    {"waitForPressure", "()I",
     (void*)android_server_am_LowMemDetector_waitForPressure},
};

int register_android_server_am_LowMemDetector(JNIEnv* env) {
    return jniRegisterNativeMethods(env, "com/android/server/am/LowMemDetector",
                                    sMethods, NELEM(sMethods));
}

} // namespace android
+2 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ int register_android_server_net_NetworkStatsFactory(JNIEnv* env);
int register_android_server_net_NetworkStatsService(JNIEnv* env);
int register_android_server_security_VerityUtils(JNIEnv* env);
int register_android_server_am_AppCompactor(JNIEnv* env);
int register_android_server_am_LowMemDetector(JNIEnv* env);
};

using namespace android;
@@ -105,5 +106,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
    register_android_server_net_NetworkStatsService(env);
    register_android_server_security_VerityUtils(env);
    register_android_server_am_AppCompactor(env);
    register_android_server_am_LowMemDetector(env);
    return JNI_VERSION_1_4;
}
Loading