Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 529a49ee authored by Lee Shombert's avatar Lee Shombert
Browse files

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
parent 9074b73e
Loading
Loading
Loading
Loading
+17 −4
Original line number Diff line number Diff line
@@ -313,6 +313,7 @@ public class PropertyInvalidatedCache<Query, Result> {
     * one of the permitted values above.  The API is a string that is a legal Java simple
     * identifier.  The api is modified to conform to the system property style guide by
     * replacing every upper case letter with an underscore and the lower case equivalent.
     * (An initial upper case letter is not prefixed with an underscore).
     * There is no requirement that the apiName be the name of an actual API.
     *
     * Be aware that SystemProperties has a maximum length which is private to the
@@ -326,7 +327,7 @@ public class PropertyInvalidatedCache<Query, Result> {
            @NonNull String apiName) {
        char[] api = apiName.toCharArray();
        int upper = 0;
        for (int i = 0; i < api.length; i++) {
        for (int i = 1; i < api.length; i++) {
            if (Character.isUpperCase(api[i])) {
                upper++;
            }
@@ -336,7 +337,9 @@ public class PropertyInvalidatedCache<Query, Result> {
        for (int i = 0; i < api.length; i++) {
            if (Character.isJavaIdentifierPart(api[i])) {
                if (Character.isUpperCase(api[i])) {
                    if (i > 0) {
                        suffix[j++] = '_';
                    }
                    suffix[j++] = Character.toLowerCase(api[i]);
                } else {
                    suffix[j++] = api[i];
@@ -1286,12 +1289,22 @@ public class PropertyInvalidatedCache<Query, Result> {
    }

    /**
     * Return the name of the cache, to be used in debug messages.
     * Return the name of the cache, to be used in debug messages.  This is exposed
     * primarily for testing.
     * @hide
     */
    private final @NonNull String cacheName() {
    public final @NonNull String cacheName() {
        return mCacheName;
    }

    /**
     * Return the property used by the cache.  This is primarily for test purposes.
     * @hide
     */
    public final @NonNull String propertyName() {
        return mPropertyName;
    }

    /**
     * Return the query as a string, to be used in debug messages.  New clients should not
     * override this, but should instead add the necessary toString() method to the Query
+57 −192
Original line number Diff line number Diff line
@@ -185,6 +185,30 @@ public class DevicePolicyManager {
        mResourcesManager = new DevicePolicyResourcesManager(context, service);
    }
    /**
     * Fetch the current value of mService.  This is used in the binder cache lambda
     * expressions.
     */
    private final IDevicePolicyManager getService() {
        return mService;
    }
    /**
     * Fetch the current value of mParentInstance.  This is used in the binder cache
     * lambda expressions.
     */
    private final boolean isParentInstance() {
        return mParentInstance;
    }
    /**
     * Fetch the current value of mContext.  This is used in the binder cache lambda
     * expressions.
     */
    private final Context getContext() {
        return mContext;
    }
    /** @hide test will override it. */
    @VisibleForTesting
    protected int myUserId() {
@@ -3783,57 +3807,21 @@ public class DevicePolicyManager {
            "android.app.extra.RESOURCE_IDS";
    /**
     * A convenience class that wraps some IpcDataCache methods. Instantiate it with an
     * API string. Instances can and should be final static. All instances of this class
     * use the same key for invalidation.
     * This object is a single place to tack on invalidation and disable calls.  All
     * binder caches in this class derive from this Config, so all can be invalidated or
     * disabled through this Config.
     */
    private static class BinderApi {
        private final static String KEY = "DevicePolicyManager";
        private final String mApi;
        BinderApi(String api) {
            mApi = api;
        }
        final String api() {
            return mApi;
        }
        final String key() {
            return KEY;
        }
        final static void invalidate() {
            IpcDataCache.invalidateCache(IpcDataCache.MODULE_SYSTEM, KEY);
        }
        final void disable() {
            IpcDataCache.disableForCurrentProcess(mApi);
        }
    }
    private static final IpcDataCache.Config sDpmCaches =
            new IpcDataCache.Config(8, IpcDataCache.MODULE_SYSTEM, "DevicePolicyManagerCaches");
    /** @hide */
    public static void invalidateBinderCaches() {
        BinderApi.invalidate();
    }
    /**
     * A simple wrapper for binder caches in this class. All caches are created with a
     * maximum of 8 entries, the SYSTEM module, and a cache name that is the same as the api.
     */
    private static class BinderCache<Q,R> extends IpcDataCache<Q,R> {
        BinderCache(BinderApi api, IpcDataCache.QueryHandler<Q,R> handler) {
            super(8, IpcDataCache.MODULE_SYSTEM, api.key(), api.api(), handler);
        }
        sDpmCaches.invalidateCache();
    }
    /**
     * Disable all caches in the local process.
     * @hide
     */
    public static void disableLocalProcessCaches() {
        disableGetKeyguardDisabledFeaturesCache();
        disableHasDeviceOwnerCache();
        disableGetProfileOwnerOrDeviceOwnerSupervisionComponentCache();
        disableIsOrganizationOwnedDeviceWithManagedProfileCache();
        disableGetDeviceOwnerOrganizationNameCache();
        disableGetOrganizationNameForUserCache();
        disableIsNetworkLoggingEnabled();
    /** @hide */
    public static void disableLocalCaches() {
        sDpmCaches.disableAllForCurrentProcess();
    }
    /** @hide */
@@ -8435,54 +8423,16 @@ public class DevicePolicyManager {
        return getKeyguardDisabledFeatures(admin, myUserId());
    }
    // A key into the keyguard cache.
    private static class KeyguardQuery {
        private final ComponentName mAdmin;
        private final int mUserHandle;
        KeyguardQuery(@Nullable ComponentName admin, int userHandle) {
            mAdmin = admin;
            mUserHandle = userHandle;
        }
        public boolean equals(Object o) {
            if (o instanceof KeyguardQuery) {
                KeyguardQuery r = (KeyguardQuery) o;
                return Objects.equals(mAdmin, r.mAdmin) && mUserHandle == r.mUserHandle;
            } else {
                return false;
            }
        }
        public int hashCode() {
            return ((mAdmin != null) ? mAdmin.hashCode() : 0) * 13 + mUserHandle;
        }
    }
    // The query handler does not cache wildcard user IDs, although they should never
    // appear in the query.
    private static final BinderApi sGetKeyguardDisabledFeatures =
            new BinderApi("getKeyguardDisabledFeatures");
    private BinderCache<KeyguardQuery, Integer> mGetKeyGuardDisabledFeaturesCache =
            new BinderCache<>(sGetKeyguardDisabledFeatures,
                    new IpcDataCache.QueryHandler<KeyguardQuery, Integer>() {
                        @Override
                        public Integer apply(KeyguardQuery query) {
                            try {
                                return mService.getKeyguardDisabledFeatures(
                                    query.mAdmin, query.mUserHandle, mParentInstance);
                            } catch (RemoteException e) {
                                throw e.rethrowFromSystemServer();
                            }
                        }});
    /** @hide */
    public static void disableGetKeyguardDisabledFeaturesCache() {
        sGetKeyguardDisabledFeatures.disable();
    }
    private IpcDataCache<Pair<ComponentName, Integer>, Integer> mGetKeyGuardDisabledFeaturesCache =
            new IpcDataCache<>(sDpmCaches.child("getKeyguardDisabledFeatures"),
                    (query) -> getService().getKeyguardDisabledFeatures(
                            query.first, query.second, isParentInstance()));
    /** @hide per-user version */
    @UnsupportedAppUsage
    public int getKeyguardDisabledFeatures(@Nullable ComponentName admin, int userHandle) {
        if (mService != null) {
            return mGetKeyGuardDisabledFeaturesCache.query(new KeyguardQuery(admin, userHandle));
            return mGetKeyGuardDisabledFeaturesCache.query(new Pair<>(admin, userHandle));
        } else {
            return KEYGUARD_DISABLE_FEATURES_NONE;
        }
@@ -8864,23 +8814,9 @@ public class DevicePolicyManager {
        return name != null ? name.getPackageName() : null;
    }
    private static final BinderApi sHasDeviceOwner =
            new BinderApi("hasDeviceOwner");
    private BinderCache<Void, Boolean> mHasDeviceOwnerCache =
            new BinderCache<>(sHasDeviceOwner,
                    new IpcDataCache.QueryHandler<Void, Boolean>() {
                        @Override
                        public Boolean apply(Void query) {
                            try {
                                return mService.hasDeviceOwner();
                            } catch (RemoteException e) {
                                throw e.rethrowFromSystemServer();
                            }
                        }});
    /** @hide */
    public static void disableHasDeviceOwnerCache() {
        sHasDeviceOwner.disable();
    }
    private IpcDataCache<Void, Boolean> mHasDeviceOwnerCache =
            new IpcDataCache<>(sDpmCaches.child("hasDeviceOwner"),
                    (query) -> getService().hasDeviceOwner());
    /**
     * Called by the system to find out whether the device is managed by a Device Owner.
@@ -9256,25 +9192,10 @@ public class DevicePolicyManager {
        return null;
    }
    private final static BinderApi sGetProfileOwnerOrDeviceOwnerSupervisionComponent =
            new BinderApi("getProfileOwnerOrDeviceOwnerSupervisionComponent");
    private final BinderCache<UserHandle, ComponentName>
    private final IpcDataCache<UserHandle, ComponentName>
            mGetProfileOwnerOrDeviceOwnerSupervisionComponentCache =
            new BinderCache(sGetProfileOwnerOrDeviceOwnerSupervisionComponent,
                    new IpcDataCache.QueryHandler<UserHandle, ComponentName>() {
                        @Override
                        public ComponentName apply(UserHandle user) {
                            try {
                                return mService.getProfileOwnerOrDeviceOwnerSupervisionComponent(
                                    user);
                            } catch (RemoteException re) {
                                throw re.rethrowFromSystemServer();
                            }
                        }});
    /** @hide */
    public static void disableGetProfileOwnerOrDeviceOwnerSupervisionComponentCache() {
        sGetProfileOwnerOrDeviceOwnerSupervisionComponent.disable();
    }
            new IpcDataCache<>(sDpmCaches.child("getProfileOwnerOrDeviceOwnerSupervisionComponent"),
                    (arg) -> getService().getProfileOwnerOrDeviceOwnerSupervisionComponent(arg));
    /**
     * Returns the configured supervision app if it exists and is the device owner or policy owner.
@@ -9329,23 +9250,9 @@ public class DevicePolicyManager {
        return null;
    }
    private final static BinderApi sIsOrganizationOwnedDeviceWithManagedProfile =
            new BinderApi("isOrganizationOwnedDeviceWithManagedProfile");
    private final BinderCache<Void, Boolean> mIsOrganizationOwnedDeviceWithManagedProfileCache =
            new BinderCache(sIsOrganizationOwnedDeviceWithManagedProfile,
                    new IpcDataCache.QueryHandler<Void, Boolean>() {
                        @Override
                        public Boolean apply(Void query) {
                            try {
                                return mService.isOrganizationOwnedDeviceWithManagedProfile();
                            } catch (RemoteException re) {
                                throw re.rethrowFromSystemServer();
                            }
                        }});
    /** @hide */
    public static void disableIsOrganizationOwnedDeviceWithManagedProfileCache() {
        sIsOrganizationOwnedDeviceWithManagedProfile.disable();
    }
    private final IpcDataCache<Void, Boolean> mIsOrganizationOwnedDeviceWithManagedProfileCache =
            new IpcDataCache(sDpmCaches.child("isOrganizationOwnedDeviceWithManagedProfile"),
                    (query) -> getService().isOrganizationOwnedDeviceWithManagedProfile());
    /**
     * Apps can use this method to find out if the device was provisioned as
@@ -12927,23 +12834,9 @@ public class DevicePolicyManager {
        }
    }
    private final static BinderApi sGetDeviceOwnerOrganizationName =
            new BinderApi("getDeviceOwnerOrganizationName");
    private final BinderCache<Void, CharSequence> mGetDeviceOwnerOrganizationNameCache =
            new BinderCache(sGetDeviceOwnerOrganizationName,
                    new IpcDataCache.QueryHandler<Void, CharSequence>() {
                        @Override
                        public CharSequence apply(Void query) {
                            try {
                                return mService.getDeviceOwnerOrganizationName();
                            } catch (RemoteException re) {
                                throw re.rethrowFromSystemServer();
                            }
                        }});
    /** @hide */
    public static void disableGetDeviceOwnerOrganizationNameCache() {
        sGetDeviceOwnerOrganizationName.disable();
    }
    private final IpcDataCache<Void, CharSequence> mGetDeviceOwnerOrganizationNameCache =
            new IpcDataCache(sDpmCaches.child("getDeviceOwnerOrganizationName"),
                    (query) -> getService().getDeviceOwnerOrganizationName());
    /**
     * Called by the system to retrieve the name of the organization managing the device.
@@ -12960,23 +12853,9 @@ public class DevicePolicyManager {
        return mGetDeviceOwnerOrganizationNameCache.query(null);
    }
    private final static BinderApi sGetOrganizationNameForUser =
            new BinderApi("getOrganizationNameForUser");
    private final BinderCache<Integer, CharSequence> mGetOrganizationNameForUserCache =
            new BinderCache(sGetOrganizationNameForUser,
                    new IpcDataCache.QueryHandler<Integer, CharSequence>() {
                        @Override
                        public CharSequence apply(Integer userHandle) {
                            try {
                                return mService.getOrganizationNameForUser(userHandle);
                            } catch (RemoteException re) {
                                throw re.rethrowFromSystemServer();
                            }
                        }});
    /** @hide */
    public static void disableGetOrganizationNameForUserCache() {
        sGetOrganizationNameForUser.disable();
    }
    private final IpcDataCache<Integer, CharSequence> mGetOrganizationNameForUserCache =
            new IpcDataCache<>(sDpmCaches.child("getOrganizationNameForUser"),
                    (query) -> getService().getOrganizationNameForUser(query));
    /**
     * Retrieve the default title message used in the confirm credentials screen for a given user.
@@ -13372,24 +13251,10 @@ public class DevicePolicyManager {
        }
    }
    private final static BinderApi sNetworkLoggingApi = new BinderApi("isNetworkLoggingEnabled");
    private BinderCache<ComponentName, Boolean> mIsNetworkLoggingEnabledCache =
            new BinderCache<>(sNetworkLoggingApi,
                    new IpcDataCache.QueryHandler<ComponentName, Boolean>() {
                        @Override
                        public Boolean apply(ComponentName admin) {
                            try {
                                return mService.isNetworkLoggingEnabled(
                                    admin, mContext.getPackageName());
                            } catch (RemoteException re) {
                                throw re.rethrowFromSystemServer();
                            }
                        }});
    /** @hide */
    public static void disableIsNetworkLoggingEnabled() {
        sNetworkLoggingApi.disable();
    }
    private IpcDataCache<ComponentName, Boolean> mIsNetworkLoggingEnabledCache =
            new IpcDataCache<>(sDpmCaches.child("isNetworkLoggingEnabled"),
                    (admin) -> getService().isNetworkLoggingEnabled(admin,
                            getContext().getPackageName()));
    /**
     * Return whether network logging is enabled by a device owner or profile owner of
+209 −4
Original line number Diff line number Diff line
@@ -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));
    }
}
+104 −0

File changed.

Preview size limit exceeded, changes collapsed.

+1 −1
Original line number Diff line number Diff line
@@ -1781,7 +1781,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    @VisibleForTesting
    DevicePolicyManagerService(Injector injector) {
        DevicePolicyManager.disableGetKeyguardDisabledFeaturesCache();
        DevicePolicyManager.disableLocalCaches();
        mInjector = injector;
        mContext = Objects.requireNonNull(injector.mContext);