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

Commit 56c43108 authored by Lee Shombert's avatar Lee Shombert Committed by Automerger Merge Worker
Browse files

Merge "Helper classes for IpcDataCache clients" into tm-dev am: ead48cc6 am: 78f5239f

parents 2d62a70b 78f5239f
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);