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

Commit 2bd06a30 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add sample rate for app compaction metrics."

parents 2fbc1256 2384df75
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -5844,6 +5844,7 @@ package android.provider {
  public static interface DeviceConfig.ActivityManager {
    field public static final String KEY_COMPACT_ACTION_1 = "compact_action_1";
    field public static final String KEY_COMPACT_ACTION_2 = "compact_action_2";
    field public static final String KEY_COMPACT_STATSD_SAMPLE_RATE = "compact_statsd_sample_rate";
    field public static final String KEY_COMPACT_THROTTLE_1 = "compact_throttle_1";
    field public static final String KEY_COMPACT_THROTTLE_2 = "compact_throttle_2";
    field public static final String KEY_COMPACT_THROTTLE_3 = "compact_throttle_3";
+1 −0
Original line number Diff line number Diff line
@@ -261,6 +261,7 @@ public final class DeviceConfig {
        String KEY_COMPACT_THROTTLE_2 = "compact_throttle_2";
        String KEY_COMPACT_THROTTLE_3 = "compact_throttle_3";
        String KEY_COMPACT_THROTTLE_4 = "compact_throttle_4";
        String KEY_COMPACT_STATSD_SAMPLE_RATE = "compact_statsd_sample_rate";

        /**
         * Maximum number of cached processes. See
+42 −12
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.am;
import static android.os.Process.THREAD_PRIORITY_FOREGROUND;
import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_ACTION_1;
import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_ACTION_2;
import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_STATSD_SAMPLE_RATE;
import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_1;
import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_2;
import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_3;
@@ -45,6 +46,7 @@ import com.android.server.ServiceThread;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Random;

public final class AppCompactor {

@@ -65,6 +67,8 @@ public final class AppCompactor {
    @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_4 = 10_000;
    // The sampling rate to push app compaction events into statsd for upload.
    @VisibleForTesting static final float DEFAULT_STATSD_SAMPLE_RATE = 0.1f;

    @VisibleForTesting
    interface PropertyChangedCallbackForTest {
@@ -104,6 +108,8 @@ public final class AppCompactor {
                                || KEY_COMPACT_THROTTLE_3.equals(name)
                                || KEY_COMPACT_THROTTLE_4.equals(name)) {
                            updateCompactionThrottles();
                        } else if (KEY_COMPACT_STATSD_SAMPLE_RATE.equals(name)) {
                            updateStatsdSampleRate();
                        }
                    }
                    if (mTestCallback != null) {
@@ -116,21 +122,25 @@ public final class AppCompactor {

    // Configured by phenotype. Updates from the server take effect immediately.
    @GuardedBy("mPhenotypeFlagLock")
    @VisibleForTesting String mCompactActionSome =
    @VisibleForTesting volatile String mCompactActionSome =
            compactActionIntToString(DEFAULT_COMPACT_ACTION_1);
    @GuardedBy("mPhenotypeFlagLock")
    @VisibleForTesting String mCompactActionFull =
    @VisibleForTesting volatile String mCompactActionFull =
            compactActionIntToString(DEFAULT_COMPACT_ACTION_2);
    @GuardedBy("mPhenotypeFlagLock")
    @VisibleForTesting long mCompactThrottleSomeSome = DEFAULT_COMPACT_THROTTLE_1;
    @VisibleForTesting volatile long mCompactThrottleSomeSome = DEFAULT_COMPACT_THROTTLE_1;
    @GuardedBy("mPhenotypeFlagLock")
    @VisibleForTesting long mCompactThrottleSomeFull = DEFAULT_COMPACT_THROTTLE_2;
    @VisibleForTesting volatile long mCompactThrottleSomeFull = DEFAULT_COMPACT_THROTTLE_2;
    @GuardedBy("mPhenotypeFlagLock")
    @VisibleForTesting long mCompactThrottleFullSome = DEFAULT_COMPACT_THROTTLE_3;
    @VisibleForTesting volatile long mCompactThrottleFullSome = DEFAULT_COMPACT_THROTTLE_3;
    @GuardedBy("mPhenotypeFlagLock")
    @VisibleForTesting long mCompactThrottleFullFull = DEFAULT_COMPACT_THROTTLE_4;
    @VisibleForTesting volatile long mCompactThrottleFullFull = DEFAULT_COMPACT_THROTTLE_4;
    @GuardedBy("mPhenotypeFlagLock")
    private boolean mUseCompaction = DEFAULT_USE_COMPACTION;
    private volatile boolean mUseCompaction = DEFAULT_USE_COMPACTION;

    private final Random mRandom = new Random();
    @GuardedBy("mPhenotypeFlagLock")
    @VisibleForTesting volatile float mStatsdSampleRate = DEFAULT_STATSD_SAMPLE_RATE;

    // Handler on which compaction runs.
    private Handler mCompactionHandler;
@@ -158,6 +168,7 @@ public final class AppCompactor {
            updateUseCompaction();
            updateCompactionActions();
            updateCompactionThrottles();
            updateStatsdSampleRate();
        }
    }

@@ -181,6 +192,7 @@ public final class AppCompactor {
            pw.println("  " + KEY_COMPACT_THROTTLE_2 + "=" + mCompactThrottleSomeFull);
            pw.println("  " + KEY_COMPACT_THROTTLE_3 + "=" + mCompactThrottleFullSome);
            pw.println("  " + KEY_COMPACT_THROTTLE_4 + "=" + mCompactThrottleFullFull);
            pw.println("  " + KEY_COMPACT_STATSD_SAMPLE_RATE + "=" + mStatsdSampleRate);
        }
    }

@@ -289,6 +301,19 @@ public final class AppCompactor {
        }
    }

    @GuardedBy("mPhenotypeFlagLock")
    private void updateStatsdSampleRate() {
        String sampleRateFlag = DeviceConfig.getProperty(DeviceConfig.ActivityManager.NAMESPACE,
                KEY_COMPACT_STATSD_SAMPLE_RATE);
        try {
            mStatsdSampleRate = TextUtils.isEmpty(sampleRateFlag)
                    ? DEFAULT_STATSD_SAMPLE_RATE : Float.parseFloat(sampleRateFlag);
        } catch (NumberFormatException e) {
            mStatsdSampleRate = DEFAULT_STATSD_SAMPLE_RATE;
        }
        mStatsdSampleRate = Math.min(1.0f, Math.max(0.0f, mStatsdSampleRate));
    }

    @VisibleForTesting
    static String compactActionIntToString(int action) {
        switch(action) {
@@ -385,11 +410,16 @@ public final class AppCompactor {
                                rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3],
                                rssAfter[0], rssAfter[1], rssAfter[2], rssAfter[3], time,
                                lastCompactAction, lastCompactTime, msg.arg1, msg.arg2);
                        // Note that as above not taking mPhenoTypeFlagLock here to avoid locking
                        // on every single compaction for a flag that will seldom change and the
                        // impact of reading the wrong value here is low.
                        if (mRandom.nextFloat() < mStatsdSampleRate) {
                            StatsLog.write(StatsLog.APP_COMPACTED, pid, name, pendingAction,
                                    rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3],
                                    rssAfter[0], rssAfter[1], rssAfter[2], rssAfter[3], time,
                                    lastCompactAction, lastCompactTime, msg.arg1,
                                    ActivityManager.processStateAmToProto(msg.arg2));
                        }
                        synchronized (mAm) {
                            proc.lastCompactTime = end;
                            proc.lastCompactAction = pendingAction;
+77 −7
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.am;

import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_ACTION_1;
import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_ACTION_2;
import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_STATSD_SAMPLE_RATE;
import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_1;
import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_2;
import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_3;
@@ -61,6 +62,9 @@ import java.util.concurrent.TimeUnit;
@RunWith(AndroidJUnit4.class)
public final class AppCompactorTest {

    private static final String CLEAR_DEVICE_CONFIG_KEY_CMD =
            "device_config delete activity_manager";

    @Mock private AppOpsService mAppOpsService;
    private AppCompactor mCompactorUnderTest;
    private HandlerThread mHandlerThread;
@@ -70,19 +74,21 @@ public final class AppCompactorTest {
    private static void clearDeviceConfig() throws IOException  {
        UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
        uiDevice.executeShellCommand(
                "device_config delete activity_manager " + KEY_USE_COMPACTION);
                CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_USE_COMPACTION);
        uiDevice.executeShellCommand(
                CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_ACTION_1);
        uiDevice.executeShellCommand(
                "device_config delete activity_manager " + KEY_COMPACT_ACTION_1);
                CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_ACTION_2);
        uiDevice.executeShellCommand(
                "device_config delete activity_manager " + KEY_COMPACT_ACTION_2);
                CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_THROTTLE_1);
        uiDevice.executeShellCommand(
                "device_config delete activity_manager " + KEY_COMPACT_THROTTLE_1);
                CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_THROTTLE_2);
        uiDevice.executeShellCommand(
                "device_config delete activity_manager " + KEY_COMPACT_THROTTLE_2);
                CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_THROTTLE_3);
        uiDevice.executeShellCommand(
                "device_config delete activity_manager " + KEY_COMPACT_THROTTLE_3);
                CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_THROTTLE_4);
        uiDevice.executeShellCommand(
                "device_config delete activity_manager " + KEY_COMPACT_THROTTLE_4);
                CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_STATSD_SAMPLE_RATE);
    }

    @Before
@@ -128,6 +134,8 @@ public final class AppCompactorTest {
                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3));
        assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4));
        assertThat(mCompactorUnderTest.mStatsdSampleRate,
                is(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE));
    }

    @Test
@@ -155,6 +163,9 @@ public final class AppCompactorTest {
        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
                KEY_COMPACT_THROTTLE_4,
                Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1), false);
        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
                KEY_COMPACT_STATSD_SAMPLE_RATE,
                Float.toString(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f), false);

        // Then calling init will read and set that flag.
        mCompactorUnderTest.init();
@@ -173,6 +184,8 @@ public final class AppCompactorTest {
                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3 + 1));
        assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1));
        assertThat(mCompactorUnderTest.mStatsdSampleRate,
                is(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f));
    }

    @Test
@@ -365,6 +378,63 @@ public final class AppCompactorTest {
                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4));
    }

    @Test
    public void statsdSampleRate_listensToDeviceConfigChanges() throws InterruptedException {
        mCompactorUnderTest.init();

        // When we override mStatsdSampleRate with a reasonable values ...
        mCountDown = new CountDownLatch(1);
        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
                KEY_COMPACT_STATSD_SAMPLE_RATE,
                Float.toString(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f), false);
        assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));

        // Then that override is reflected in the compactor.
        assertThat(mCompactorUnderTest.mStatsdSampleRate,
                is(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f));
    }

    @Test
    public void statsdSanokeRate_listensToDeviceConfigChangesBadValues()
            throws InterruptedException {
        mCompactorUnderTest.init();

        // When we override mStatsdSampleRate with a reasonable values ...
        mCountDown = new CountDownLatch(1);
        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
                KEY_COMPACT_STATSD_SAMPLE_RATE, "foo", false);
        assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));

        // Then that override is reflected in the compactor.
        assertThat(mCompactorUnderTest.mStatsdSampleRate,
                is(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE));
    }

    @Test
    public void statsdSanokeRate_listensToDeviceConfigChangesOutOfRangeValues()
            throws InterruptedException {
        mCompactorUnderTest.init();

        // When we override mStatsdSampleRate with an value outside of [0..1]...
        mCountDown = new CountDownLatch(1);
        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
                KEY_COMPACT_STATSD_SAMPLE_RATE,
                Float.toString(-1.0f), false);
        assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));

        // Then the values is capped in the range.
        assertThat(mCompactorUnderTest.mStatsdSampleRate, is(0.0f));

        mCountDown = new CountDownLatch(1);
        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
                KEY_COMPACT_STATSD_SAMPLE_RATE,
                Float.toString(1.01f), false);
        assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));

        // Then the values is capped in the range.
        assertThat(mCompactorUnderTest.mStatsdSampleRate, is(1.0f));
    }

    private class TestInjector extends Injector {
        @Override
        public AppOpsService getAppOpsService(File file, Handler handler) {