Merge "Helper classes for IpcDataCache clients" into tm-dev am: ead48cc667
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17542360 Change-Id: If6877d58654d387357c8200395186279069c316c Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -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])) {
|
||||
suffix[j++] = '_';
|
||||
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
|
||||
|
||||
@@ -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();
|
||||
sDpmCaches.invalidateCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,14 @@ public class IpcDataCacheTest {
|
||||
return value(x);
|
||||
}
|
||||
|
||||
// A single query but this can throw an exception.
|
||||
boolean query(int x, boolean y) throws RemoteException {
|
||||
if (y) {
|
||||
throw new RemoteException();
|
||||
}
|
||||
return query(x);
|
||||
}
|
||||
|
||||
// Return the expected value of an input, without incrementing the query count.
|
||||
boolean value(int x) {
|
||||
return x % 3 == 0;
|
||||
@@ -138,6 +146,47 @@ public class IpcDataCacheTest {
|
||||
tester.verify(9);
|
||||
}
|
||||
|
||||
// This test is disabled pending an sepolicy change that allows any app to set the
|
||||
// test property.
|
||||
@Test
|
||||
public void testRemoteCall() {
|
||||
|
||||
// A stand-in for the binder. The test verifies that calls are passed through to
|
||||
// this class properly.
|
||||
ServerProxy tester = new ServerProxy();
|
||||
|
||||
// Create a cache that uses simple arithmetic to computer its values.
|
||||
IpcDataCache.Config config = new IpcDataCache.Config(4, MODULE, API, "testCache2");
|
||||
IpcDataCache<Integer, Boolean> testCache =
|
||||
new IpcDataCache<>(config, (x) -> tester.query(x, x % 10 == 9));
|
||||
|
||||
IpcDataCache.setTestMode(true);
|
||||
testCache.testPropertyName();
|
||||
|
||||
tester.verify(0);
|
||||
assertEquals(tester.value(3), testCache.query(3));
|
||||
tester.verify(1);
|
||||
assertEquals(tester.value(3), testCache.query(3));
|
||||
tester.verify(2);
|
||||
testCache.invalidateCache();
|
||||
assertEquals(tester.value(3), testCache.query(3));
|
||||
tester.verify(3);
|
||||
assertEquals(tester.value(5), testCache.query(5));
|
||||
tester.verify(4);
|
||||
assertEquals(tester.value(5), testCache.query(5));
|
||||
tester.verify(4);
|
||||
assertEquals(tester.value(3), testCache.query(3));
|
||||
tester.verify(4);
|
||||
|
||||
try {
|
||||
testCache.query(9);
|
||||
assertEquals(false, true); // The code should not reach this point.
|
||||
} catch (RuntimeException e) {
|
||||
assertEquals(e.getCause() instanceof RemoteException, true);
|
||||
}
|
||||
tester.verify(4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisableCache() {
|
||||
|
||||
@@ -225,6 +274,17 @@ public class IpcDataCacheTest {
|
||||
testPropertyName();
|
||||
}
|
||||
|
||||
TestCache(IpcDataCache.Config c) {
|
||||
this(c, new TestQuery());
|
||||
}
|
||||
|
||||
TestCache(IpcDataCache.Config c, TestQuery query) {
|
||||
super(c, query);
|
||||
mQuery = query;
|
||||
setTestMode(true);
|
||||
testPropertyName();
|
||||
}
|
||||
|
||||
int getRecomputeCount() {
|
||||
return mQuery.getRecomputeCount();
|
||||
}
|
||||
@@ -309,4 +369,48 @@ public class IpcDataCacheTest {
|
||||
assertEquals("foo5", cache.query(5));
|
||||
assertEquals(3, cache.getRecomputeCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfig() {
|
||||
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);
|
||||
assertEquals(bc.isDisabled(), false);
|
||||
assertEquals(cc.isDisabled(), false);
|
||||
assertEquals(dc.isDisabled(), false);
|
||||
|
||||
a.disableAllForCurrentProcess();
|
||||
assertEquals(ac.isDisabled(), true);
|
||||
assertEquals(bc.isDisabled(), false);
|
||||
assertEquals(cc.isDisabled(), false);
|
||||
assertEquals(dc.isDisabled(), true);
|
||||
|
||||
IpcDataCache.Config e = a.child("nameE");
|
||||
TestCache ec = new TestCache(e);
|
||||
assertEquals(ec.isDisabled(), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1781,7 +1781,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
|
||||
@VisibleForTesting
|
||||
DevicePolicyManagerService(Injector injector) {
|
||||
DevicePolicyManager.disableGetKeyguardDisabledFeaturesCache();
|
||||
DevicePolicyManager.disableLocalCaches();
|
||||
|
||||
mInjector = injector;
|
||||
mContext = Objects.requireNonNull(injector.mContext);
|
||||
|
||||
Reference in New Issue
Block a user