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

Commit 72af24e0 authored by Tim Murray's avatar Tim Murray Committed by Automerger Merge Worker
Browse files

Merge "CachedAppOptimizer: kill apps that spam binder transactions" into...

Merge "CachedAppOptimizer: kill apps that spam binder transactions" into udc-dev am: c8e36828 am: 0fe72199

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/23712932



Change-Id: I4218d506e64cd446dd4feac8e7097be3a087ba9f
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 97d73a7e 0fe72199
Loading
Loading
Loading
Loading
+104 −11
Original line number Original line Diff line number Diff line
@@ -123,7 +123,14 @@ public final class CachedAppOptimizer {
            "freeze_debounce_timeout";
            "freeze_debounce_timeout";
    @VisibleForTesting static final String KEY_FREEZER_EXEMPT_INST_PKG =
    @VisibleForTesting static final String KEY_FREEZER_EXEMPT_INST_PKG =
            "freeze_exempt_inst_pkg";
            "freeze_exempt_inst_pkg";

    @VisibleForTesting static final String KEY_FREEZER_BINDER_ENABLED =
            "freeze_binder_enabled";
    @VisibleForTesting static final String KEY_FREEZER_BINDER_DIVISOR =
            "freeze_binder_divisor";
    @VisibleForTesting static final String KEY_FREEZER_BINDER_OFFSET =
            "freeze_binder_offset";
    @VisibleForTesting static final String KEY_FREEZER_BINDER_THRESHOLD =
            "freeze_binder_threshold";


    static final int UNFREEZE_REASON_NONE =
    static final int UNFREEZE_REASON_NONE =
            FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_NONE;
            FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_NONE;
@@ -237,8 +244,8 @@ public final class CachedAppOptimizer {
    @VisibleForTesting static final boolean ENABLE_FILE_COMPACT = false;
    @VisibleForTesting static final boolean ENABLE_FILE_COMPACT = false;


    // Defaults for phenotype flags.
    // Defaults for phenotype flags.
    @VisibleForTesting static final Boolean DEFAULT_USE_COMPACTION = true;
    @VisibleForTesting static final boolean DEFAULT_USE_COMPACTION = true;
    @VisibleForTesting static final Boolean DEFAULT_USE_FREEZER = true;
    @VisibleForTesting static final boolean DEFAULT_USE_FREEZER = true;
    @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_1 = 5_000;
    @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_1 = 5_000;
    @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_2 = 10_000;
    @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_2 = 10_000;
    @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_3 = 500;
    @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_3 = 500;
@@ -257,7 +264,11 @@ public final class CachedAppOptimizer {
    @VisibleForTesting static final String DEFAULT_COMPACT_PROC_STATE_THROTTLE =
    @VisibleForTesting static final String DEFAULT_COMPACT_PROC_STATE_THROTTLE =
            String.valueOf(ActivityManager.PROCESS_STATE_RECEIVER);
            String.valueOf(ActivityManager.PROCESS_STATE_RECEIVER);
    @VisibleForTesting static final long DEFAULT_FREEZER_DEBOUNCE_TIMEOUT = 10_000L;
    @VisibleForTesting static final long DEFAULT_FREEZER_DEBOUNCE_TIMEOUT = 10_000L;
    @VisibleForTesting static final Boolean DEFAULT_FREEZER_EXEMPT_INST_PKG = true;
    @VisibleForTesting static final boolean DEFAULT_FREEZER_EXEMPT_INST_PKG = true;
    @VisibleForTesting static final boolean DEFAULT_FREEZER_BINDER_ENABLED = true;
    @VisibleForTesting static final long DEFAULT_FREEZER_BINDER_DIVISOR = 4;
    @VisibleForTesting static final int DEFAULT_FREEZER_BINDER_OFFSET = 500;
    @VisibleForTesting static final long DEFAULT_FREEZER_BINDER_THRESHOLD = 1_000;


    @VisibleForTesting static final Uri CACHED_APP_FREEZER_ENABLED_URI = Settings.Global.getUriFor(
    @VisibleForTesting static final Uri CACHED_APP_FREEZER_ENABLED_URI = Settings.Global.getUriFor(
                Settings.Global.CACHED_APPS_FREEZER_ENABLED);
                Settings.Global.CACHED_APPS_FREEZER_ENABLED);
@@ -393,6 +404,11 @@ public final class CachedAppOptimizer {
                                updateFreezerDebounceTimeout();
                                updateFreezerDebounceTimeout();
                            } else if (KEY_FREEZER_EXEMPT_INST_PKG.equals(name)) {
                            } else if (KEY_FREEZER_EXEMPT_INST_PKG.equals(name)) {
                                updateFreezerExemptInstPkg();
                                updateFreezerExemptInstPkg();
                            } else if (KEY_FREEZER_BINDER_ENABLED.equals(name)
                                    || KEY_FREEZER_BINDER_DIVISOR.equals(name)
                                    || KEY_FREEZER_BINDER_THRESHOLD.equals(name)
                                    || KEY_FREEZER_BINDER_OFFSET.equals(name)) {
                                updateFreezerBinderState();
                            }
                            }
                        }
                        }
                    }
                    }
@@ -455,6 +471,16 @@ public final class CachedAppOptimizer {
    @GuardedBy("mPhenotypeFlagLock")
    @GuardedBy("mPhenotypeFlagLock")
    @VisibleForTesting final Set<Integer> mProcStateThrottle;
    @VisibleForTesting final Set<Integer> mProcStateThrottle;


    @GuardedBy("mPhenotypeFlagLock")
    @VisibleForTesting volatile boolean mFreezerBinderEnabled = DEFAULT_FREEZER_BINDER_ENABLED;
    @GuardedBy("mPhenotypeFlagLock")
    @VisibleForTesting volatile long mFreezerBinderDivisor = DEFAULT_FREEZER_BINDER_DIVISOR;
    @GuardedBy("mPhenotypeFlagLock")
    @VisibleForTesting volatile int mFreezerBinderOffset = DEFAULT_FREEZER_BINDER_OFFSET;
    @GuardedBy("mPhenotypeFlagLock")
    @VisibleForTesting volatile long mFreezerBinderThreshold = DEFAULT_FREEZER_BINDER_THRESHOLD;


    // Handler on which compaction runs.
    // Handler on which compaction runs.
    @VisibleForTesting
    @VisibleForTesting
    Handler mCompactionHandler;
    Handler mCompactionHandler;
@@ -759,6 +785,10 @@ public final class CachedAppOptimizer {
            pw.println("  " + KEY_FREEZER_STATSD_SAMPLE_RATE + "=" + mFreezerStatsdSampleRate);
            pw.println("  " + KEY_FREEZER_STATSD_SAMPLE_RATE + "=" + mFreezerStatsdSampleRate);
            pw.println("  " + KEY_FREEZER_DEBOUNCE_TIMEOUT + "=" + mFreezerDebounceTimeout);
            pw.println("  " + KEY_FREEZER_DEBOUNCE_TIMEOUT + "=" + mFreezerDebounceTimeout);
            pw.println("  " + KEY_FREEZER_EXEMPT_INST_PKG + "=" + mFreezerExemptInstPkg);
            pw.println("  " + KEY_FREEZER_EXEMPT_INST_PKG + "=" + mFreezerExemptInstPkg);
            pw.println("  " + KEY_FREEZER_BINDER_ENABLED + "=" + mFreezerBinderEnabled);
            pw.println("  " + KEY_FREEZER_BINDER_THRESHOLD + "=" + mFreezerBinderThreshold);
            pw.println("  " + KEY_FREEZER_BINDER_DIVISOR + "=" + mFreezerBinderDivisor);
            pw.println("  " + KEY_FREEZER_BINDER_OFFSET + "=" + mFreezerBinderOffset);
            synchronized (mProcLock) {
            synchronized (mProcLock) {
                int size = mFrozenProcesses.size();
                int size = mFrozenProcesses.size();
                pw.println("  Apps frozen: " + size);
                pw.println("  Apps frozen: " + size);
@@ -1264,6 +1294,26 @@ public final class CachedAppOptimizer {
        Slog.d(TAG_AM, "Freezer exemption set to " + mFreezerExemptInstPkg);
        Slog.d(TAG_AM, "Freezer exemption set to " + mFreezerExemptInstPkg);
    }
    }


    @GuardedBy("mPhenotypeFlagLock")
    private void updateFreezerBinderState() {
        mFreezerBinderEnabled = DeviceConfig.getBoolean(
                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
                KEY_FREEZER_BINDER_ENABLED, DEFAULT_FREEZER_BINDER_ENABLED);
        mFreezerBinderDivisor = DeviceConfig.getLong(
                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
                KEY_FREEZER_BINDER_DIVISOR, DEFAULT_FREEZER_BINDER_DIVISOR);
        mFreezerBinderOffset = DeviceConfig.getInt(
                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
                KEY_FREEZER_BINDER_OFFSET, DEFAULT_FREEZER_BINDER_OFFSET);
        mFreezerBinderThreshold = DeviceConfig.getLong(
                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
                KEY_FREEZER_BINDER_THRESHOLD, DEFAULT_FREEZER_BINDER_THRESHOLD);
        Slog.d(TAG_AM, "Freezer binder state set to enabled=" + mFreezerBinderEnabled
                + ", divisor=" + mFreezerBinderDivisor
                + ", offset=" + mFreezerBinderOffset
                + ", threshold=" + mFreezerBinderThreshold);
    }

    private boolean parseProcStateThrottle(String procStateThrottleString) {
    private boolean parseProcStateThrottle(String procStateThrottleString) {
        String[] procStates = TextUtils.split(procStateThrottleString, ",");
        String[] procStates = TextUtils.split(procStateThrottleString, ",");
        mProcStateThrottle.clear();
        mProcStateThrottle.clear();
@@ -1352,6 +1402,7 @@ public final class CachedAppOptimizer {
                }
                }
            }
            }
        }
        }
        app.mOptRecord.setLastUsedTimeout(delayMillis);
        mFreezeHandler.sendMessageDelayed(
        mFreezeHandler.sendMessageDelayed(
                mFreezeHandler.obtainMessage(SET_FROZEN_PROCESS_MSG, DO_FREEZE, 0, app),
                mFreezeHandler.obtainMessage(SET_FROZEN_PROCESS_MSG, DO_FREEZE, 0, app),
                delayMillis);
                delayMillis);
@@ -2121,12 +2172,54 @@ public final class CachedAppOptimizer {
        }
        }


        @GuardedBy({"mAm", "mProcLock"})
        @GuardedBy({"mAm", "mProcLock"})
        private void rescheduleFreeze(final ProcessRecord proc, final String reason,
        private void handleBinderFreezerFailure(final ProcessRecord proc, final String reason) {
                @UnfreezeReason int reasonCode) {
            if (!mFreezerBinderEnabled) {
            Slog.d(TAG_AM, "Reschedule freeze for process " + proc.getPid()
                // Just reschedule indefinitely.
                    + " " + proc.processName + " (" + reason + ")");
                unfreezeAppLSP(proc, UNFREEZE_REASON_BINDER_TXNS);
            unfreezeAppLSP(proc, reasonCode);
                freezeAppAsyncLSP(proc);
                freezeAppAsyncLSP(proc);
                return;
            }
            /*
             * This handles the case where a process couldn't be frozen due to pending binder
             * transactions. In order to prevent apps from avoiding the freezer by spamming binder
             * transactions, there is an exponential decrease in freezer retry times plus a random
             * offset per attempt to avoid phase issues. Once the last-attempted timeout is below a
             * threshold, we assume that the app is spamming binder calls and can never be frozen,
             * and we will then crash the app.
             */
            if (proc.mOptRecord.getLastUsedTimeout() <= mFreezerBinderThreshold) {
                // We've given the app plenty of chances, assume broken. Time to die.
                Slog.d(TAG_AM, "Kill app due to repeated failure to freeze binder: "
                        + proc.getPid() + " " + proc.processName);
                mAm.mHandler.post(() -> {
                    synchronized (mAm) {
                        // Crash regardless of procstate in case the app has found another way
                        // to abuse oom_adj
                        if (proc.getThread() == null) {
                            return;
                        }
                        proc.killLocked("excessive binder traffic during cached",
                                ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE,
                                ApplicationExitInfo.SUBREASON_EXCESSIVE_CPU,
                                true);
                    }
                });
                return;
            }

            long timeout = proc.mOptRecord.getLastUsedTimeout() / mFreezerBinderDivisor;
            // range is [-mFreezerBinderOffset, +mFreezerBinderOffset]
            int offset = mRandom.nextInt(mFreezerBinderOffset * 2) - mFreezerBinderOffset;
            timeout = Math.max(timeout + offset, mFreezerBinderThreshold);

            Slog.d(TAG_AM, "Reschedule freeze for process " + proc.getPid()
                    + " " + proc.processName + " (" + reason  + "), timeout=" + timeout);
            Trace.instantForTrack(Trace.TRACE_TAG_ACTIVITY_MANAGER, ATRACE_FREEZER_TRACK,
                    "Reschedule freeze " + proc.processName + ":" + proc.getPid()
                    + " timeout=" + timeout + ", reason=" + reason);

            unfreezeAppLSP(proc, UNFREEZE_REASON_BINDER_TXNS);
            freezeAppAsyncLSP(proc, timeout);
        }
        }


        /**
        /**
@@ -2173,7 +2266,7 @@ public final class CachedAppOptimizer {
                // transactions that might be pending.
                // transactions that might be pending.
                try {
                try {
                    if (freezeBinder(pid, true, FREEZE_BINDER_TIMEOUT_MS) != 0) {
                    if (freezeBinder(pid, true, FREEZE_BINDER_TIMEOUT_MS) != 0) {
                        rescheduleFreeze(proc, "outstanding txns", UNFREEZE_REASON_BINDER_TXNS);
                        handleBinderFreezerFailure(proc, "outstanding txns");
                        return;
                        return;
                    }
                    }
                } catch (RuntimeException e) {
                } catch (RuntimeException e) {
@@ -2234,7 +2327,7 @@ public final class CachedAppOptimizer {


                if ((freezeInfo & TXNS_PENDING_WHILE_FROZEN) != 0) {
                if ((freezeInfo & TXNS_PENDING_WHILE_FROZEN) != 0) {
                    synchronized (mProcLock) {
                    synchronized (mProcLock) {
                        rescheduleFreeze(proc, "new pending txns", UNFREEZE_REASON_BINDER_TXNS);
                        handleBinderFreezerFailure(proc, "new pending txns");
                    }
                    }
                    return;
                    return;
                }
                }
+16 −0
Original line number Original line Diff line number Diff line
@@ -127,6 +127,12 @@ final class ProcessCachedOptimizerRecord {
    @GuardedBy("mProcLock")
    @GuardedBy("mProcLock")
    private @UptimeMillisLong long mEarliestFreezableTimeMillis;
    private @UptimeMillisLong long mEarliestFreezableTimeMillis;


    /**
     * This is the most recently used timeout for freezing the app in millis
     */
    @GuardedBy("mProcLock")
    private long mLastUsedTimeout;

    @GuardedBy("mProcLock")
    @GuardedBy("mProcLock")
    long getLastCompactTime() {
    long getLastCompactTime() {
        return mLastCompactTime;
        return mLastCompactTime;
@@ -281,6 +287,16 @@ final class ProcessCachedOptimizerRecord {
        mEarliestFreezableTimeMillis = earliestFreezableTimeMillis;
        mEarliestFreezableTimeMillis = earliestFreezableTimeMillis;
    }
    }


    @GuardedBy("mProcLock")
    long getLastUsedTimeout() {
        return mLastUsedTimeout;
    }

    @GuardedBy("mProcLock")
    void setLastUsedTimeout(long lastUsedTimeout) {
        mLastUsedTimeout = lastUsedTimeout;
    }

    @GuardedBy("mProcLock")
    @GuardedBy("mProcLock")
    boolean isFreezeExempt() {
    boolean isFreezeExempt() {
        return mFreezeExempt;
        return mFreezeExempt;