diff options
| author | Lee Shombert <shombert@google.com> | 2022-04-08 07:54:39 -0700 |
|---|---|---|
| committer | Lee Shombert <shombert@google.com> | 2022-04-11 07:27:16 -0700 |
| commit | 529a49ee3d6452f033cb43a57bf8c865e177e2b8 (patch) | |
| tree | cc973441e72db07421a39aefafcf909ba6bafe01 /core/java/android/os/IpcDataCache.java | |
| parent | 9074b73ec7942c6515a2a1e519cd16d18dd9ce59 (diff) | |
Helper classes for IpcDataCache clients
Bug: 227653108
This adds a helper class that can reduce much of the boilerplate in
code that uses IpcDataCache (or the internal-only variant,
PropertyInvalidatedCache). See the changes to DevicePolicyManager for
example usage.
Two PropertyInvalidatedCaches APIs are exposed for testing. The
method createPropertyName() is changed so that apis like "Foo" are
converted to "foo", not "_foo".
Unit tests for the new behavior are added to IpcDataCacheTest.
This was manually tested by dumping the cache info from builds with
and without this change. Special attention is paid to the
DevicePolicyManager caches. The same caches were found (as identified
by their key and api) and the caches were enabled/disabled the same.
In the course of testing, multiple instances of DevicePolicyManager
caches were observed. Cache performance is better if the caches are
static; making them static will be addressed in b/228452829.
Test:
* atest FrameworksCoreTests:IpcDataCacheTest
* atest FrameworksCoreTests:PropertyInvalidatedCacheTests
* atest FrameworksServicesTests:DevicePolicyConstantsTest
* atest FrameworksServicesTests:DevicePolicyEventLoggerTest
* atest FrameworksServicesTests:DevicePolicyManagerServiceMigrationTest
* atest FrameworksServicesTests:DevicePolicyManagerTest
* atest FrameworksServicesTests:EnterpriseSpecificIdCalculatorTest
* atest FrameworksServicesTests:OverlayPackagesProviderTest
* atest FrameworksServicesTests:OwnersTest
* atest FrameworksServicesTests:PolicyVersionUpgraderTest
* atest FrameworksServicesTests:SecurityEventTest
* atest FrameworksServicesTests:SystemUpdatePolicyTest
* atest FrameworksServicesTests:TransferOwnershipMetadataManagerTest
* atest MixedDeviceOwnerTest#testIsDeviceOrganizationOwnedWithManagedProfile
* atest MixedDeviceOwnerTest#testSetKeyguardDisabledFeatures
* atest MixedManagedProfileOwnerTest#testIsDeviceOrganizationOwnedWithManagedProfile
* atest MixedManagedProfileOwnerTest#testNetworkLoggingDelegate
* atest MixedManagedProfileOwnerTest#testSetKeyguardDisabledFeatures
* atest OrgOwnedProfileOwnerTest#testIsDeviceOrganizationOwnedWithManagedProfile
* atest OrgOwnedProfileOwnerTest#testNetworkLoggingDelegate
* atest OrgOwnedProfileOwnerTest#testSetKeyguardDisabledFeatures
* atest android.devicepolicy.cts.DevicePolicyManagerTest
* atest android.devicepolicy.cts.NetworkLoggingTest
* atest com.android.cts.devicepolicy.DeviceOwnerTest#testAdminActionBookkeeping
Change-Id: I2f4fe4ed25db5fb3100334b9d2ce748ee928c10d
Diffstat (limited to 'core/java/android/os/IpcDataCache.java')
| -rw-r--r-- | core/java/android/os/IpcDataCache.java | 213 |
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)); + } } |
