Loading core/api/test-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -538,6 +538,7 @@ package android.app.admin { public class DevicePolicyManager { method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void acknowledgeNewUserDisclaimer(); method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void calculateHasIncompatibleAccounts(); method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void clearOrganizationId(); method @RequiresPermission(android.Manifest.permission.CLEAR_FREEZE_PERIOD) public void clearSystemUpdatePolicyFreezePeriodRecord(); method @RequiresPermission(android.Manifest.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS) public long forceNetworkLogs(); Loading core/java/android/app/admin/DevicePolicyManager.java +17 −0 Original line number Diff line number Diff line Loading @@ -16824,6 +16824,23 @@ public class DevicePolicyManager { } } /** * Recalculate the incompatible accounts cache. * * @hide */ @TestApi @RequiresPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void calculateHasIncompatibleAccounts() { if (mService != null) { try { mService.calculateHasIncompatibleAccounts(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } /** * @return {@code true} if bypassing the device policy management role qualification is allowed * with the current state of the device. core/java/android/app/admin/IDevicePolicyManager.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -608,4 +608,6 @@ interface IDevicePolicyManager { boolean isDeviceFinanced(String callerPackageName); String getFinancedDeviceKioskRoleHolder(String callerPackageName); void calculateHasIncompatibleAccounts(); } services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +86 −45 Original line number Diff line number Diff line Loading @@ -85,6 +85,7 @@ import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY; import static android.Manifest.permission.SET_TIME; import static android.Manifest.permission.SET_TIME_ZONE; import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK; import static android.accounts.AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.MODE_DEFAULT; Loading Loading @@ -532,6 +533,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; Loading Loading @@ -1140,6 +1142,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } if (Intent.ACTION_BOOT_COMPLETED.equals(action)) { calculateHasIncompatibleAccounts(); } if (Intent.ACTION_BOOT_COMPLETED.equals(action) && userHandle == mOwners.getDeviceOwnerUserId()) { mBugreportCollectionManager.checkForPendingBugreportAfterBoot(); Loading Loading @@ -1253,6 +1260,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } else if (ACTION_MANAGED_PROFILE_AVAILABLE.equals(action)) { notifyIfManagedSubscriptionsAreUnavailable( UserHandle.of(userHandle), /* managedProfileAvailable= */ true); } else if (LOGIN_ACCOUNTS_CHANGED_ACTION.equals(action)) { calculateHasIncompatibleAccounts(); } } Loading Loading @@ -2105,6 +2114,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { filter.addAction(Intent.ACTION_USER_STOPPED); filter.addAction(Intent.ACTION_USER_SWITCHED); filter.addAction(Intent.ACTION_USER_UNLOCKED); filter.addAction(LOGIN_ACCOUNTS_CHANGED_ACTION); filter.addAction(ACTION_MANAGED_PROFILE_UNAVAILABLE); filter.addAction(ACTION_MANAGED_PROFILE_AVAILABLE); filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); Loading Loading @@ -9560,6 +9570,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (getLockObject()) { enforceCanSetDeviceOwnerLocked(caller, admin, userId, hasIncompatibleAccountsOrNonAdb); Preconditions.checkArgument(isPackageInstalledForUser(admin.getPackageName(), userId), "Invalid component " + admin + " for device owner"); final ActiveAdmin activeAdmin = getActiveAdminUncheckedLocked(admin, userId); Loading Loading @@ -18386,6 +18397,26 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return isUserAffiliatedWithDeviceLocked(userId); } private boolean hasIncompatibleAccountsOnAnyUser() { if (mHasIncompatibleAccounts == null) { // Hasn't loaded for the first time yet - assume the worst return true; } for (boolean hasIncompatible : mHasIncompatibleAccounts.values()) { if (hasIncompatible) { return true; } } return false; } private boolean hasIncompatibleAccounts(int userId) { return mHasIncompatibleAccounts == null ? true : mHasIncompatibleAccounts.getOrDefault(userId, /* default= */ false); } /** * Return true if a given user has any accounts that'll prevent installing a device or profile * owner {@code owner}. Loading Loading @@ -18423,7 +18454,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } boolean compatible = !hasIncompatibleAccounts(am, accounts); boolean compatible = !hasIncompatibleAccounts(userId); if (compatible) { Slogf.w(LOG_TAG, "All accounts are compatible"); } else { Loading @@ -18433,20 +18464,43 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { }); } private boolean hasIncompatibleAccounts(AccountManager am, Account[] accounts) { // TODO(b/244284408): Add test final String[] feature_allow = @Override public void calculateHasIncompatibleAccounts() { new CalculateHasIncompatibleAccountsTask().executeOnExecutor( AsyncTask.THREAD_POOL_EXECUTOR, null); } @Nullable private volatile Map<Integer, Boolean> mHasIncompatibleAccounts; class CalculateHasIncompatibleAccountsTask extends AsyncTask< Void, Void, Map<Integer, Boolean>> { private static final String[] FEATURE_ALLOW = {DevicePolicyManager.ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED}; final String[] feature_disallow = private static final String[] FEATURE_DISALLOW = {DevicePolicyManager.ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED}; @Override protected Map<Integer, Boolean> doInBackground(Void... args) { List<UserInfo> users = mUserManagerInternal.getUsers(/* excludeDying= */ true); Map<Integer, Boolean> results = new HashMap<>(); for (UserInfo userInfo : users) { results.put(userInfo.id, userHasIncompatibleAccounts(userInfo.id)); } return results; } private boolean userHasIncompatibleAccounts(int id) { AccountManager am = mContext.createContextAsUser(UserHandle.of(id), /* flags= */ 0) .getSystemService(AccountManager.class); Account[] accounts = am.getAccounts(); for (Account account : accounts) { if (hasAccountFeatures(am, account, feature_disallow)) { Slogf.e(LOG_TAG, "%s has %s", account, feature_disallow[0]); if (hasAccountFeatures(am, account, FEATURE_DISALLOW)) { return true; } if (!hasAccountFeatures(am, account, feature_allow)) { Slogf.e(LOG_TAG, "%s doesn't have %s", account, feature_allow[0]); if (!hasAccountFeatures(am, account, FEATURE_ALLOW)) { return true; } } Loading @@ -18454,16 +18508,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return false; } private boolean hasAccountFeatures(AccountManager am, Account account, String[] features) { @Override protected void onPostExecute(Map<Integer, Boolean> results) { mHasIncompatibleAccounts = Collections.unmodifiableMap(results); Slogf.i(LOG_TAG, "Finished calculating hasIncompatibleAccountsTask"); } private static boolean hasAccountFeatures(AccountManager am, Account account, String[] features) { try { // TODO(267156507): Restore without blocking binder thread return false; // return am.hasFeatures(account, features, null, null).getResult(); return am.hasFeatures(account, features, null, null).getResult(); } catch (Exception e) { Slogf.w(LOG_TAG, "Failed to get account feature", e); return false; } } }; private boolean isAdb(CallerIdentity caller) { return isShellUid(caller) || isRootUid(caller); Loading Loading @@ -22295,26 +22356,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } private boolean hasIncompatibleAccountsOnAnyUser() { long callingIdentity = Binder.clearCallingIdentity(); try { for (UserInfo user : mUserManagerInternal.getUsers(/* excludeDying= */ true)) { AccountManager am = mContext.createContextAsUser( UserHandle.of(user.id), /* flags= */ 0) .getSystemService(AccountManager.class); Account[] accounts = am.getAccounts(); if (hasIncompatibleAccounts(am, accounts)) { return true; } } return false; } finally { Binder.restoreCallingIdentity(callingIdentity); } } private void setBypassDevicePolicyManagementRoleQualificationStateInternal( String currentRoleHolder, boolean allowBypass) { boolean stateChanged = false; Loading
core/api/test-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -538,6 +538,7 @@ package android.app.admin { public class DevicePolicyManager { method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void acknowledgeNewUserDisclaimer(); method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void calculateHasIncompatibleAccounts(); method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void clearOrganizationId(); method @RequiresPermission(android.Manifest.permission.CLEAR_FREEZE_PERIOD) public void clearSystemUpdatePolicyFreezePeriodRecord(); method @RequiresPermission(android.Manifest.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS) public long forceNetworkLogs(); Loading
core/java/android/app/admin/DevicePolicyManager.java +17 −0 Original line number Diff line number Diff line Loading @@ -16824,6 +16824,23 @@ public class DevicePolicyManager { } } /** * Recalculate the incompatible accounts cache. * * @hide */ @TestApi @RequiresPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void calculateHasIncompatibleAccounts() { if (mService != null) { try { mService.calculateHasIncompatibleAccounts(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } /** * @return {@code true} if bypassing the device policy management role qualification is allowed * with the current state of the device.
core/java/android/app/admin/IDevicePolicyManager.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -608,4 +608,6 @@ interface IDevicePolicyManager { boolean isDeviceFinanced(String callerPackageName); String getFinancedDeviceKioskRoleHolder(String callerPackageName); void calculateHasIncompatibleAccounts(); }
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +86 −45 Original line number Diff line number Diff line Loading @@ -85,6 +85,7 @@ import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY; import static android.Manifest.permission.SET_TIME; import static android.Manifest.permission.SET_TIME_ZONE; import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK; import static android.accounts.AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.MODE_DEFAULT; Loading Loading @@ -532,6 +533,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; Loading Loading @@ -1140,6 +1142,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } if (Intent.ACTION_BOOT_COMPLETED.equals(action)) { calculateHasIncompatibleAccounts(); } if (Intent.ACTION_BOOT_COMPLETED.equals(action) && userHandle == mOwners.getDeviceOwnerUserId()) { mBugreportCollectionManager.checkForPendingBugreportAfterBoot(); Loading Loading @@ -1253,6 +1260,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } else if (ACTION_MANAGED_PROFILE_AVAILABLE.equals(action)) { notifyIfManagedSubscriptionsAreUnavailable( UserHandle.of(userHandle), /* managedProfileAvailable= */ true); } else if (LOGIN_ACCOUNTS_CHANGED_ACTION.equals(action)) { calculateHasIncompatibleAccounts(); } } Loading Loading @@ -2105,6 +2114,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { filter.addAction(Intent.ACTION_USER_STOPPED); filter.addAction(Intent.ACTION_USER_SWITCHED); filter.addAction(Intent.ACTION_USER_UNLOCKED); filter.addAction(LOGIN_ACCOUNTS_CHANGED_ACTION); filter.addAction(ACTION_MANAGED_PROFILE_UNAVAILABLE); filter.addAction(ACTION_MANAGED_PROFILE_AVAILABLE); filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); Loading Loading @@ -9560,6 +9570,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (getLockObject()) { enforceCanSetDeviceOwnerLocked(caller, admin, userId, hasIncompatibleAccountsOrNonAdb); Preconditions.checkArgument(isPackageInstalledForUser(admin.getPackageName(), userId), "Invalid component " + admin + " for device owner"); final ActiveAdmin activeAdmin = getActiveAdminUncheckedLocked(admin, userId); Loading Loading @@ -18386,6 +18397,26 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return isUserAffiliatedWithDeviceLocked(userId); } private boolean hasIncompatibleAccountsOnAnyUser() { if (mHasIncompatibleAccounts == null) { // Hasn't loaded for the first time yet - assume the worst return true; } for (boolean hasIncompatible : mHasIncompatibleAccounts.values()) { if (hasIncompatible) { return true; } } return false; } private boolean hasIncompatibleAccounts(int userId) { return mHasIncompatibleAccounts == null ? true : mHasIncompatibleAccounts.getOrDefault(userId, /* default= */ false); } /** * Return true if a given user has any accounts that'll prevent installing a device or profile * owner {@code owner}. Loading Loading @@ -18423,7 +18454,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } boolean compatible = !hasIncompatibleAccounts(am, accounts); boolean compatible = !hasIncompatibleAccounts(userId); if (compatible) { Slogf.w(LOG_TAG, "All accounts are compatible"); } else { Loading @@ -18433,20 +18464,43 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { }); } private boolean hasIncompatibleAccounts(AccountManager am, Account[] accounts) { // TODO(b/244284408): Add test final String[] feature_allow = @Override public void calculateHasIncompatibleAccounts() { new CalculateHasIncompatibleAccountsTask().executeOnExecutor( AsyncTask.THREAD_POOL_EXECUTOR, null); } @Nullable private volatile Map<Integer, Boolean> mHasIncompatibleAccounts; class CalculateHasIncompatibleAccountsTask extends AsyncTask< Void, Void, Map<Integer, Boolean>> { private static final String[] FEATURE_ALLOW = {DevicePolicyManager.ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED}; final String[] feature_disallow = private static final String[] FEATURE_DISALLOW = {DevicePolicyManager.ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED}; @Override protected Map<Integer, Boolean> doInBackground(Void... args) { List<UserInfo> users = mUserManagerInternal.getUsers(/* excludeDying= */ true); Map<Integer, Boolean> results = new HashMap<>(); for (UserInfo userInfo : users) { results.put(userInfo.id, userHasIncompatibleAccounts(userInfo.id)); } return results; } private boolean userHasIncompatibleAccounts(int id) { AccountManager am = mContext.createContextAsUser(UserHandle.of(id), /* flags= */ 0) .getSystemService(AccountManager.class); Account[] accounts = am.getAccounts(); for (Account account : accounts) { if (hasAccountFeatures(am, account, feature_disallow)) { Slogf.e(LOG_TAG, "%s has %s", account, feature_disallow[0]); if (hasAccountFeatures(am, account, FEATURE_DISALLOW)) { return true; } if (!hasAccountFeatures(am, account, feature_allow)) { Slogf.e(LOG_TAG, "%s doesn't have %s", account, feature_allow[0]); if (!hasAccountFeatures(am, account, FEATURE_ALLOW)) { return true; } } Loading @@ -18454,16 +18508,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return false; } private boolean hasAccountFeatures(AccountManager am, Account account, String[] features) { @Override protected void onPostExecute(Map<Integer, Boolean> results) { mHasIncompatibleAccounts = Collections.unmodifiableMap(results); Slogf.i(LOG_TAG, "Finished calculating hasIncompatibleAccountsTask"); } private static boolean hasAccountFeatures(AccountManager am, Account account, String[] features) { try { // TODO(267156507): Restore without blocking binder thread return false; // return am.hasFeatures(account, features, null, null).getResult(); return am.hasFeatures(account, features, null, null).getResult(); } catch (Exception e) { Slogf.w(LOG_TAG, "Failed to get account feature", e); return false; } } }; private boolean isAdb(CallerIdentity caller) { return isShellUid(caller) || isRootUid(caller); Loading Loading @@ -22295,26 +22356,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } private boolean hasIncompatibleAccountsOnAnyUser() { long callingIdentity = Binder.clearCallingIdentity(); try { for (UserInfo user : mUserManagerInternal.getUsers(/* excludeDying= */ true)) { AccountManager am = mContext.createContextAsUser( UserHandle.of(user.id), /* flags= */ 0) .getSystemService(AccountManager.class); Account[] accounts = am.getAccounts(); if (hasIncompatibleAccounts(am, accounts)) { return true; } } return false; } finally { Binder.restoreCallingIdentity(callingIdentity); } } private void setBypassDevicePolicyManagementRoleQualificationStateInternal( String currentRoleHolder, boolean allowBypass) { boolean stateChanged = false;