Merge "Add sample rate for app compaction metrics."
diff --git a/api/system-current.txt b/api/system-current.txt
index d061d01..a203b41 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5844,6 +5844,7 @@
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";
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 30c0731..ea35077 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -261,6 +261,7 @@
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
diff --git a/services/core/java/com/android/server/am/AppCompactor.java b/services/core/java/com/android/server/am/AppCompactor.java
index bb55ec31..1118014 100644
--- a/services/core/java/com/android/server/am/AppCompactor.java
+++ b/services/core/java/com/android/server/am/AppCompactor.java
@@ -19,6 +19,7 @@
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 java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Random;
public final class AppCompactor {
@@ -65,6 +67,8 @@
@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 @@
|| 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 @@
// 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 @@
updateUseCompaction();
updateCompactionActions();
updateCompactionThrottles();
+ updateStatsdSampleRate();
}
}
@@ -181,6 +192,7 @@
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 @@
}
}
+ @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 @@
rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3],
rssAfter[0], rssAfter[1], rssAfter[2], rssAfter[3], time,
lastCompactAction, lastCompactTime, msg.arg1, msg.arg2);
- 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));
+ // 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;
diff --git a/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java b/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java
index 1a231cf..2f8e545 100644
--- a/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java
@@ -18,6 +18,7 @@
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 @@
@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 @@
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(
- "device_config delete activity_manager " + KEY_COMPACT_ACTION_1);
+ CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_ACTION_1);
uiDevice.executeShellCommand(
- "device_config delete activity_manager " + KEY_COMPACT_ACTION_2);
+ CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_ACTION_2);
uiDevice.executeShellCommand(
- "device_config delete activity_manager " + KEY_COMPACT_THROTTLE_1);
+ CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_THROTTLE_1);
uiDevice.executeShellCommand(
- "device_config delete activity_manager " + KEY_COMPACT_THROTTLE_2);
+ CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_THROTTLE_2);
uiDevice.executeShellCommand(
- "device_config delete activity_manager " + KEY_COMPACT_THROTTLE_3);
+ CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_THROTTLE_3);
uiDevice.executeShellCommand(
- "device_config delete activity_manager " + KEY_COMPACT_THROTTLE_4);
+ CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_THROTTLE_4);
+ uiDevice.executeShellCommand(
+ CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_STATSD_SAMPLE_RATE);
}
@Before
@@ -128,6 +134,8 @@
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 @@
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 @@
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 @@
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) {