Merge "Change bypassRoleQualification persistence logic" into tm-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
747806ddf8
@@ -69,6 +69,7 @@ class DevicePolicyData {
|
||||
private static final String TAG_PASSWORD_VALIDITY = "password-validity";
|
||||
private static final String TAG_PASSWORD_TOKEN_HANDLE = "password-token";
|
||||
private static final String TAG_PROTECTED_PACKAGES = "protected-packages";
|
||||
private static final String TAG_BYPASS_ROLE_QUALIFICATIONS = "bypass-role-qualifications";
|
||||
private static final String ATTR_VALUE = "value";
|
||||
private static final String ATTR_ALIAS = "alias";
|
||||
private static final String ATTR_ID = "id";
|
||||
@@ -107,6 +108,8 @@ class DevicePolicyData {
|
||||
int mPasswordOwner = -1;
|
||||
long mLastMaximumTimeToLock = -1;
|
||||
boolean mUserSetupComplete = false;
|
||||
boolean mBypassDevicePolicyManagementRoleQualifications = false;
|
||||
String mCurrentRoleHolder;
|
||||
boolean mPaired = false;
|
||||
int mUserProvisioningState;
|
||||
int mPermissionPolicy;
|
||||
@@ -374,6 +377,12 @@ class DevicePolicyData {
|
||||
out.endTag(null, TAG_APPS_SUSPENDED);
|
||||
}
|
||||
|
||||
if (policyData.mBypassDevicePolicyManagementRoleQualifications) {
|
||||
out.startTag(null, TAG_BYPASS_ROLE_QUALIFICATIONS);
|
||||
out.attribute(null, ATTR_VALUE, policyData.mCurrentRoleHolder);
|
||||
out.endTag(null, TAG_BYPASS_ROLE_QUALIFICATIONS);
|
||||
}
|
||||
|
||||
out.endTag(null, "policies");
|
||||
|
||||
out.endDocument();
|
||||
@@ -558,6 +567,9 @@ class DevicePolicyData {
|
||||
} else if (TAG_APPS_SUSPENDED.equals(tag)) {
|
||||
policy.mAppsSuspended =
|
||||
parser.getAttributeBoolean(null, ATTR_VALUE, false);
|
||||
} else if (TAG_BYPASS_ROLE_QUALIFICATIONS.equals(tag)) {
|
||||
policy.mBypassDevicePolicyManagementRoleQualifications = true;
|
||||
policy.mCurrentRoleHolder = parser.getAttributeValue(null, ATTR_VALUE);
|
||||
} else {
|
||||
Slogf.w(TAG, "Unknown tag: %s", tag);
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
|
||||
@@ -138,7 +138,6 @@ import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT
|
||||
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
|
||||
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK;
|
||||
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
|
||||
import static android.provider.Settings.Global.BYPASS_DEVICE_POLICY_MANAGEMENT_ROLE_QUALIFICATIONS;
|
||||
import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
|
||||
import static android.provider.Settings.Secure.MANAGED_PROVISIONING_DPC_DOWNLOADED;
|
||||
import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
|
||||
@@ -222,6 +221,7 @@ import android.app.admin.UnsafeStateException;
|
||||
import android.app.admin.WifiSsidPolicy;
|
||||
import android.app.backup.IBackupManager;
|
||||
import android.app.compat.CompatChanges;
|
||||
import android.app.role.OnRoleHoldersChangedListener;
|
||||
import android.app.role.RoleManager;
|
||||
import android.app.trust.TrustManager;
|
||||
import android.app.usage.UsageStatsManagerInternal;
|
||||
@@ -255,6 +255,7 @@ import android.content.pm.ParceledListSlice;
|
||||
import android.content.pm.PermissionInfo;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.content.pm.Signature;
|
||||
import android.content.pm.StringParceledListSlice;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.content.res.Resources;
|
||||
@@ -409,6 +410,7 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
@@ -756,6 +758,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
private @UserIdInt int mNetworkLoggingNotificationUserId = UserHandle.USER_NULL;
|
||||
|
||||
private final DeviceManagementResourcesProvider mDeviceManagementResourcesProvider;
|
||||
private final DevicePolicyManagementRoleObserver mDevicePolicyManagementRoleObserver;
|
||||
|
||||
private static final boolean ENABLE_LOCK_GUARD = true;
|
||||
|
||||
@@ -1823,6 +1826,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
mBugreportCollectionManager = new RemoteBugreportManager(this, mInjector);
|
||||
|
||||
mDeviceManagementResourcesProvider = mInjector.getDeviceManagementResourcesProvider();
|
||||
mDevicePolicyManagementRoleObserver = new DevicePolicyManagementRoleObserver(mContext);
|
||||
mDevicePolicyManagementRoleObserver.register();
|
||||
|
||||
// "Lite" interface is available even when the device doesn't have the feature
|
||||
LocalServices.addService(DevicePolicyManagerLiteInternal.class, mLocalService);
|
||||
@@ -18663,16 +18668,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
|
||||
android.Manifest.permission.MANAGE_ROLE_HOLDERS));
|
||||
return mInjector.binderWithCleanCallingIdentity(() -> {
|
||||
if (mInjector.settingsGlobalGetInt(
|
||||
BYPASS_DEVICE_POLICY_MANAGEMENT_ROLE_QUALIFICATIONS, /* def= */ 0) == 1) {
|
||||
if (getUserData(
|
||||
UserHandle.USER_SYSTEM).mBypassDevicePolicyManagementRoleQualifications) {
|
||||
return true;
|
||||
}
|
||||
if (shouldAllowBypassingDevicePolicyManagementRoleQualificationInternal()) {
|
||||
mInjector.settingsGlobalPutInt(
|
||||
BYPASS_DEVICE_POLICY_MANAGEMENT_ROLE_QUALIFICATIONS, /* value= */ 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return shouldAllowBypassingDevicePolicyManagementRoleQualificationInternal();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -18685,6 +18685,142 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
return accounts.length == 0;
|
||||
}
|
||||
|
||||
private void setBypassDevicePolicyManagementRoleQualificationStateInternal(
|
||||
String currentRoleHolder, boolean allowBypass) {
|
||||
boolean stateChanged = false;
|
||||
DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM);
|
||||
if (policy.mBypassDevicePolicyManagementRoleQualifications != allowBypass) {
|
||||
policy.mBypassDevicePolicyManagementRoleQualifications = allowBypass;
|
||||
stateChanged = true;
|
||||
}
|
||||
if (!Objects.equals(currentRoleHolder, policy.mCurrentRoleHolder)) {
|
||||
policy.mCurrentRoleHolder = currentRoleHolder;
|
||||
stateChanged = true;
|
||||
}
|
||||
if (stateChanged) {
|
||||
synchronized (getLockObject()) {
|
||||
saveSettingsLocked(UserHandle.USER_SYSTEM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class DevicePolicyManagementRoleObserver implements OnRoleHoldersChangedListener {
|
||||
private RoleManager mRm;
|
||||
private final Executor mExecutor;
|
||||
private final Context mContext;
|
||||
|
||||
DevicePolicyManagementRoleObserver(@NonNull Context context) {
|
||||
mContext = context;
|
||||
mExecutor = mContext.getMainExecutor();
|
||||
mRm = mContext.getSystemService(RoleManager.class);
|
||||
}
|
||||
|
||||
public void register() {
|
||||
mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.SYSTEM);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
|
||||
if (!RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT.equals(roleName)) {
|
||||
return;
|
||||
}
|
||||
String newRoleHolder = getRoleHolder();
|
||||
if (isDefaultRoleHolder(newRoleHolder)) {
|
||||
Slogf.i(LOG_TAG,
|
||||
"onRoleHoldersChanged: Default role holder is set, returning early");
|
||||
return;
|
||||
}
|
||||
if (newRoleHolder == null) {
|
||||
Slogf.i(LOG_TAG,
|
||||
"onRoleHoldersChanged: New role holder is null, returning early");
|
||||
return;
|
||||
}
|
||||
if (shouldAllowBypassingDevicePolicyManagementRoleQualificationInternal()) {
|
||||
Slogf.w(LOG_TAG,
|
||||
"onRoleHoldersChanged: Updating current role holder to " + newRoleHolder);
|
||||
setBypassDevicePolicyManagementRoleQualificationStateInternal(
|
||||
newRoleHolder, /* allowBypass= */ true);
|
||||
return;
|
||||
}
|
||||
DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM);
|
||||
if (!newRoleHolder.equals(policy.mCurrentRoleHolder)) {
|
||||
Slogf.w(LOG_TAG,
|
||||
"onRoleHoldersChanged: You can't set a different role holder, role "
|
||||
+ "is getting revoked from " + newRoleHolder);
|
||||
setBypassDevicePolicyManagementRoleQualificationStateInternal(
|
||||
/* currentRoleHolder= */ null, /* allowBypass= */ false);
|
||||
mRm.removeRoleHolderAsUser(
|
||||
RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT,
|
||||
newRoleHolder,
|
||||
/* flags= */ 0,
|
||||
user,
|
||||
mExecutor,
|
||||
successful -> {});
|
||||
}
|
||||
}
|
||||
|
||||
private String getRoleHolder() {
|
||||
return DevicePolicyManagerService.this.getDevicePolicyManagementRoleHolderPackageName(
|
||||
mContext);
|
||||
}
|
||||
|
||||
private boolean isDefaultRoleHolder(String packageName) {
|
||||
String defaultRoleHolder = getDefaultRoleHolderPackageName();
|
||||
if (packageName == null || defaultRoleHolder == null) {
|
||||
return false;
|
||||
}
|
||||
if (!defaultRoleHolder.equals(packageName)) {
|
||||
return false;
|
||||
}
|
||||
return hasSigningCertificate(
|
||||
packageName, getDefaultRoleHolderPackageSignature());
|
||||
}
|
||||
|
||||
private boolean hasSigningCertificate(String packageName, String certificateString) {
|
||||
if (packageName == null || certificateString == null) {
|
||||
return false;
|
||||
}
|
||||
byte[] certificate;
|
||||
try {
|
||||
certificate = new Signature(certificateString).toByteArray();
|
||||
} catch (IllegalArgumentException e) {
|
||||
Slogf.w(LOG_TAG, "Cannot parse signing certificate: " + certificateString, e);
|
||||
return false;
|
||||
}
|
||||
PackageManager pm = mInjector.getPackageManager();
|
||||
return pm.hasSigningCertificate(
|
||||
packageName, certificate, PackageManager.CERT_INPUT_SHA256);
|
||||
}
|
||||
|
||||
private String getDefaultRoleHolderPackageName() {
|
||||
String[] info = getDefaultRoleHolderPackageNameAndSignature();
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
return info[0];
|
||||
}
|
||||
|
||||
private String getDefaultRoleHolderPackageSignature() {
|
||||
String[] info = getDefaultRoleHolderPackageNameAndSignature();
|
||||
if (info == null || info.length < 2) {
|
||||
return null;
|
||||
}
|
||||
return info[1];
|
||||
}
|
||||
|
||||
private String[] getDefaultRoleHolderPackageNameAndSignature() {
|
||||
String packageNameAndSignature = mContext.getString(
|
||||
com.android.internal.R.string.config_devicePolicyManagement);
|
||||
if (TextUtils.isEmpty(packageNameAndSignature)) {
|
||||
return null;
|
||||
}
|
||||
if (packageNameAndSignature.contains(":")) {
|
||||
return packageNameAndSignature.split(":");
|
||||
}
|
||||
return new String[]{packageNameAndSignature};
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserHandle> getPolicyManagedProfiles(@NonNull UserHandle user) {
|
||||
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
|
||||
|
||||
@@ -102,6 +102,7 @@
|
||||
<uses-permission android:name="android.permission.READ_NEARBY_STREAMING_POLICY" />
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING" />
|
||||
<uses-permission android:name="android.permission.PACKAGE_VERIFICATION_AGENT" />
|
||||
<uses-permission android:name="android.permission.OBSERVE_ROLE_HOLDERS" />
|
||||
|
||||
<queries>
|
||||
<package android:name="com.android.servicestests.apps.suspendtestapp" />
|
||||
|
||||
@@ -237,6 +237,8 @@ public class DpmMockContext extends MockContext {
|
||||
return mMockSystemServices.devicePolicyManager;
|
||||
case Context.LOCATION_SERVICE:
|
||||
return mMockSystemServices.locationManager;
|
||||
case Context.ROLE_SERVICE:
|
||||
return mMockSystemServices.roleManager;
|
||||
}
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import android.app.IActivityTaskManager;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.app.backup.IBackupManager;
|
||||
import android.app.role.RoleManager;
|
||||
import android.app.usage.UsageStatsManagerInternal;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
@@ -131,6 +132,7 @@ public class MockSystemServices {
|
||||
public final VpnManager vpnManager;
|
||||
public final DevicePolicyManager devicePolicyManager;
|
||||
public final LocationManager locationManager;
|
||||
public final RoleManager roleManager;
|
||||
/** Note this is a partial mock, not a real mock. */
|
||||
public final PackageManager packageManager;
|
||||
public final BuildMock buildMock = new BuildMock();
|
||||
@@ -181,6 +183,7 @@ public class MockSystemServices {
|
||||
vpnManager = mock(VpnManager.class);
|
||||
devicePolicyManager = mock(DevicePolicyManager.class);
|
||||
locationManager = mock(LocationManager.class);
|
||||
roleManager = realContext.getSystemService(RoleManager.class);
|
||||
|
||||
// Package manager is huge, so we use a partial mock instead.
|
||||
packageManager = spy(realContext.getPackageManager());
|
||||
|
||||
Reference in New Issue
Block a user