Add DeviceConfigUtils version caching and tests
Querying the APK version can be relatively expensive, so cache it with a
static. Package version cannot change without restarting the process.
Also add some testing for flags being equal to the min/max values.
Bug: 17454103
Test: atest NetworkStaticLibTests
Change-Id: I18c298beb843e0a9f76162d353623bb15ab155f1
diff --git a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java
index 5fec0dd..271cc6e 100644
--- a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java
+++ b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java
@@ -25,6 +25,7 @@
import androidx.annotation.BoolRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
/**
* Utilities for modules to query {@link DeviceConfig} and flags.
@@ -34,6 +35,21 @@
private static final String TAG = DeviceConfigUtils.class.getSimpleName();
+ @VisibleForTesting
+ protected static volatile long sPackageVersion = -1;
+ private static long getPackageVersion(@NonNull final Context context)
+ throws PackageManager.NameNotFoundException {
+ // sPackageVersion may be set by another thread just after this check, but querying the
+ // package version several times on rare occasions is fine.
+ if (sPackageVersion >= 0) {
+ return sPackageVersion;
+ }
+ final long version = context.getPackageManager().getPackageInfo(
+ context.getPackageName(), 0).getLongVersionCode();
+ sPackageVersion = version;
+ return version;
+ }
+
/**
* Look up the value of a property for a particular namespace from {@link DeviceConfig}.
* @param namespace The namespace containing the property to look up.
@@ -137,8 +153,7 @@
try {
final int propertyVersion = getDeviceConfigPropertyInt(namespace, name,
0 /* default value */);
- final long packageVersion = context.getPackageManager().getPackageInfo(
- context.getPackageName(), 0).getLongVersionCode();
+ final long packageVersion = getPackageVersion(context);
return (propertyVersion == 0 && defaultEnabled)
|| (propertyVersion != 0 && packageVersion >= (long) propertyVersion);
} catch (PackageManager.NameNotFoundException e) {
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java
index bb78854..982dbe7 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java
@@ -26,6 +26,8 @@
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import android.content.Context;
import android.content.pm.PackageInfo;
@@ -86,6 +88,7 @@
@After
public void tearDown() {
mSession.finishMocking();
+ DeviceConfigUtils.sPackageVersion = -1L;
}
@Test
@@ -137,6 +140,16 @@
}
@Test
+ public void testGetDeviceConfigPropertyInt_EqualsMaximumValue() {
+ doReturn(Integer.toString(TEST_MAX_FLAG_VALUE)).when(() -> DeviceConfig.getProperty(
+ eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG)));
+ assertEquals(TEST_MAX_FLAG_VALUE, DeviceConfigUtils.getDeviceConfigPropertyInt(
+ TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_MIN_FLAG_VALUE /* minimum value */,
+ TEST_MAX_FLAG_VALUE /* maximum value */,
+ TEST_DEFAULT_FLAG_VALUE /* default value */));
+ }
+
+ @Test
public void testGetDeviceConfigPropertyInt_BelowMinimumValue() {
doReturn(Integer.toString(TEST_MIN_FLAG_VALUE - 10)).when(() -> DeviceConfig.getProperty(
eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG)));
@@ -147,6 +160,16 @@
}
@Test
+ public void testGetDeviceConfigPropertyInt_EqualsMinimumValue() {
+ doReturn(Integer.toString(TEST_MIN_FLAG_VALUE)).when(() -> DeviceConfig.getProperty(
+ eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG)));
+ assertEquals(TEST_MIN_FLAG_VALUE, DeviceConfigUtils.getDeviceConfigPropertyInt(
+ TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_MIN_FLAG_VALUE /* minimum value */,
+ TEST_MAX_FLAG_VALUE /* maximum value */,
+ TEST_DEFAULT_FLAG_VALUE /* default value */));
+ }
+
+ @Test
public void testGetDeviceConfigPropertyBoolean_Null() {
doReturn(null).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE),
eq(TEST_EXPERIMENT_FLAG)));
@@ -165,7 +188,7 @@
}
@Test
- public void testFeatureIsEnabledWithExceptionsEnabled() {
+ public void testFeatureIsEnabled() {
doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE),
eq(TEST_EXPERIMENT_FLAG)));
assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE,
@@ -190,6 +213,21 @@
}
@Test
+ public void testFeatureIsEnabledCaching() throws Exception {
+ doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE),
+ eq(TEST_EXPERIMENT_FLAG)));
+ assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE,
+ TEST_EXPERIMENT_FLAG));
+ assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE,
+ TEST_EXPERIMENT_FLAG));
+
+ // Package info is only queried once
+ verify(mContext, times(1)).getPackageManager();
+ verify(mContext, times(1)).getPackageName();
+ verify(mPm, times(1)).getPackageInfo(anyString(), anyInt());
+ }
+
+ @Test
public void testGetResBooleanConfig() {
final int someResId = 1234;
doReturn(true).when(mResources).getBoolean(someResId);