summaryrefslogtreecommitdiff
path: root/core/java/android/os/IpcDataCache.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/os/IpcDataCache.java')
-rw-r--r--core/java/android/os/IpcDataCache.java213
1 files changed, 209 insertions, 4 deletions
diff --git a/core/java/android/os/IpcDataCache.java b/core/java/android/os/IpcDataCache.java
index 0efa34cdc47f..bf44d65c4002 100644
--- a/core/java/android/os/IpcDataCache.java
+++ b/core/java/android/os/IpcDataCache.java
@@ -23,7 +23,7 @@ import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.app.PropertyInvalidatedCache;
import android.text.TextUtils;
-import android.util.Log;
+import android.util.ArraySet;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.FastPrintWriter;
@@ -35,7 +35,6 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
@@ -324,8 +323,8 @@ public class IpcDataCache<Query, Result> extends PropertyInvalidatedCache<Query,
@SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
@TestApi
public IpcDataCache(int maxEntries, @NonNull @IpcDataCacheModule String module,
- @NonNull String api,
- @NonNull String cacheName, @NonNull QueryHandler<Query, Result> computer) {
+ @NonNull String api, @NonNull String cacheName,
+ @NonNull QueryHandler<Query, Result> computer) {
super(maxEntries, module, api, cacheName, computer);
}
@@ -382,4 +381,210 @@ public class IpcDataCache<Query, Result> extends PropertyInvalidatedCache<Query,
@NonNull String api) {
PropertyInvalidatedCache.invalidateCache(module, 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.
+ *
+ * There are three specific use cases supported by this class.
+ *
+ * 1. Instance-per-cache: create a static instance of this class using the same
+ * parameters as would have been given to IpcDataCache (or
+ * PropertyInvalidatedCache). This static instance provides a hook for the
+ * invalidateCache() and disableForLocalProcess() calls, which, generally, must
+ * also be static.
+ *
+ * 2. Short-hand for shared configuration parameters: create an instance of this class
+ * to capture the maximum number of entries and the module to be used by more than
+ * one cache in the class. Refer to this instance when creating new configs. Only
+ * the api and (optionally key) for the new cache must be supplied.
+ *
+ * 3. Tied caches: create a static instance of this class to capture the maximum
+ * number of entries, the module, and the key. Refer to this instance when
+ * creating a new config that differs in only the api. The new config can be
+ * created as part of the cache constructor. All caches that trace back to the
+ * root config share the same key and are invalidated by the invalidateCache()
+ * method of the root config. All caches that trace back to the root config can be
+ * disabled in the local process by the disableAllForCurrentProcess() method of the
+ * root config.
+ *
+ * @hide
+ */
+ public static class Config {
+ private final int mMaxEntries;
+ @IpcDataCacheModule
+ private final String mModule;
+ private final String mApi;
+ private final String mName;
+
+ /**
+ * The list of cache names that were created extending this Config. If
+ * disableForCurrentProcess() is invoked on this config then all children will be
+ * disabled. Furthermore, any new children based off of this config will be
+ * disabled. The construction order guarantees that new caches will be disabled
+ * before they are created (the Config must be created before the IpcDataCache is
+ * created).
+ */
+ private ArraySet<String> mChildren;
+
+ /**
+ * True if registered children are disabled in the current process. If this is
+ * true then all new children are disabled as they are registered.
+ */
+ private boolean mDisabled = false;
+
+ public Config(int maxEntries, @NonNull @IpcDataCacheModule String module,
+ @NonNull String api, @NonNull String name) {
+ mMaxEntries = maxEntries;
+ mModule = module;
+ mApi = api;
+ mName = name;
+ }
+
+ /**
+ * A short-hand constructor that makes the name the same as the api.
+ */
+ public Config(int maxEntries, @NonNull @IpcDataCacheModule String module,
+ @NonNull String api) {
+ this(maxEntries, module, api, api);
+ }
+
+ /**
+ * Copy the module and max entries from the Config and take the api and name from
+ * the parameter list.
+ */
+ public Config(@NonNull Config root, @NonNull String api, @NonNull String name) {
+ this(root.maxEntries(), root.module(), api, name);
+ }
+
+ /**
+ * Copy the module and max entries from the Config and take the api and name from
+ * the parameter list.
+ */
+ public Config(@NonNull Config root, @NonNull String api) {
+ this(root.maxEntries(), root.module(), api, api);
+ }
+
+ /**
+ * Fetch a config that is a child of <this>. The child shares the same api as the
+ * parent and is registered with the parent for the purposes of disabling in the
+ * current process.
+ */
+ public Config child(@NonNull String name) {
+ final Config result = new Config(this, api(), 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;
+ }
+
+ public final @NonNull String name() {
+ return mName;
+ }
+
+ /**
+ * Register a child cache name. If disableForCurrentProcess() has been called
+ * against this cache, disable th new child.
+ */
+ private final void registerChild(String name) {
+ synchronized (this) {
+ if (mChildren == null) {
+ mChildren = new ArraySet<>();
+ }
+ mChildren.add(name);
+ if (mDisabled) {
+ IpcDataCache.disableForCurrentProcess(name);
+ }
+ }
+ }
+
+ /**
+ * Invalidate all caches that share this Config's module and api.
+ */
+ public void invalidateCache() {
+ IpcDataCache.invalidateCache(mModule, mApi);
+ }
+
+ /**
+ * Disable all caches that share this Config's name.
+ */
+ public void disableForCurrentProcess() {
+ IpcDataCache.disableForCurrentProcess(mName);
+ }
+
+ /**
+ * Disable this cache and all children. Any child that is added in the future
+ * will alwo be disabled.
+ */
+ public void disableAllForCurrentProcess() {
+ synchronized (this) {
+ mDisabled = true;
+ disableForCurrentProcess();
+ if (mChildren != null) {
+ for (String c : mChildren) {
+ IpcDataCache.disableForCurrentProcess(c);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Create a new cache using a config.
+ * @hide
+ */
+ public IpcDataCache(@NonNull Config config, @NonNull QueryHandler<Query, Result> computer) {
+ super(config.maxEntries(), config.module(), config.api(), config.name(), computer);
+ }
+
+ /**
+ * An interface suitable for a lambda expression instead of a QueryHandler.
+ * @hide
+ */
+ public interface RemoteCall<Query, Result> {
+ Result apply(Query query) throws RemoteException;
+ }
+
+ /**
+ * This is a query handler that is created with a lambda expression that is invoked
+ * every time the handler is called. The handler is specifically meant for services
+ * hosted by system_server; the handler automatically rethrows RemoteException as a
+ * RuntimeException, which is the usual handling for failed binder calls.
+ */
+ private static class SystemServerCallHandler<Query, Result>
+ extends IpcDataCache.QueryHandler<Query, Result> {
+ private final RemoteCall<Query, Result> mHandler;
+ public SystemServerCallHandler(RemoteCall handler) {
+ mHandler = handler;
+ }
+ @Override
+ public Result apply(Query query) {
+ try {
+ return mHandler.apply(query);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Create a cache using a config and a lambda expression.
+ * @hide
+ */
+ public IpcDataCache(@NonNull Config config, @NonNull RemoteCall<Query, Result> computer) {
+ this(config, new SystemServerCallHandler<>(computer));
+ }
}