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

Commit 29e40a45 authored by Shashi Shekar Shankar's avatar Shashi Shekar Shankar Committed by Linux Build Service Account
Browse files

Performance: Memory Optimizations

The following optimizations are squashed in this change.

1. Enable Aggressive trim settings.

This change will enable aggressive trim settings for targets
up to 1GB. The change can be turned on/off from system properties.
By default, the properties are set for targets up to 1GB.

Changes spread in to : ProcessList.java
CRs-Fixed: 783020

2. Propagate B-services to higher adj.

Depending on the inactivity of a service, move the B-services to
highest adj 906. Under memory pressure, these services will
be killed first ahead of cached apps which results in better
concurrency numbers with bg apps. Inactivity time and minumum
no of services to be maintained are configurable as system properties.
Improves concurrency.

Changes spread in to : ActivityManagerService.java
CRs-Fixed: 792122

3. Postpone service restart during app launch.

In the android framework, when the service gets killed,
it will be rescheduled. Postpone the service restart if
the app is in process of startup. By Default this feature
is disabled. It can be enabled from build.prop of target.

Changes spread in to : ActiveServices.java
CRs-Fixed: 879756 911145

Squash of following change-IDs:
    Change-Id: I233dddbff07e7ec1fe2ee96402fe1d411903beb5
    Change-Id: Ied6cfcc3d11951f32f18de680b0e3483db8e163e
    Change-Id: Ia86edf027e20df2c7aa6f34e3aa293f7a8e6f1fa

Change-Id: I3b2110743a6e0dd1379aa3b7703b3a897db3f6e6
parent 698c18a2
Loading
Loading
Loading
Loading
+66 −1
Original line number Diff line number Diff line
@@ -125,6 +125,10 @@ public final class ActiveServices {
    // at the same time.
    final int mMaxStartingBackground;

    // Flag to reschedule the services during app launch. Disable by default.
    private static final boolean SERVICE_RESCHEDULE
            = SystemProperties.getBoolean("ro.am.reschedule_service", false);

    final SparseArray<ServiceMap> mServiceMap = new SparseArray<>();

    /**
@@ -1492,6 +1496,14 @@ public final class ActiveServices {
                        r.pendingStarts.add(0, si);
                        long dur = SystemClock.uptimeMillis() - si.deliveredTime;
                        dur *= 2;
                        if (SERVICE_RESCHEDULE && DEBUG_DELAYED_SERVICE) {
                            Slog.w(TAG,"Can add more delay !!!"
                               +" si.deliveredTime "+si.deliveredTime
                               +" dur "+dur
                               +" si.deliveryCount "+si.deliveryCount
                               +" si.doneExecutingCount "+si.doneExecutingCount
                               +" allowCancel "+allowCancel);
                        }
                        if (minDuration < dur) minDuration = dur;
                        if (resetTime < dur) resetTime = dur;
                    } else {
@@ -1504,6 +1516,13 @@ public final class ActiveServices {
            }

            r.totalRestartCount++;
            if (SERVICE_RESCHEDULE && DEBUG_DELAYED_SERVICE) {
                Slog.w(TAG,"r.name "+r.name+" N "+N+" minDuration "+minDuration
                       +" resetTime "+resetTime+" now "+now
                       +" r.restartDelay "+r.restartDelay
                       +" r.restartTime+resetTime "+(r.restartTime+resetTime)
                       +" allowCancel "+allowCancel);
            }
            if (r.restartDelay == 0) {
                r.restartCount++;
                r.restartDelay = minDuration;
@@ -1525,6 +1544,14 @@ public final class ActiveServices {
            }

            r.nextRestartTime = now + r.restartDelay;
            if (SERVICE_RESCHEDULE && DEBUG_DELAYED_SERVICE) {
                Slog.w(TAG,"r.name "+r.name+" N "+N+" minDuration "+minDuration
                       +" resetTime "+resetTime+" now "+now
                       +" r.restartDelay "+r.restartDelay
                       +" r.restartTime+resetTime "+(r.restartTime+resetTime)
                       +" r.nextRestartTime "+r.nextRestartTime
                       +" allowCancel "+allowCancel);
            }

            // Make sure that we don't end up restarting a bunch of services
            // all at the same time.
@@ -1567,6 +1594,15 @@ public final class ActiveServices {
        r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
        Slog.w(TAG, "Scheduling restart of crashed service "
                + r.shortName + " in " + r.restartDelay + "ms");

        if (SERVICE_RESCHEDULE && DEBUG_DELAYED_SERVICE) {
            for (int i=mRestartingServices.size()-1; i>=0; i--) {
                ServiceRecord r2 = mRestartingServices.get(i);
                Slog.w(TAG,"Restarting list - i "+i+" r2.nextRestartTime "
                           +r2.nextRestartTime+" r2.name "+r2.name);
            }
        }

        EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART,
                r.userId, r.shortName, r.restartDelay);

@@ -1587,7 +1623,31 @@ public final class ActiveServices {
            return;
        }
        try {
            if(SERVICE_RESCHEDULE == true) {
                boolean shouldDelay = false;
                ActivityRecord top_rc = null;
                ActivityStack stack = mAm.getFocusedStack();
                if(stack != null) {
                    top_rc = stack.topRunningActivityLocked();
                }
                if(top_rc != null) {
                    if(!top_rc.nowVisible && !r.shortName.contains(top_rc.packageName)) {
                        shouldDelay = true;
                    }
                }
                if(!shouldDelay) {
                    bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true, false);
                } else {
                    if (DEBUG_DELAYED_SERVICE) {
                        Slog.v(TAG, "Reschedule service restart due to app launch"
                              +" r.shortName "+r.shortName+" r.app = "+r.app);
                    }
                    r.resetRestartCounter();
                    scheduleServiceRestartLocked(r, true);
                }
            } else {
                bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true, false);
            }
        } catch (TransactionTooLargeException e) {
            // Ignore, it's been logged and nothing upstack cares.
        }
@@ -1812,6 +1872,11 @@ public final class ActiveServices {
                if (newService) {
                    app.services.remove(r);
                    r.app = null;
                    if (SERVICE_RESCHEDULE && DEBUG_DELAYED_SERVICE) {
                    Slog.w(TAG, " Failed to create Service !!!! ."
                           +"This will introduce huge delay...  "
                           +r.shortName + " in " + r.restartDelay + "ms");
                    }
                }

                // Retry.
+49 −0
Original line number Diff line number Diff line
@@ -1536,6 +1536,16 @@ public final class ActivityManagerService extends ActivityManagerNative
    UnsupportedDisplaySizeDialog mUnsupportedDisplaySizeDialog;
    long mLastMemUsageReportTime = 0;
    // Min aging threshold in milliseconds to consider a B-service
    int mMinBServiceAgingTime =
            SystemProperties.getInt("ro.sys.fw.bservice_age", 5000);
    // Threshold for B-services when in memory pressure
    int mBServiceAppThreshold =
            SystemProperties.getInt("ro.sys.fw.bservice_limit", 5);
    // Enable B-service aging propagation on memory pressure.
    boolean mEnableBServicePropagation =
            SystemProperties.getBoolean("ro.sys.fw.bservice_enable", false);
    /**
     * Flag whether the current user is a "monkey", i.e. whether
     * the UI is driven by a UI automation tool.
@@ -20577,8 +20587,39 @@ public final class ActivityManagerService extends ActivityManagerNative
        int nextCachedAdj = curCachedAdj+1;
        int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ;
        int nextEmptyAdj = curEmptyAdj+2;
        ProcessRecord selectedAppRecord = null;
        long serviceLastActivity = 0;
        int numBServices = 0;
        for (int i=N-1; i>=0; i--) {
            ProcessRecord app = mLruProcesses.get(i);
            if (mEnableBServicePropagation && app.serviceb
                    && (app.curAdj == ProcessList.SERVICE_B_ADJ)) {
                numBServices++;
                for (int s = app.services.size() - 1; s >= 0; s--) {
                    ServiceRecord sr = app.services.valueAt(s);
                    if (DEBUG_OOM_ADJ) Slog.d(TAG,"app.processName = " + app.processName
                            + " serviceb = " + app.serviceb + " s = " + s + " sr.lastActivity = "
                            + sr.lastActivity + " packageName = " + sr.packageName
                            + " processName = " + sr.processName);
                    if (SystemClock.uptimeMillis() - sr.lastActivity
                            < mMinBServiceAgingTime) {
                        if (DEBUG_OOM_ADJ) {
                            Slog.d(TAG,"Not aged enough!!!");
                        }
                        continue;
                    }
                    if (serviceLastActivity == 0) {
                        serviceLastActivity = sr.lastActivity;
                        selectedAppRecord = app;
                    } else if (sr.lastActivity < serviceLastActivity) {
                        serviceLastActivity = sr.lastActivity;
                        selectedAppRecord = app;
                    }
                }
            }
            if (DEBUG_OOM_ADJ && selectedAppRecord != null) Slog.d(TAG,
                    "Identified app.processName = " + selectedAppRecord.processName
                    + " app.pid = " + selectedAppRecord.pid);
            if (!app.killedByAm && app.thread != null) {
                app.procStateChanged = false;
                computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now);
@@ -20687,6 +20728,14 @@ public final class ActivityManagerService extends ActivityManagerNative
                }
            }
        }
        if ((numBServices > mBServiceAppThreshold) && (true == mAllowLowerMemLevel)
                && (selectedAppRecord != null)) {
            ProcessList.setOomAdj(selectedAppRecord.pid, selectedAppRecord.info.uid,
                    ProcessList.CACHED_APP_MAX_ADJ);
            selectedAppRecord.setAdj = selectedAppRecord.curAdj;
            if (DEBUG_OOM_ADJ) Slog.d(TAG,"app.processName = " + selectedAppRecord.processName
                        + " app.pid = " + selectedAppRecord.pid + " is moved to higher adj");
        }
        mNumServiceProcs = mNewNumServiceProcs;
+33 −3
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import com.android.server.wm.WindowManagerService;
import android.content.res.Resources;
import android.graphics.Point;
import android.os.SystemProperties;
import android.os.Process;
import android.net.LocalSocketAddress;
import android.net.LocalSocket;
import android.util.Slog;
@@ -146,6 +147,17 @@ final class ProcessList {
    // process limit.
    static final int MAX_CACHED_APPS = 32;

    static final boolean USE_TRIM_SETTINGS =
            SystemProperties.getBoolean("ro.sys.fw.use_trim_settings",true);
    static final int EMPTY_APP_PERCENT = SystemProperties.getInt("ro.sys.fw.empty_app_percent",50);
    static final int TRIM_EMPTY_PERCENT =
            SystemProperties.getInt("ro.sys.fw.trim_empty_percent",100);
    static final int TRIM_CACHE_PERCENT =
            SystemProperties.getInt("ro.sys.fw.trim_cache_percent",100);
    static final long TRIM_ENABLE_MEMORY =
            SystemProperties.getLong("ro.sys.fw.trim_enable_memory",1073741824);
    public static boolean allowTrim() { return Process.getTotalMemory() < TRIM_ENABLE_MEMORY ; }

    // We allow empty processes to stick around for at most 30 minutes.
    static final long MAX_EMPTY_TIME = 30*60*1000;

@@ -154,11 +166,25 @@ final class ProcessList {

    // The number of empty apps at which we don't consider it necessary to do
    // memory trimming.
    static final int TRIM_EMPTY_APPS = MAX_EMPTY_APPS/2;
    public static int computeTrimEmptyApps() {
        if (USE_TRIM_SETTINGS && allowTrim()) {
            return MAX_EMPTY_APPS*TRIM_EMPTY_PERCENT/100;
        } else {
            return MAX_EMPTY_APPS/2;
        }
    }
    static final int TRIM_EMPTY_APPS = computeTrimEmptyApps();

    // The number of cached at which we don't consider it necessary to do
    // memory trimming.
    static final int TRIM_CACHED_APPS = (MAX_CACHED_APPS-MAX_EMPTY_APPS)/3;
    public static int computeTrimCachedApps() {
        if (USE_TRIM_SETTINGS && allowTrim()) {
            return MAX_CACHED_APPS*TRIM_CACHE_PERCENT/100;
        } else {
            return (MAX_CACHED_APPS-MAX_EMPTY_APPS)/3;
        }
    }
    static final int TRIM_CACHED_APPS = computeTrimCachedApps();

    // Threshold of number of cached+empty where we consider memory critical.
    static final int TRIM_CRITICAL_THRESHOLD = 3;
@@ -319,8 +345,12 @@ final class ProcessList {
    }

    public static int computeEmptyProcessLimit(int totalProcessLimit) {
        if(USE_TRIM_SETTINGS && allowTrim()) {
            return totalProcessLimit*EMPTY_APP_PERCENT/100;
        } else {
            return totalProcessLimit/2;
        }
    }

    private static String buildOomTag(String prefix, String space, int val, int base) {
        if (val == base) {