|
|
|
|
@@ -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;
|
|
|
|
|
@@ -531,6 +532,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;
|
|
|
|
|
@@ -1139,6 +1141,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();
|
|
|
|
|
@@ -1252,6 +1259,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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -2104,6 +2113,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);
|
|
|
|
|
@@ -9515,6 +9525,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);
|
|
|
|
|
@@ -18303,6 +18314,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}.
|
|
|
|
|
@@ -18340,7 +18371,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 {
|
|
|
|
|
@@ -18350,37 +18381,67 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean hasIncompatibleAccounts(AccountManager am, Account[] accounts) {
|
|
|
|
|
// TODO(b/244284408): Add test
|
|
|
|
|
final String[] feature_allow =
|
|
|
|
|
{ DevicePolicyManager.ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED };
|
|
|
|
|
final String[] feature_disallow =
|
|
|
|
|
{ DevicePolicyManager.ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED };
|
|
|
|
|
|
|
|
|
|
for (Account account : accounts) {
|
|
|
|
|
if (hasAccountFeatures(am, account, feature_disallow)) {
|
|
|
|
|
Slogf.e(LOG_TAG, "%s has %s", account, feature_disallow[0]);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (!hasAccountFeatures(am, account, feature_allow)) {
|
|
|
|
|
Slogf.e(LOG_TAG, "%s doesn't have %s", account, feature_allow[0]);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
@Override
|
|
|
|
|
public void calculateHasIncompatibleAccounts() {
|
|
|
|
|
new CalculateHasIncompatibleAccountsTask().executeOnExecutor(
|
|
|
|
|
AsyncTask.THREAD_POOL_EXECUTOR, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private 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();
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Slogf.w(LOG_TAG, "Failed to get account feature", e);
|
|
|
|
|
@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};
|
|
|
|
|
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)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (!hasAccountFeatures(am, account, FEATURE_ALLOW)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@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 {
|
|
|
|
|
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);
|
|
|
|
|
@@ -22212,26 +22273,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;
|
|
|
|
|
|