Merge "Put a binder cache on DevicePolicyManager APIs" into tm-dev

This commit is contained in:
Lee Shombert 2022-03-31 15:09:47 +00:00 committed by Android (Google) Code Review
commit b53dad8cb0
8 changed files with 310 additions and 57 deletions

View File

@ -64,6 +64,7 @@ import android.nfc.NfcAdapter;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.IpcDataCache;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.os.PersistableBundle;
@ -3781,6 +3782,60 @@ public class DevicePolicyManager {
public static final String EXTRA_RESOURCE_IDS =
"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.
*/
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);
}
}
/** @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);
}
}
/**
* Disable all caches in the local process.
* @hide
*/
public static void disableLocalProcessCaches() {
disableGetKeyguardDisabledFeaturesCache();
disableHasDeviceOwnerCache();
disableGetProfileOwnerOrDeviceOwnerSupervisionComponentCache();
disableIsOrganizationOwnedDeviceWithManagedProfileCache();
disableGetDeviceOwnerOrganizationNameCache();
disableGetOrganizationNameForUserCache();
disableIsNetworkLoggingEnabled();
}
/** @hide */
@NonNull
@TestApi
@ -8380,17 +8435,57 @@ 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();
}
/** @hide per-user version */
@UnsupportedAppUsage
public int getKeyguardDisabledFeatures(@Nullable ComponentName admin, int userHandle) {
if (mService != null) {
try {
return mService.getKeyguardDisabledFeatures(admin, userHandle, mParentInstance);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
return mGetKeyGuardDisabledFeaturesCache.query(new KeyguardQuery(admin, userHandle));
} else {
return KEYGUARD_DISABLE_FEATURES_NONE;
}
return KEYGUARD_DISABLE_FEATURES_NONE;
}
/**
@ -8769,6 +8864,24 @@ 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();
}
/**
* Called by the system to find out whether the device is managed by a Device Owner.
*
@ -8781,11 +8894,7 @@ public class DevicePolicyManager {
@SystemApi
@SuppressLint("RequiresPermission")
public boolean isDeviceManaged() {
try {
return mService.hasDeviceOwner();
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
return mHasDeviceOwnerCache.query(null);
}
/**
@ -9147,6 +9256,26 @@ public class DevicePolicyManager {
return null;
}
private final static BinderApi sGetProfileOwnerOrDeviceOwnerSupervisionComponent =
new BinderApi("getProfileOwnerOrDeviceOwnerSupervisionComponent");
private final BinderCache<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();
}
/**
* Returns the configured supervision app if it exists and is the device owner or policy owner.
* @hide
@ -9154,11 +9283,7 @@ public class DevicePolicyManager {
public @Nullable ComponentName getProfileOwnerOrDeviceOwnerSupervisionComponent(
@NonNull UserHandle user) {
if (mService != null) {
try {
return mService.getProfileOwnerOrDeviceOwnerSupervisionComponent(user);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
return mGetProfileOwnerOrDeviceOwnerSupervisionComponentCache.query(user);
}
return null;
}
@ -9204,6 +9329,24 @@ 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();
}
/**
* Apps can use this method to find out if the device was provisioned as
* organization-owend device with a managed profile.
@ -9220,11 +9363,7 @@ public class DevicePolicyManager {
public boolean isOrganizationOwnedDeviceWithManagedProfile() {
throwIfParentInstance("isOrganizationOwnedDeviceWithManagedProfile");
if (mService != null) {
try {
return mService.isOrganizationOwnedDeviceWithManagedProfile();
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
return mIsOrganizationOwnedDeviceWithManagedProfileCache.query(null);
}
return false;
}
@ -12788,6 +12927,24 @@ 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();
}
/**
* Called by the system to retrieve the name of the organization managing the device.
*
@ -12800,11 +12957,25 @@ public class DevicePolicyManager {
@SystemApi
@SuppressLint("RequiresPermission")
public @Nullable CharSequence getDeviceOwnerOrganizationName() {
try {
return mService.getDeviceOwnerOrganizationName();
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
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();
}
/**
@ -12816,11 +12987,7 @@ public class DevicePolicyManager {
* @hide
*/
public @Nullable CharSequence getOrganizationNameForUser(int userHandle) {
try {
return mService.getOrganizationNameForUser(userHandle);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
return mGetOrganizationNameForUserCache.query(userHandle);
}
/**
@ -13205,6 +13372,25 @@ 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();
}
/**
* Return whether network logging is enabled by a device owner or profile owner of
* a managed profile.
@ -13219,11 +13405,7 @@ public class DevicePolicyManager {
*/
public boolean isNetworkLoggingEnabled(@Nullable ComponentName admin) {
throwIfParentInstance("isNetworkLoggingEnabled");
try {
return mService.isNetworkLoggingEnabled(admin, mContext.getPackageName());
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
return mIsNetworkLoggingEnabledCache.query(admin);
}
/**

View File

@ -1798,6 +1798,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@VisibleForTesting
DevicePolicyManagerService(Injector injector) {
DevicePolicyManager.disableGetKeyguardDisabledFeaturesCache();
mInjector = injector;
mContext = Objects.requireNonNull(injector.mContext);
mHandler = new Handler(Objects.requireNonNull(injector.getMyLooper()));
@ -1889,6 +1891,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
performPolicyVersionUpgrade();
mDeviceManagementResourcesProvider.load();
// The binder caches are not enabled until the first invalidation.
invalidateBinderCaches();
}
/**
* Invalidate the binder API caches. The invalidation itself does not require any
* locking, but this specific call should be protected by getLockObject() to ensure
* that the invalidation is synchronous with cached queries, for those queries that
* are served under getLockObject().
*/
static void invalidateBinderCaches() {
DevicePolicyManager.invalidateBinderCaches();
}
/**
@ -3065,6 +3080,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
!mInjector.storageManagerIsFileBasedEncryptionEnabled())) {
sendChangedNotification(userHandle);
}
invalidateBinderCaches();
}
private void sendChangedNotification(int userHandle) {
@ -3386,6 +3402,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (owner != null) {
mDeviceAdminServiceController.startServiceForOwner(
owner.getPackageName(), userId, actionForLog);
invalidateBinderCaches();
}
}
@ -8411,6 +8428,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
/**
* Gets the disabled state for features in keyguard for the given admin,
* or the aggregate of all active admins if who is null.
* This API is cached: invalidate with invalidateBinderCaches().
*/
@Override
public int getKeyguardDisabledFeatures(ComponentName who, int userHandle, boolean parent) {
@ -8620,6 +8638,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return true;
}
/**
* This API is cached: invalidate with invalidateBinderCaches().
*/
@Override
public boolean hasDeviceOwner() {
final CallerIdentity caller = getCallerIdentity();
@ -9395,6 +9416,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
});
}
/**
* This API is cached: invalidate with invalidateBinderCaches().
*/
@Override
public @Nullable ComponentName getProfileOwnerOrDeviceOwnerSupervisionComponent(
@NonNull UserHandle userHandle) {
@ -9460,6 +9484,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return UserHandle.USER_NULL;
}
/**
* This API is cached: invalidate with invalidateBinderCaches().
*/
@Override
public boolean isOrganizationOwnedDeviceWithManagedProfile() {
if (!mHasFeature) {
@ -13045,6 +13072,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
mConstants = loadConstants();
invalidateBinderCaches();
mInjector.binderWithCleanCallingIdentity(() -> {
final Intent intent = new Intent(
@ -13205,6 +13233,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
.createEvent(DevicePolicyEnums.SEPARATE_PROFILE_CHALLENGE_CHANGED)
.setBoolean(isSeparateProfileChallengeEnabled(userId))
.write();
invalidateBinderCaches();
}
@Override
@ -14628,6 +14657,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
/**
* This API is cached: invalidate with invalidateBinderCaches().
*/
@Override
public CharSequence getDeviceOwnerOrganizationName() {
if (!mHasFeature) {
@ -14642,6 +14674,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
/**
* This API is cached: invalidate with invalidateBinderCaches().
*/
@Override
public CharSequence getOrganizationNameForUser(int userHandle) {
if (!mHasFeature) {
@ -15727,6 +15762,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// available after next boot.
}
/**
* This API is cached: invalidate with invalidateBinderCaches().
*/
@Override
public boolean isNetworkLoggingEnabled(@Nullable ComponentName admin,
@NonNull String packageName) {

View File

@ -217,10 +217,9 @@ class Owners {
Slog.w(TAG, String.format("User %d has both DO and PO, which is not supported",
getDeviceOwnerUserId()));
}
pushToPackageManagerLocked();
notifyChangeLocked();
pushToActivityTaskManagerLocked();
pushToActivityManagerLocked();
pushToAppOpsLocked();
for (ArrayMap.Entry<String, List<String>> entry :
mDeviceOwnerProtectedPackages.entrySet()) {
@ -230,6 +229,21 @@ class Owners {
}
}
// Notify interested parties that things have changed. This does not notify the
// ActivityTaskManager.
private void notifyChangeLocked() {
pushToDevicePolicyManager();
pushToPackageManagerLocked();
pushToActivityManagerLocked();
pushToAppOpsLocked();
}
private void pushToDevicePolicyManager() {
// Not every change here must invalidate the DPM caches, but there is no harm in
// invalidating the caches unnecessarily, provided the invalidation is infrequent.
DevicePolicyManagerService.invalidateBinderCaches();
}
private void pushToPackageManagerLocked() {
final SparseArray<String> po = new SparseArray<>();
for (int i = mProfileOwners.size() - 1; i >= 0; i--) {
@ -344,10 +358,8 @@ class Owners {
mDeviceOwnerUserId = userId;
mUserManagerInternal.setDeviceManaged(true);
pushToPackageManagerLocked();
notifyChangeLocked();
pushToActivityTaskManagerLocked();
pushToActivityManagerLocked();
pushToAppOpsLocked();
}
}
@ -364,10 +376,8 @@ class Owners {
mDeviceOwnerUserId = UserHandle.USER_NULL;
mUserManagerInternal.setDeviceManaged(false);
pushToPackageManagerLocked();
notifyChangeLocked();
pushToActivityTaskManagerLocked();
pushToActivityManagerLocked();
pushToAppOpsLocked();
}
}
@ -378,9 +388,7 @@ class Owners {
/* userRestrictionsMigrated =*/ true, /* remoteBugreportUri =*/ null,
/* remoteBugreportHash =*/ null, /* isOrganizationOwnedDevice =*/ false));
mUserManagerInternal.setUserManaged(userId, true);
pushToPackageManagerLocked();
pushToActivityManagerLocked();
pushToAppOpsLocked();
notifyChangeLocked();
}
}
@ -388,9 +396,7 @@ class Owners {
synchronized (mLock) {
mProfileOwners.remove(userId);
mUserManagerInternal.setUserManaged(userId, false);
pushToPackageManagerLocked();
pushToActivityManagerLocked();
pushToAppOpsLocked();
notifyChangeLocked();
}
}
@ -402,9 +408,7 @@ class Owners {
ownerInfo.remoteBugreportHash, /* isOrganizationOwnedDevice =*/
ownerInfo.isOrganizationOwnedDevice);
mProfileOwners.put(userId, newOwnerInfo);
pushToPackageManagerLocked();
pushToActivityManagerLocked();
pushToAppOpsLocked();
notifyChangeLocked();
}
}
@ -430,10 +434,8 @@ class Owners {
mDeviceOwnerProtectedPackages.put(
mDeviceOwner.packageName, previousProtectedPackages);
}
pushToPackageManagerLocked();
notifyChangeLocked();
pushToActivityTaskManagerLocked();
pushToActivityManagerLocked();
pushToAppOpsLocked();
}
}
@ -765,6 +767,7 @@ class Owners {
if (DEBUG) {
Log.d(TAG, "Writing to device owner file");
}
pushToDevicePolicyManager();
new DeviceOwnerReadWriter().writeToFileLocked();
}
}
@ -774,6 +777,7 @@ class Owners {
if (DEBUG) {
Log.d(TAG, "Writing to profile owner file for user " + userId);
}
pushToDevicePolicyManager();
new ProfileOwnerReadWriter(userId).writeToFileLocked();
}
}

View File

@ -40,6 +40,7 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.IpcDataCache;
import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
@ -75,6 +76,10 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
@Before
public void setUp() throws Exception {
// Disable caches in this test process. This must happen early, since some of the
// following initialization steps invalidate caches.
IpcDataCache.disableForTestMode();
mContext = getContext();
// Make createContextAsUser to work.

View File

@ -128,6 +128,7 @@ import android.net.wifi.WifiSsid;
import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.IpcDataCache;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
@ -261,6 +262,10 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Before
public void setUp() throws Exception {
// Disable caches in this test process. This must happen early, since some of the
// following initialization steps invalidate caches.
IpcDataCache.disableForTestMode();
mContext = getContext();
mServiceContext = mContext;
mServiceContext.binder.callingUid = DpmMockContext.CALLER_UID;

View File

@ -32,6 +32,7 @@ import android.app.admin.DnsEvent;
import android.app.admin.NetworkEvent;
import android.content.Intent;
import android.os.Bundle;
import android.os.IpcDataCache;
import android.os.Message;
import android.os.Parcel;
import android.os.SystemClock;
@ -56,6 +57,10 @@ public class NetworkEventTest extends DpmTestBase {
@Before
public void setUp() throws Exception {
// Disable caches in this test process. This must happen early, since some of the
// following initialization steps invalidate caches.
IpcDataCache.disableForTestMode();
mSpiedDpmMockContext = spy(mMockContext);
mSpiedDpmMockContext.callerPermissions.add(
android.Manifest.permission.MANAGE_DEVICE_ADMINS);

View File

@ -24,6 +24,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
import android.content.ComponentName;
import android.os.IpcDataCache;
import android.os.UserHandle;
import android.test.suitebuilder.annotation.SmallTest;
@ -33,6 +34,7 @@ import com.android.server.devicepolicy.DevicePolicyManagerServiceTestable.Owners
import com.google.android.collect.Lists;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -53,6 +55,13 @@ public class OwnersTest extends DpmTestBase {
private static final List<String> DEVICE_OWNER_PROTECTED_PACKAGES =
Lists.newArrayList("package_1", "package_2");
@Before
public void setUp() throws Exception {
// Disable caches in this test process. This must happen early, since some of the
// following initialization steps invalidate caches.
IpcDataCache.disableForTestMode();
}
@Test
public void testUpgrade01() throws Exception {
getServices().addUsers(10, 11, 20, 21);

View File

@ -28,6 +28,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.os.IpcDataCache;
import android.os.Parcel;
import android.os.UserHandle;
import android.util.TypedXmlPullParser;
@ -128,6 +129,10 @@ public class PolicyVersionUpgraderTest extends DpmTestBase {
@Before
public void setUp() {
// Disable caches in this test process. This must happen early, since some of the
// following initialization steps invalidate caches.
IpcDataCache.disableForTestMode();
mProvider = new FakePolicyUpgraderDataProvider();
mUpgrader = new PolicyVersionUpgrader(mProvider);
mDataDir = new File(mRealTestContext.getCacheDir(), "test-data");