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

Commit 094c3ef6 authored by Jing Ji's avatar Jing Ji
Browse files

OomAdjust Performance Improvement

* Reduce the number of processes to be computed.
* Reduce the overhead of getting process attributes

Overall by average the time spent on the OomAdjust update goes
down from 911us to 441us (51.6% faster) in Day-Of-Use test.

Bug: 135941673
Test: forrest test health/reliability/greenday
Test: Loop test
Test: atest MockingOomAdjusterTests
Test: atest FrameworksServicesTests:ActivityManagerServiceTest
Test: atest CtsAppTestCases:ActivityManagerProcessStateTest

Change-Id: I43cc4af4a268b24620c3231a87f7c9d2a14e4fbc
parent 79431843
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -1819,7 +1819,7 @@ public final class ActiveServices {
                                || (callerApp.getCurProcState() <= ActivityManager.PROCESS_STATE_TOP
                                        && (flags & Context.BIND_TREAT_LIKE_ACTIVITY) != 0),
                        b.client);
                mAm.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE);
                mAm.updateOomAdjLocked(s.app, OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE);
            }

            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bind " + s + " with " + b
@@ -2701,7 +2701,7 @@ public final class ActiveServices {
        bumpServiceExecutingLocked(r, execInFg, "create");
        mAm.updateLruProcessLocked(app, false, null);
        updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
        mAm.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
        mAm.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_START_SERVICE);

        boolean created = false;
        try {
+26 −0
Original line number Diff line number Diff line
@@ -282,6 +282,19 @@ final class ActivityManagerConstants extends ContentObserver {
    // memory trimming.
    public int CUR_TRIM_CACHED_PROCESSES;

    @SuppressWarnings("unused")
    private static final int OOMADJ_UPDATE_POLICY_SLOW = 0;
    private static final int OOMADJ_UPDATE_POLICY_QUICK = 1;
    private static final int DEFAULT_OOMADJ_UPDATE_POLICY = OOMADJ_UPDATE_POLICY_QUICK;

    private static final String KEY_OOMADJ_UPDATE_POLICY = "oomadj_update_policy";

    // Indicate if the oom adjuster should take the quick path to update the oom adj scores,
    // in which no futher actions will be performed if there are no significant adj/proc state
    // changes for the specific process; otherwise, use the traditonal slow path which would
    // keep updating all processes in the LRU list.
    public boolean OOMADJ_UPDATE_QUICK = DEFAULT_OOMADJ_UPDATE_POLICY == OOMADJ_UPDATE_POLICY_QUICK;

    private static final long MIN_AUTOMATIC_HEAP_DUMP_PSS_THRESHOLD_BYTES = 100 * 1024; // 100 KB

    private final boolean mSystemServerAutomaticHeapDumpEnabled;
@@ -316,6 +329,9 @@ final class ActivityManagerConstants extends ContentObserver {
                            case KEY_DEFAULT_BACKGROUND_ACTIVITY_STARTS_ENABLED:
                                updateBackgroundActivityStarts();
                                break;
                            case KEY_OOMADJ_UPDATE_POLICY:
                                updateOomAdjUpdatePolicy();
                                break;
                            default:
                                break;
                        }
@@ -354,6 +370,7 @@ final class ActivityManagerConstants extends ContentObserver {
        updateMaxCachedProcesses();
        updateActivityStartsLoggingEnabled();
        updateBackgroundActivityStarts();
        updateOomAdjUpdatePolicy();
    }

    public void setOverrideMaxCachedProcesses(int value) {
@@ -472,6 +489,14 @@ final class ActivityManagerConstants extends ContentObserver {
                /*defaultValue*/ false);
    }

    private void updateOomAdjUpdatePolicy() {
        OOMADJ_UPDATE_QUICK = DeviceConfig.getInt(
                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                KEY_OOMADJ_UPDATE_POLICY,
                /* defaultValue */ DEFAULT_OOMADJ_UPDATE_POLICY)
                == OOMADJ_UPDATE_POLICY_QUICK;
    }

    private void updateEnableAutomaticSystemServerHeapDumps() {
        if (!mSystemServerAutomaticHeapDumpEnabled) {
            Slog.wtf(TAG,
@@ -587,5 +612,6 @@ final class ActivityManagerConstants extends ContentObserver {
        pw.print("  CUR_MAX_EMPTY_PROCESSES="); pw.println(CUR_MAX_EMPTY_PROCESSES);
        pw.print("  CUR_TRIM_EMPTY_PROCESSES="); pw.println(CUR_TRIM_EMPTY_PROCESSES);
        pw.print("  CUR_TRIM_CACHED_PROCESSES="); pw.println(CUR_TRIM_CACHED_PROCESSES);
        pw.print("  OOMADJ_UPDATE_QUICK="); pw.println(OOMADJ_UPDATE_QUICK);
    }
}
+21 −138
Original line number Diff line number Diff line
@@ -42,8 +42,6 @@ import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode;
import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground;
import static android.os.FactoryTest.FACTORY_TEST_OFF;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
@@ -424,7 +422,7 @@ public class ActivityManagerService extends IActivityManager.Stub
    private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
    static final String TAG_LRU = TAG + POSTFIX_LRU;
    private static final String TAG_MU = TAG + POSTFIX_MU;
    private static final String TAG_NETWORK = TAG + POSTFIX_NETWORK;
    static final String TAG_NETWORK = TAG + POSTFIX_NETWORK;
    static final String TAG_OOM_ADJ = TAG + POSTFIX_OOM_ADJ;
    private static final String TAG_POWER = TAG + POSTFIX_POWER;
    static final String TAG_PROCESS_OBSERVERS = TAG + POSTFIX_PROCESS_OBSERVERS;
@@ -534,24 +532,6 @@ public class ActivityManagerService extends IActivityManager.Stub
     */
    private static final int BINDER_PROXY_LOW_WATERMARK = 5500;
    /**
     * State indicating that there is no need for any blocking for network.
     */
    @VisibleForTesting
    static final int NETWORK_STATE_NO_CHANGE = 0;
    /**
     * State indicating that the main thread needs to be informed about the network wait.
     */
    @VisibleForTesting
    static final int NETWORK_STATE_BLOCK = 1;
    /**
     * State indicating that any threads waiting for network state to get updated can be unblocked.
     */
    @VisibleForTesting
    static final int NETWORK_STATE_UNBLOCK = 2;
    // Max character limit for a notification title. If the notification title is larger than this
    // the notification will not be legible to the user.
    private static final int MAX_BUGREPORT_TITLE_SIZE = 50;
@@ -1360,7 +1340,7 @@ public class ActivityManagerService extends IActivityManager.Stub
    String mTrackAllocationApp = null;
    String mNativeDebuggingApp = null;
    private final Injector mInjector;
    final Injector mInjector;
    static final class ProcessChangeItem {
        static final int CHANGE_ACTIVITIES = 1<<0;
@@ -5171,7 +5151,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        }
        if (!didSomething) {
            updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN);
            updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN);
            checkTime(startTime, "attachApplicationLocked: after updateOomAdjLocked");
        }
@@ -5686,6 +5666,7 @@ public class ActivityManagerService extends IActivityManager.Stub
    void importanceTokenDied(ImportanceToken token) {
        synchronized (ActivityManagerService.this) {
            ProcessRecord pr = null;
            synchronized (mPidsSelfLocked) {
                ImportanceToken cur
                    = mImportantProcesses.get(token.pid);
@@ -5693,14 +5674,14 @@ public class ActivityManagerService extends IActivityManager.Stub
                    return;
                }
                mImportantProcesses.remove(token.pid);
                ProcessRecord pr = mPidsSelfLocked.get(token.pid);
                pr = mPidsSelfLocked.get(token.pid);
                if (pr == null) {
                    return;
                }
                pr.forcingToImportant = null;
                updateProcessForegroundLocked(pr, false, 0, false);
            }
            updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY);
            updateOomAdjLocked(pr, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY);
        }
    }
@@ -5711,8 +5692,9 @@ public class ActivityManagerService extends IActivityManager.Stub
        synchronized(this) {
            boolean changed = false;
            ProcessRecord pr = null;
            synchronized (mPidsSelfLocked) {
                ProcessRecord pr = mPidsSelfLocked.get(pid);
                pr = mPidsSelfLocked.get(pid);
                if (pr == null && isForeground) {
                    Slog.w(TAG, "setProcessForeground called on unknown pid: " + pid);
                    return;
@@ -5746,7 +5728,7 @@ public class ActivityManagerService extends IActivityManager.Stub
            }
            if (changed) {
                updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY);
                updateOomAdjLocked(pr, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY);
            }
        }
    }
@@ -7890,7 +7872,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                    new HostingRecord("added application",
                            customProcess != null ? customProcess : info.processName));
            mProcessList.updateLruProcessLocked(app, false, null);
            updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN);
            updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN);
        }
        // This package really, really can not be stopped.
@@ -17031,7 +17013,7 @@ public class ActivityManagerService extends IActivityManager.Stub
            item.foregroundServiceTypes = fgServiceTypes;
            if (oomAdj) {
                updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY);
                updateOomAdjLocked(proc, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY);
            }
        }
    }
@@ -17286,6 +17268,16 @@ public class ActivityManagerService extends IActivityManager.Stub
        mOomAdjuster.updateOomAdjLocked(oomAdjReason);
    }
    /*
     * Update OomAdj for a specific process and its reachable processes.
     * @param app The process to update
     * @param oomAdjReason
     */
    @GuardedBy("this")
    final void updateOomAdjLocked(ProcessRecord app, String oomAdjReason) {
        mOomAdjuster.updateOomAdjLocked(app, oomAdjReason);
    }
    @Override
    public void makePackageIdle(String packageName, int userId) {
        if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
@@ -17352,115 +17344,6 @@ public class ActivityManagerService extends IActivityManager.Stub
        }
    }
    /**
     * Checks if any uid is coming from background to foreground or vice versa and if so, increments
     * the {@link UidRecord#curProcStateSeq} corresponding to that uid using global seq counter
     * {@link ProcessList#mProcStateSeqCounter} and notifies the app if it needs to block.
     */
    @VisibleForTesting
    @GuardedBy("this")
    void incrementProcStateSeqAndNotifyAppsLocked() {
        if (mWaitForNetworkTimeoutMs <= 0) {
            return;
        }
        // Used for identifying which uids need to block for network.
        ArrayList<Integer> blockingUids = null;
        for (int i = mProcessList.mActiveUids.size() - 1; i >= 0; --i) {
            final UidRecord uidRec = mProcessList.mActiveUids.valueAt(i);
            // If the network is not restricted for uid, then nothing to do here.
            if (!mInjector.isNetworkRestrictedForUid(uidRec.uid)) {
                continue;
            }
            if (!UserHandle.isApp(uidRec.uid) || !uidRec.hasInternetPermission) {
                continue;
            }
            // If process state is not changed, then there's nothing to do.
            if (uidRec.setProcState == uidRec.getCurProcState()) {
                continue;
            }
            final int blockState = getBlockStateForUid(uidRec);
            // No need to inform the app when the blockState is NETWORK_STATE_NO_CHANGE as
            // there's nothing the app needs to do in this scenario.
            if (blockState == NETWORK_STATE_NO_CHANGE) {
                continue;
            }
            synchronized (uidRec.networkStateLock) {
                uidRec.curProcStateSeq = ++mProcessList.mProcStateSeqCounter; // TODO: use method
                if (blockState == NETWORK_STATE_BLOCK) {
                    if (blockingUids == null) {
                        blockingUids = new ArrayList<>();
                    }
                    blockingUids.add(uidRec.uid);
                } else {
                    if (DEBUG_NETWORK) {
                        Slog.d(TAG_NETWORK, "uid going to background, notifying all blocking"
                                + " threads for uid: " + uidRec);
                    }
                    if (uidRec.waitingForNetwork) {
                        uidRec.networkStateLock.notifyAll();
                    }
                }
            }
        }
        // There are no uids that need to block, so nothing more to do.
        if (blockingUids == null) {
            return;
        }
        for (int i = mProcessList.mLruProcesses.size() - 1; i >= 0; --i) {
            final ProcessRecord app = mProcessList.mLruProcesses.get(i);
            if (!blockingUids.contains(app.uid)) {
                continue;
            }
            if (!app.killedByAm && app.thread != null) {
                final UidRecord uidRec = mProcessList.getUidRecordLocked(app.uid);
                try {
                    if (DEBUG_NETWORK) {
                        Slog.d(TAG_NETWORK, "Informing app thread that it needs to block: "
                                + uidRec);
                    }
                    if (uidRec != null) {
                        app.thread.setNetworkBlockSeq(uidRec.curProcStateSeq);
                    }
                } catch (RemoteException ignored) {
                }
            }
        }
    }
    /**
     * Checks if the uid is coming from background to foreground or vice versa and returns
     * appropriate block state based on this.
     *
     * @return blockState based on whether the uid is coming from background to foreground or
     *         vice versa. If bg->fg or fg->bg, then {@link #NETWORK_STATE_BLOCK} or
     *         {@link #NETWORK_STATE_UNBLOCK} respectively, otherwise
     *         {@link #NETWORK_STATE_NO_CHANGE}.
     */
    @VisibleForTesting
    int getBlockStateForUid(UidRecord uidRec) {
        // Denotes whether uid's process state is currently allowed network access.
        final boolean isAllowed =
                isProcStateAllowedWhileIdleOrPowerSaveMode(uidRec.getCurProcState())
                || isProcStateAllowedWhileOnRestrictBackground(uidRec.getCurProcState());
        // Denotes whether uid's process state was previously allowed network access.
        final boolean wasAllowed = isProcStateAllowedWhileIdleOrPowerSaveMode(uidRec.setProcState)
                || isProcStateAllowedWhileOnRestrictBackground(uidRec.setProcState);
        // When the uid is coming to foreground, AMS should inform the app thread that it should
        // block for the network rules to get updated before launching an activity.
        if (!wasAllowed && isAllowed) {
            return NETWORK_STATE_BLOCK;
        }
        // When the uid is going to background, AMS should inform the app thread that if an
        // activity launch is blocked for the network rules to get updated, it should be unblocked.
        if (wasAllowed && !isAllowed) {
            return NETWORK_STATE_UNBLOCK;
        }
        return NETWORK_STATE_NO_CHANGE;
    }
    final void runInBackgroundDisabled(int uid) {
        synchronized (this) {
            UidRecord uidRec = mProcessList.getUidRecordLocked(uid);
+1 −1
Original line number Diff line number Diff line
@@ -309,7 +309,7 @@ public final class BroadcastQueue {
        app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
        mService.mProcessList.updateLruProcessLocked(app, false, null);
        if (!skipOomAdj) {
            mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
            mService.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_NONE);
        }

        // Tell the application to launch this receiver.
+36 −10
Original line number Diff line number Diff line
@@ -45,7 +45,7 @@ public class OomAdjProfiler {
    private boolean mLastScheduledScreenOff;

    @GuardedBy("this")
    private long mOomAdjStartTimeMs;
    private long mOomAdjStartTimeUs;
    @GuardedBy("this")
    private boolean mOomAdjStarted;

@@ -65,6 +65,11 @@ public class OomAdjProfiler {
    @GuardedBy("this")
    final RingBuffer<CpuTimes> mSystemServerCpuTimesHist = new RingBuffer<>(CpuTimes.class, 10);

    @GuardedBy("this")
    private long mTotalOomAdjRunTimeUs;
    @GuardedBy("this")
    private int mTotalOomAdjCalls;

    void batteryPowerChanged(boolean onBattery) {
        synchronized (this) {
            scheduleSystemServerCpuTimeUpdate();
@@ -81,7 +86,7 @@ public class OomAdjProfiler {

    void oomAdjStarted() {
        synchronized (this) {
            mOomAdjStartTimeMs = SystemClock.currentThreadTimeMillis();
            mOomAdjStartTimeUs = SystemClock.currentThreadTimeMicro();
            mOomAdjStarted = true;
        }
    }
@@ -91,7 +96,10 @@ public class OomAdjProfiler {
            if (!mOomAdjStarted) {
                return;
            }
            mOomAdjRunTime.addCpuTimeMs(SystemClock.currentThreadTimeMillis() - mOomAdjStartTimeMs);
            long elapsedUs = SystemClock.currentThreadTimeMicro() - mOomAdjStartTimeUs;
            mOomAdjRunTime.addCpuTimeUs(elapsedUs);
            mTotalOomAdjRunTimeUs += elapsedUs;
            mTotalOomAdjCalls++;
        }
    }

@@ -169,32 +177,50 @@ public class OomAdjProfiler {
                pw.print("oom_adj=");
                pw.println(oomAdjRunTimes[i]);
            }
            if (mTotalOomAdjCalls != 0) {
                pw.println("System server total oomAdj runtimes (us) since boot:");
                pw.print("  cpu time spent=");
                pw.print(mTotalOomAdjRunTimeUs);
                pw.print("  number of calls=");
                pw.print(mTotalOomAdjCalls);
                pw.print("  average=");
                pw.println(mTotalOomAdjRunTimeUs / mTotalOomAdjCalls);
            }
        }
    }

    private class CpuTimes {
        private long mOnBatteryTimeMs;
        private long mOnBatteryScreenOffTimeMs;
        private long mOnBatteryTimeUs;
        private long mOnBatteryScreenOffTimeUs;

        public void addCpuTimeMs(long cpuTimeMs) {
            addCpuTimeMs(cpuTimeMs, mOnBattery, mScreenOff);
            addCpuTimeUs(cpuTimeMs * 1000, mOnBattery, mScreenOff);
        }

        public void addCpuTimeMs(long cpuTimeMs, boolean onBattery, boolean screenOff) {
            addCpuTimeUs(cpuTimeMs * 1000, onBattery, screenOff);
        }

        public void addCpuTimeUs(long cpuTimeUs) {
            addCpuTimeUs(cpuTimeUs, mOnBattery, mScreenOff);
        }

        public void addCpuTimeUs(long cpuTimeUs, boolean onBattery, boolean screenOff) {
            if (onBattery) {
                mOnBatteryTimeMs += cpuTimeMs;
                mOnBatteryTimeUs += cpuTimeUs;
                if (screenOff) {
                    mOnBatteryScreenOffTimeMs += cpuTimeMs;
                    mOnBatteryScreenOffTimeUs += cpuTimeUs;
                }
            }
        }

        public boolean isEmpty() {
            return mOnBatteryTimeMs == 0 && mOnBatteryScreenOffTimeMs == 0;
            return mOnBatteryTimeUs == 0 && mOnBatteryScreenOffTimeUs == 0;
        }

        public String toString() {
            return "[" + mOnBatteryTimeMs + "," + mOnBatteryScreenOffTimeMs + "]";
            return "[" + (mOnBatteryTimeUs / 1000) + ","
                    + (mOnBatteryScreenOffTimeUs / 1000) + "]";
        }
    }
}
Loading