summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/PropertyInvalidatedCache.java29
-rw-r--r--core/java/android/os/IpcDataCache.java66
-rw-r--r--core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java15
-rw-r--r--core/tests/coretests/src/android/os/IpcDataCacheTest.java76
4 files changed, 130 insertions, 56 deletions
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index 9bb0ba4cf8fa..1e971a5c736a 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -1294,6 +1294,13 @@ public class PropertyInvalidatedCache<Query, Result> {
public static record Args(@NonNull String mModule, @Nullable String mApi,
int mMaxEntries, boolean mIsolateUids, boolean mTestMode, boolean mCacheNulls) {
+ /**
+ * Default values for fields.
+ */
+ public static final int DEFAULT_MAX_ENTRIES = 32;
+ public static final boolean DEFAULT_ISOLATE_UIDS = true;
+ public static final boolean DEFAULT_CACHE_NULLS = false;
+
// Validation: the module must be one of the known module strings and the maxEntries must
// be positive.
public Args {
@@ -1308,10 +1315,10 @@ public class PropertyInvalidatedCache<Query, Result> {
public Args(@NonNull String module) {
this(module,
null, // api
- 32, // maxEntries
- true, // isolateUids
+ DEFAULT_MAX_ENTRIES,
+ DEFAULT_ISOLATE_UIDS,
false, // testMode
- true // allowNulls
+ DEFAULT_CACHE_NULLS
);
}
@@ -1361,7 +1368,7 @@ public class PropertyInvalidatedCache<Query, Result> {
* Burst a property name into module and api. Throw if the key is invalid. This method is
* used in to transition legacy cache constructors to the args constructor.
*/
- private static Args parseProperty(@NonNull String name) {
+ private static Args argsFromProperty(@NonNull String name) {
throwIfInvalidCacheKey(name);
// Strip off the leading well-known prefix.
String base = name.substring(CACHE_KEY_PREFIX.length() + 1);
@@ -1384,8 +1391,9 @@ public class PropertyInvalidatedCache<Query, Result> {
*
* @hide
*/
+ @Deprecated
public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName) {
- this(parseProperty(propertyName).maxEntries(maxEntries), propertyName, null);
+ this(argsFromProperty(propertyName).maxEntries(maxEntries), propertyName, null);
}
/**
@@ -1399,9 +1407,10 @@ public class PropertyInvalidatedCache<Query, Result> {
* @param cacheName Name of this cache in debug and dumpsys
* @hide
*/
+ @Deprecated
public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName,
@NonNull String cacheName) {
- this(parseProperty(propertyName).maxEntries(maxEntries), cacheName, null);
+ this(argsFromProperty(propertyName).maxEntries(maxEntries), cacheName, null);
}
/**
@@ -1857,6 +1866,14 @@ public class PropertyInvalidatedCache<Query, Result> {
}
/**
+ * Invalidate caches in all processes that have the module and api specified in the args.
+ * @hide
+ */
+ public static void invalidateCache(@NonNull Args args) {
+ invalidateCache(createPropertyName(args.mModule, args.mApi));
+ }
+
+ /**
* Invalidate PropertyInvalidatedCache caches in all processes that are keyed on
* {@var name}. This function is synchronous: caches are invalidated upon return.
*
diff --git a/core/java/android/os/IpcDataCache.java b/core/java/android/os/IpcDataCache.java
index 8db1567336d3..a2e9314f6436 100644
--- a/core/java/android/os/IpcDataCache.java
+++ b/core/java/android/os/IpcDataCache.java
@@ -400,10 +400,11 @@ public class IpcDataCache<Query, Result> extends PropertyInvalidatedCache<Query,
}
/**
- * This is a convenience class that encapsulates configuration information for a
- * cache. It may be supplied to the cache constructors in lieu of the other
- * parameters. The class captures maximum entry count, the module, the key, and the
- * api.
+ * This is a convenience class that encapsulates configuration information for a cache. It
+ * may be supplied to the cache constructors in lieu of the other parameters. The class
+ * captures maximum entry count, the module, the key, and the api. The key is used to
+ * invalidate the cache and may be shared by different caches. The api is a user-visible (in
+ * debug) name for the cache.
*
* There are three specific use cases supported by this class.
*
@@ -430,11 +431,8 @@ public class IpcDataCache<Query, Result> extends PropertyInvalidatedCache<Query,
* @hide
*/
public static class Config {
- private final int mMaxEntries;
- @IpcDataCacheModule
- private final String mModule;
- private final String mApi;
- private final String mName;
+ final Args mArgs;
+ final String mName;
/**
* The list of cache names that were created extending this Config. If
@@ -452,12 +450,20 @@ public class IpcDataCache<Query, Result> extends PropertyInvalidatedCache<Query,
*/
private boolean mDisabled = false;
+ /**
+ * Fully construct a config.
+ */
+ private Config(@NonNull Args args, @NonNull String name) {
+ mArgs = args;
+ mName = name;
+ }
+
+ /**
+ *
+ */
public Config(int maxEntries, @NonNull @IpcDataCacheModule String module,
@NonNull String api, @NonNull String name) {
- mMaxEntries = maxEntries;
- mModule = module;
- mApi = api;
- mName = name;
+ this(new Args(module).api(api).maxEntries(maxEntries), name);
}
/**
@@ -473,7 +479,7 @@ public class IpcDataCache<Query, Result> extends PropertyInvalidatedCache<Query,
* the parameter list.
*/
public Config(@NonNull Config root, @NonNull String api, @NonNull String name) {
- this(root.maxEntries(), root.module(), api, name);
+ this(root.mArgs.api(api), name);
}
/**
@@ -481,7 +487,7 @@ public class IpcDataCache<Query, Result> extends PropertyInvalidatedCache<Query,
* the parameter list.
*/
public Config(@NonNull Config root, @NonNull String api) {
- this(root.maxEntries(), root.module(), api, api);
+ this(root.mArgs.api(api), api);
}
/**
@@ -490,26 +496,23 @@ public class IpcDataCache<Query, Result> extends PropertyInvalidatedCache<Query,
* current process.
*/
public Config child(@NonNull String name) {
- final Config result = new Config(this, api(), name);
+ final Config result = new Config(mArgs, name);
registerChild(name);
return result;
}
- public final int maxEntries() {
- return mMaxEntries;
- }
-
- @IpcDataCacheModule
- public final @NonNull String module() {
- return mModule;
- }
-
- public final @NonNull String api() {
- return mApi;
+ /**
+ * Set the cacheNull behavior.
+ */
+ public Config cacheNulls(boolean enable) {
+ return new Config(mArgs.cacheNulls(enable), mName);
}
- public final @NonNull String name() {
- return mName;
+ /**
+ * Set the isolateUidss behavior.
+ */
+ public Config isolateUids(boolean enable) {
+ return new Config(mArgs.isolateUids(enable), mName);
}
/**
@@ -532,7 +535,7 @@ public class IpcDataCache<Query, Result> extends PropertyInvalidatedCache<Query,
* Invalidate all caches that share this Config's module and api.
*/
public void invalidateCache() {
- IpcDataCache.invalidateCache(mModule, mApi);
+ IpcDataCache.invalidateCache(mArgs);
}
/**
@@ -564,8 +567,7 @@ public class IpcDataCache<Query, Result> extends PropertyInvalidatedCache<Query,
* @hide
*/
public IpcDataCache(@NonNull Config config, @NonNull QueryHandler<Query, Result> computer) {
- super(new Args(config.module()).maxEntries(config.maxEntries()).api(config.api()),
- config.name(), computer);
+ super(config.mArgs, config.mName, computer);
}
/**
diff --git a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
index 177c7f0b2f27..bd273377984d 100644
--- a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
+++ b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
@@ -740,5 +740,20 @@ public class PropertyInvalidatedCacheTests {
assertEquals(null, cache.query(30));
// The recompute is 4 because nulls were not cached.
assertEquals(4, cache.getRecomputeCount());
+
+ // Verify that the default is not to cache nulls.
+ cache = new TestCache(new Args(MODULE_TEST)
+ .maxEntries(4).api("testCachingNulls"),
+ new TestQuery());
+ cache.invalidateCache();
+ assertEquals("foo1", cache.query(1));
+ assertEquals("foo2", cache.query(2));
+ assertEquals(null, cache.query(30));
+ assertEquals(3, cache.getRecomputeCount());
+ assertEquals("foo1", cache.query(1));
+ assertEquals("foo2", cache.query(2));
+ assertEquals(null, cache.query(30));
+ // The recompute is 4 because nulls were not cached.
+ assertEquals(4, cache.getRecomputeCount());
}
}
diff --git a/core/tests/coretests/src/android/os/IpcDataCacheTest.java b/core/tests/coretests/src/android/os/IpcDataCacheTest.java
index e14608ac503d..523b1b075a7c 100644
--- a/core/tests/coretests/src/android/os/IpcDataCacheTest.java
+++ b/core/tests/coretests/src/android/os/IpcDataCacheTest.java
@@ -16,13 +16,19 @@
package android.os;
+import static android.app.Flags.FLAG_PIC_CACHE_NULLS;
+import static android.app.Flags.FLAG_PIC_ISOLATE_CACHE_BY_UID;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
+import android.app.PropertyInvalidatedCache;
+import android.app.PropertyInvalidatedCache.Args;
import android.multiuser.Flags;
import android.platform.test.annotations.IgnoreUnderRavenwood;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.ravenwood.RavenwoodRule;
+import android.os.IpcDataCache;
import androidx.test.filters.SmallTest;
@@ -287,7 +293,12 @@ public class IpcDataCacheTest {
@Override
public String apply(Integer qv) {
mRecomputeCount += 1;
- return "foo" + qv.toString();
+ // Special case for testing caches of nulls. Integers in the range 30-40 return null.
+ if (qv >= 30 && qv < 40) {
+ return null;
+ } else {
+ return "foo" + qv.toString();
+ }
}
int getRecomputeCount() {
@@ -406,31 +417,16 @@ public class IpcDataCacheTest {
}
@Test
- public void testConfig() {
+ public void testConfigDisable() {
+ // Create a set of caches based on a set of chained configs.
IpcDataCache.Config a = new IpcDataCache.Config(8, MODULE, "apiA");
TestCache ac = new TestCache(a);
- assertEquals(8, a.maxEntries());
- assertEquals(MODULE, a.module());
- assertEquals("apiA", a.api());
- assertEquals("apiA", a.name());
IpcDataCache.Config b = new IpcDataCache.Config(a, "apiB");
TestCache bc = new TestCache(b);
- assertEquals(8, b.maxEntries());
- assertEquals(MODULE, b.module());
- assertEquals("apiB", b.api());
- assertEquals("apiB", b.name());
IpcDataCache.Config c = new IpcDataCache.Config(a, "apiC", "nameC");
TestCache cc = new TestCache(c);
- assertEquals(8, c.maxEntries());
- assertEquals(MODULE, c.module());
- assertEquals("apiC", c.api());
- assertEquals("nameC", c.name());
IpcDataCache.Config d = a.child("nameD");
TestCache dc = new TestCache(d);
- assertEquals(8, d.maxEntries());
- assertEquals(MODULE, d.module());
- assertEquals("apiA", d.api());
- assertEquals("nameD", d.name());
a.disableForCurrentProcess();
assertEquals(ac.isDisabled(), true);
@@ -449,6 +445,7 @@ public class IpcDataCacheTest {
assertEquals(ec.isDisabled(), true);
}
+
// Verify that invalidating the cache from an app process would fail due to lack of permissions.
@Test
@android.platform.test.annotations.DisabledOnRavenwood(
@@ -507,4 +504,47 @@ public class IpcDataCacheTest {
// Re-enable test mode (so that the cleanup for the test does not throw).
IpcDataCache.setTestMode(true);
}
+
+ @RequiresFlagsEnabled(FLAG_PIC_CACHE_NULLS)
+ @Test
+ public void testCachingNulls() {
+ IpcDataCache.Config c =
+ new IpcDataCache.Config(4, IpcDataCache.MODULE_TEST, "testCachingNulls");
+ TestCache cache;
+ cache = new TestCache(c.cacheNulls(true));
+ cache.invalidateCache();
+ assertEquals("foo1", cache.query(1));
+ assertEquals("foo2", cache.query(2));
+ assertEquals(null, cache.query(30));
+ assertEquals(3, cache.getRecomputeCount());
+ assertEquals("foo1", cache.query(1));
+ assertEquals("foo2", cache.query(2));
+ assertEquals(null, cache.query(30));
+ assertEquals(3, cache.getRecomputeCount());
+
+ cache = new TestCache(c.cacheNulls(false));
+ cache.invalidateCache();
+ assertEquals("foo1", cache.query(1));
+ assertEquals("foo2", cache.query(2));
+ assertEquals(null, cache.query(30));
+ assertEquals(3, cache.getRecomputeCount());
+ assertEquals("foo1", cache.query(1));
+ assertEquals("foo2", cache.query(2));
+ assertEquals(null, cache.query(30));
+ // The recompute is 4 because nulls were not cached.
+ assertEquals(4, cache.getRecomputeCount());
+
+ // Verify that the default is not to cache nulls.
+ cache = new TestCache(c);
+ cache.invalidateCache();
+ assertEquals("foo1", cache.query(1));
+ assertEquals("foo2", cache.query(2));
+ assertEquals(null, cache.query(30));
+ assertEquals(3, cache.getRecomputeCount());
+ assertEquals("foo1", cache.query(1));
+ assertEquals("foo2", cache.query(2));
+ assertEquals(null, cache.query(30));
+ // The recompute is 4 because nulls were not cached.
+ assertEquals(4, cache.getRecomputeCount());
+ }
}