1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settingslib; 18 19 import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE; 20 import static android.app.admin.DevicePolicyManager.MTE_NOT_CONTROLLED_BY_POLICY; 21 import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER; 22 import static android.app.role.RoleManager.ROLE_FINANCED_DEVICE_KIOSK; 23 24 import static com.android.settingslib.Utils.getColorAttrDefaultColor; 25 26 import android.annotation.UserIdInt; 27 import android.app.AppGlobals; 28 import android.app.AppOpsManager; 29 import android.app.admin.DevicePolicyManager; 30 import android.app.admin.EnforcingAdmin; 31 import android.app.admin.PackagePolicy; 32 import android.app.admin.UnknownAuthority; 33 import android.app.ecm.EnhancedConfirmationManager; 34 import android.app.role.RoleManager; 35 import android.content.ComponentName; 36 import android.content.Context; 37 import android.content.Intent; 38 import android.content.pm.IPackageManager; 39 import android.content.pm.PackageManager; 40 import android.content.pm.UserInfo; 41 import android.content.res.TypedArray; 42 import android.graphics.drawable.Drawable; 43 import android.os.Build; 44 import android.os.RemoteException; 45 import android.os.UserHandle; 46 import android.os.UserManager; 47 import android.os.UserManager.EnforcingUser; 48 import android.security.advancedprotection.AdvancedProtectionManager; 49 import android.text.SpannableStringBuilder; 50 import android.text.Spanned; 51 import android.text.style.ForegroundColorSpan; 52 import android.text.style.ImageSpan; 53 import android.util.Log; 54 import android.view.MenuItem; 55 import android.widget.TextView; 56 57 import androidx.annotation.NonNull; 58 import androidx.annotation.Nullable; 59 import androidx.annotation.RequiresApi; 60 import androidx.annotation.VisibleForTesting; 61 62 import com.android.internal.widget.LockPatternUtils; 63 64 import java.util.HashSet; 65 import java.util.List; 66 67 /** 68 * Utility class to host methods usable in adding a restricted padlock icon and showing admin 69 * support message dialog. 70 */ 71 public class RestrictedLockUtilsInternal extends RestrictedLockUtils { 72 73 private static final String LOG_TAG = "RestrictedLockUtils"; 74 private static final boolean DEBUG = Log.isLoggable(LOG_TAG, Log.DEBUG); 75 76 // TODO(b/281701062): reference role name from role manager once its exposed. 77 private static final String ROLE_DEVICE_LOCK_CONTROLLER = 78 "android.app.role.SYSTEM_FINANCED_DEVICE_CONTROLLER"; 79 80 //TODO(b/378931989): Switch to android.app.admin.DevicePolicyIdentifiers.MEMORY_TAGGING_POLICY 81 //when the appropriate flag is launched. 82 private static final String MEMORY_TAGGING_POLICY = "memoryTagging"; 83 84 /** 85 * @return drawables for displaying with settings that are locked by a device admin. 86 */ getRestrictedPadlock(Context context)87 public static Drawable getRestrictedPadlock(Context context) { 88 Drawable restrictedPadlock = context.getDrawable(android.R.drawable.ic_info); 89 final int iconSize = context.getResources().getDimensionPixelSize( 90 android.R.dimen.config_restrictedIconSize); 91 92 TypedArray ta = context.obtainStyledAttributes(new int[]{android.R.attr.colorAccent}); 93 int colorAccent = ta.getColor(0, 0); 94 ta.recycle(); 95 restrictedPadlock.setTint(colorAccent); 96 97 restrictedPadlock.setBounds(0, 0, iconSize, iconSize); 98 return restrictedPadlock; 99 } 100 101 /** 102 * Checks if a given permission requires additional confirmation for the given package 103 * 104 * @return An intent to show the user if additional confirmation is required, null otherwise 105 */ 106 @Nullable checkIfRequiresEnhancedConfirmation(@onNull Context context, @NonNull String settingIdentifier, @NonNull String packageName)107 public static Intent checkIfRequiresEnhancedConfirmation(@NonNull Context context, 108 @NonNull String settingIdentifier, @NonNull String packageName) { 109 110 if (!android.permission.flags.Flags.enhancedConfirmationModeApisEnabled() 111 || !android.security.Flags.extendEcmToAllSettings()) { 112 return null; 113 } 114 115 EnhancedConfirmationManager ecManager = (EnhancedConfirmationManager) context 116 .getSystemService(Context.ECM_ENHANCED_CONFIRMATION_SERVICE); 117 try { 118 if (ecManager.isRestricted(packageName, settingIdentifier)) { 119 return ecManager.createRestrictedSettingDialogIntent( 120 packageName, settingIdentifier); 121 } 122 } catch (PackageManager.NameNotFoundException e) { 123 Log.e(LOG_TAG, "package not found: " + packageName, e); 124 } 125 126 return null; 127 } 128 129 /** 130 * <p>This is {@code true} when the setting is a protected setting (i.e., a sensitive resource), 131 * and the app is restricted (i.e., considered dangerous), and the user has not yet cleared the 132 * app's restriction status (i.e., by clicking "Allow restricted settings" for this app). * 133 */ isEnhancedConfirmationRestricted(@onNull Context context, @NonNull String settingIdentifier, @NonNull String packageName)134 public static boolean isEnhancedConfirmationRestricted(@NonNull Context context, 135 @NonNull String settingIdentifier, @NonNull String packageName) { 136 if (android.permission.flags.Flags.enhancedConfirmationModeApisEnabled() 137 && android.security.Flags.extendEcmToAllSettings()) { 138 try { 139 return context.getSystemService(EnhancedConfirmationManager.class) 140 .isRestricted(packageName, settingIdentifier); 141 } catch (PackageManager.NameNotFoundException e) { 142 Log.e(LOG_TAG, "Exception when retrieving package:" + packageName, e); 143 return false; 144 } 145 } else { 146 try { 147 if (!settingIdentifier.equals(AppOpsManager.OPSTR_BIND_ACCESSIBILITY_SERVICE)) { 148 return false; 149 } 150 int uid = context.getPackageManager().getPackageUid(packageName, 0); 151 final int mode = context.getSystemService(AppOpsManager.class) 152 .noteOpNoThrow(AppOpsManager.OP_ACCESS_RESTRICTED_SETTINGS, 153 uid, packageName); 154 final boolean ecmEnabled = context.getResources().getBoolean( 155 com.android.internal.R.bool.config_enhancedConfirmationModeEnabled); 156 return ecmEnabled && mode != AppOpsManager.MODE_ALLOWED 157 && mode != AppOpsManager.MODE_DEFAULT; 158 } catch (Exception e) { 159 // Fallback in case if app ops is not available in testing. 160 return false; 161 } 162 } 163 } 164 165 /** 166 * Checks if a restriction is enforced on a user and returns the enforced admin and 167 * admin userId. 168 * 169 * @param userRestriction Restriction to check 170 * @param userId User which we need to check if restriction is enforced on. 171 * @return EnforcedAdmin Object containing the enforced admin component and admin user details, 172 * or {@code null} If the restriction is not set. If the restriction is set by both device owner 173 * and profile owner, then the admin component will be set to {@code null} and userId to 174 * {@link UserHandle#USER_NULL}. 175 */ checkIfRestrictionEnforced(Context context, String userRestriction, int userId)176 public static EnforcedAdmin checkIfRestrictionEnforced(Context context, 177 String userRestriction, int userId) { 178 final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( 179 Context.DEVICE_POLICY_SERVICE); 180 if (dpm == null) { 181 return null; 182 } 183 184 final UserManager um = UserManager.get(context); 185 final UserHandle userHandle = UserHandle.of(userId); 186 final List<UserManager.EnforcingUser> enforcingUsers = 187 um.getUserRestrictionSources(userRestriction, userHandle); 188 189 if (enforcingUsers.isEmpty()) { 190 // Restriction is not enforced. 191 return null; 192 } 193 final int size = enforcingUsers.size(); 194 if (size > 1) { 195 final EnforcedAdmin enforcedAdmin = EnforcedAdmin 196 .createDefaultEnforcedAdminWithRestriction(userRestriction); 197 enforcedAdmin.user = userHandle; 198 if (DEBUG) { 199 Log.d(LOG_TAG, "Multiple (" + size + ") enforcing users for restriction '" 200 + userRestriction + "' on user " + userHandle + "; returning default admin " 201 + "(" + enforcedAdmin + ")"); 202 } 203 return enforcedAdmin; 204 } 205 206 final EnforcingUser enforcingUser = enforcingUsers.get(0); 207 final int restrictionSource = enforcingUser.getUserRestrictionSource(); 208 if (restrictionSource == UserManager.RESTRICTION_SOURCE_SYSTEM) { 209 return null; 210 } 211 212 if (android.security.Flags.aapmApi()) { 213 EnforcingAdmin admin = dpm.getEnforcingAdmin(userId, userRestriction); 214 if (admin != null) { 215 return new EnforcedAdmin(admin.getComponentName(), userRestriction, 216 admin.getUserHandle()); 217 } 218 } 219 220 final EnforcedAdmin admin = 221 getProfileOrDeviceOwner(context, userRestriction, enforcingUser.getUserHandle()); 222 if (admin != null) { 223 return admin; 224 } 225 return EnforcedAdmin.createDefaultEnforcedAdminWithRestriction(userRestriction); 226 } 227 hasBaseUserRestriction(Context context, String userRestriction, int userId)228 public static boolean hasBaseUserRestriction(Context context, 229 String userRestriction, int userId) { 230 final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); 231 return um.hasBaseUserRestriction(userRestriction, UserHandle.of(userId)); 232 } 233 234 /** 235 * Checks whether keyguard features are disabled by policy. 236 * 237 * @param context {@link Context} for the calling user. 238 * 239 * @param keyguardFeatures Any one of keyguard features that can be 240 * disabled by {@link android.app.admin.DevicePolicyManager#setKeyguardDisabledFeatures}. 241 * 242 * @param userId User to check enforced admin status for. 243 * 244 * @return EnforcedAdmin Object containing the enforced admin component and admin user details, 245 * or {@code null} If the notification features are not disabled. If the restriction is set by 246 * multiple admins, then the admin component will be set to {@code null} and userId to 247 * {@link UserHandle#USER_NULL}. 248 */ checkIfKeyguardFeaturesDisabled(Context context, int keyguardFeatures, final @UserIdInt int userId)249 public static EnforcedAdmin checkIfKeyguardFeaturesDisabled(Context context, 250 int keyguardFeatures, final @UserIdInt int userId) { 251 UserInfo userInfo = UserManager.get(context).getUserInfo(userId); 252 if (userInfo == null) { 253 Log.w(LOG_TAG, "User " + userId + " does not exist"); 254 return null; 255 } 256 257 final LockSettingCheck check = 258 (dpm, admin, checkUser) -> { 259 int effectiveFeatures = dpm.getKeyguardDisabledFeatures(admin, checkUser); 260 if (checkUser != userId) { 261 // This case is reached when {@code checkUser} is a managed profile and 262 // {@code userId} is the parent user. 263 effectiveFeatures &= PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER; 264 } 265 return (effectiveFeatures & keyguardFeatures) != KEYGUARD_DISABLE_FEATURES_NONE; 266 }; 267 if (userInfo.isManagedProfile()) { 268 DevicePolicyManager dpm = 269 (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); 270 return findEnforcedAdmin(dpm.getActiveAdminsAsUser(userId), dpm, userId, check); 271 } 272 return checkForLockSetting(context, userId, check); 273 } 274 275 /** 276 * @return the UserHandle for a userId. Return null for USER_NULL 277 */ getUserHandleOf(@serIdInt int userId)278 private static UserHandle getUserHandleOf(@UserIdInt int userId) { 279 if (userId == UserHandle.USER_NULL) { 280 return null; 281 } else { 282 return UserHandle.of(userId); 283 } 284 } 285 286 /** 287 * Filter a set of device admins based on a predicate {@code check}. This is equivalent to 288 * {@code admins.stream().filter(check).map(x → new EnforcedAdmin(admin, userId)} except it's 289 * returning a zero/one/many-type thing. 290 * 291 * @param admins set of candidate device admins identified by {@link ComponentName}. 292 * @param userId user to create the resultant {@link EnforcedAdmin} as. 293 * @param check filter predicate. 294 * 295 * @return {@code null} if none of the {@param admins} match. 296 * An {@link EnforcedAdmin} if exactly one of the admins matches. 297 * Otherwise, {@link EnforcedAdmin#MULTIPLE_ENFORCED_ADMIN} for multiple matches. 298 */ 299 @Nullable findEnforcedAdmin(@ullable List<ComponentName> admins, @NonNull DevicePolicyManager dpm, @UserIdInt int userId, @NonNull LockSettingCheck check)300 private static EnforcedAdmin findEnforcedAdmin(@Nullable List<ComponentName> admins, 301 @NonNull DevicePolicyManager dpm, @UserIdInt int userId, 302 @NonNull LockSettingCheck check) { 303 if (admins == null) { 304 return null; 305 } 306 307 final UserHandle user = getUserHandleOf(userId); 308 EnforcedAdmin enforcedAdmin = null; 309 for (ComponentName admin : admins) { 310 if (check.isEnforcing(dpm, admin, userId)) { 311 if (enforcedAdmin == null) { 312 enforcedAdmin = new EnforcedAdmin(admin, user); 313 } else { 314 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN; 315 } 316 } 317 } 318 return enforcedAdmin; 319 } 320 checkIfUninstallBlocked(Context context, String packageName, int userId)321 public static EnforcedAdmin checkIfUninstallBlocked(Context context, 322 String packageName, int userId) { 323 EnforcedAdmin allAppsControlDisallowedAdmin = checkIfRestrictionEnforced(context, 324 UserManager.DISALLOW_APPS_CONTROL, userId); 325 if (allAppsControlDisallowedAdmin != null) { 326 return allAppsControlDisallowedAdmin; 327 } 328 EnforcedAdmin allAppsUninstallDisallowedAdmin = checkIfRestrictionEnforced(context, 329 UserManager.DISALLOW_UNINSTALL_APPS, userId); 330 if (allAppsUninstallDisallowedAdmin != null) { 331 return allAppsUninstallDisallowedAdmin; 332 } 333 IPackageManager ipm = AppGlobals.getPackageManager(); 334 try { 335 if (ipm.getBlockUninstallForUser(packageName, userId)) { 336 return getProfileOrDeviceOwner(context, getUserHandleOf(userId)); 337 } 338 } catch (RemoteException e) { 339 // Nothing to do 340 } 341 return null; 342 } 343 344 /** 345 * Check if an application is suspended. 346 * 347 * @return EnforcedAdmin Object containing the enforced admin component and admin user details, 348 * or {@code null} if the application is not suspended. 349 */ checkIfApplicationIsSuspended(Context context, String packageName, int userId)350 public static EnforcedAdmin checkIfApplicationIsSuspended(Context context, String packageName, 351 int userId) { 352 IPackageManager ipm = AppGlobals.getPackageManager(); 353 try { 354 if (ipm.isPackageSuspendedForUser(packageName, userId)) { 355 return getProfileOrDeviceOwner(context, getUserHandleOf(userId)); 356 } 357 } catch (RemoteException | IllegalArgumentException e) { 358 // Nothing to do 359 } 360 return null; 361 } 362 checkIfInputMethodDisallowed(Context context, String packageName, int userId)363 public static EnforcedAdmin checkIfInputMethodDisallowed(Context context, 364 String packageName, int userId) { 365 DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( 366 Context.DEVICE_POLICY_SERVICE); 367 if (dpm == null) { 368 return null; 369 } 370 EnforcedAdmin admin = getProfileOrDeviceOwner(context, getUserHandleOf(userId)); 371 boolean permitted = true; 372 if (admin != null) { 373 permitted = dpm.isInputMethodPermittedByAdmin(admin.component, 374 packageName, userId); 375 } 376 377 boolean permittedByParentAdmin = true; 378 EnforcedAdmin profileAdmin = null; 379 int managedProfileId = getManagedProfileId(context, userId); 380 if (managedProfileId != UserHandle.USER_NULL) { 381 profileAdmin = getProfileOrDeviceOwner(context, getUserHandleOf(managedProfileId)); 382 // If the device is an organization-owned device with a managed profile, the 383 // managedProfileId will be used instead of the affected userId. This is because 384 // isInputMethodPermittedByAdmin is called on the parent DPM instance, which will 385 // return results affecting the personal profile. 386 if (profileAdmin != null && dpm.isOrganizationOwnedDeviceWithManagedProfile()) { 387 DevicePolicyManager parentDpm = sProxy.getParentProfileInstance(dpm, 388 UserManager.get(context).getUserInfo(managedProfileId)); 389 permittedByParentAdmin = parentDpm.isInputMethodPermittedByAdmin( 390 profileAdmin.component, packageName, managedProfileId); 391 } 392 } 393 if (!permitted && !permittedByParentAdmin) { 394 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN; 395 } else if (!permitted) { 396 return admin; 397 } else if (!permittedByParentAdmin) { 398 return profileAdmin; 399 } 400 return null; 401 } 402 403 /** 404 * @param context 405 * @param userId user id of a managed profile. 406 * @return is remote contacts search disallowed. 407 */ checkIfRemoteContactSearchDisallowed(Context context, int userId)408 public static EnforcedAdmin checkIfRemoteContactSearchDisallowed(Context context, int userId) { 409 DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( 410 Context.DEVICE_POLICY_SERVICE); 411 if (dpm == null) { 412 return null; 413 } 414 EnforcedAdmin admin = getProfileOwner(context, userId); 415 if (admin == null) { 416 return null; 417 } 418 UserHandle userHandle = UserHandle.of(userId); 419 if (dpm.getCrossProfileContactsSearchDisabled(userHandle) 420 && dpm.getCrossProfileCallerIdDisabled(userHandle)) { 421 return admin; 422 } 423 return null; 424 } 425 checkIfAccessibilityServiceDisallowed(Context context, String packageName, int userId)426 public static EnforcedAdmin checkIfAccessibilityServiceDisallowed(Context context, 427 String packageName, int userId) { 428 DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( 429 Context.DEVICE_POLICY_SERVICE); 430 if (dpm == null) { 431 return null; 432 } 433 EnforcedAdmin admin = getProfileOrDeviceOwner(context, getUserHandleOf(userId)); 434 boolean permitted = true; 435 if (admin != null) { 436 permitted = dpm.isAccessibilityServicePermittedByAdmin(admin.component, 437 packageName, userId); 438 } 439 int managedProfileId = getManagedProfileId(context, userId); 440 EnforcedAdmin profileAdmin = getProfileOrDeviceOwner(context, 441 getUserHandleOf(managedProfileId)); 442 boolean permittedByProfileAdmin = true; 443 if (profileAdmin != null) { 444 permittedByProfileAdmin = dpm.isAccessibilityServicePermittedByAdmin( 445 profileAdmin.component, packageName, managedProfileId); 446 } 447 if (!permitted && !permittedByProfileAdmin) { 448 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN; 449 } else if (!permitted) { 450 return admin; 451 } else if (!permittedByProfileAdmin) { 452 return profileAdmin; 453 } 454 return null; 455 } 456 457 /** 458 * Retrieves the user ID of a managed profile associated with a specific user. 459 * 460 * <p>This method iterates over the users in the profile group associated with the given user ID 461 * and returns the ID of the user that is identified as a managed profile user. 462 * If no managed profile is found, it returns {@link UserHandle#USER_NULL}. 463 * 464 * @param context The context used to obtain the {@link UserManager} system service. 465 * @param userId The ID of the user for whom to find the managed profile. 466 * @return The user ID of the managed profile, or {@link UserHandle#USER_NULL} if none exists. 467 */ getManagedProfileId(Context context, int userId)468 private static int getManagedProfileId(Context context, int userId) { 469 UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); 470 List<UserInfo> userProfiles = um.getProfiles(userId); 471 for (UserInfo uInfo : userProfiles) { 472 if (uInfo.isManagedProfile()) { 473 return uInfo.id; 474 } 475 } 476 return UserHandle.USER_NULL; 477 } 478 479 /** 480 * Check if account management for a specific type of account is disabled by admin. 481 * Only a profile or device owner can disable account management. So, we check if account 482 * management is disabled and return profile or device owner on the calling user. 483 * 484 * @return EnforcedAdmin Object containing the enforced admin component and admin user details, 485 * or {@code null} if the account management is not disabled. 486 */ checkIfAccountManagementDisabled(Context context, String accountType, int userId)487 public static EnforcedAdmin checkIfAccountManagementDisabled(Context context, 488 String accountType, int userId) { 489 if (accountType == null) { 490 return null; 491 } 492 DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( 493 Context.DEVICE_POLICY_SERVICE); 494 PackageManager pm = context.getPackageManager(); 495 if (!pm.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN) || dpm == null) { 496 return null; 497 } 498 boolean isAccountTypeDisabled = false; 499 String[] disabledTypes = dpm.getAccountTypesWithManagementDisabledAsUser(userId); 500 for (String type : disabledTypes) { 501 if (accountType.equals(type)) { 502 isAccountTypeDisabled = true; 503 break; 504 } 505 } 506 if (!isAccountTypeDisabled) { 507 return null; 508 } 509 return getProfileOrDeviceOwner(context, getUserHandleOf(userId)); 510 } 511 512 /** 513 * Check if USB data signaling (except from charging functions) is disabled by the admin. 514 * Only a device owner or a profile owner on an organization-owned managed profile can disable 515 * USB data signaling. 516 * 517 * @return EnforcedAdmin Object containing the enforced admin component and admin user details, 518 * or {@code null} if USB data signaling is not disabled. 519 */ checkIfUsbDataSignalingIsDisabled(Context context, int userId)520 public static EnforcedAdmin checkIfUsbDataSignalingIsDisabled(Context context, int userId) { 521 DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class); 522 if (dpm == null || dpm.isUsbDataSignalingEnabled()) { 523 return null; 524 } else { 525 EnforcedAdmin admin = getProfileOrDeviceOwner(context, getUserHandleOf(userId)); 526 int managedProfileId = getManagedProfileId(context, userId); 527 if (admin == null && managedProfileId != UserHandle.USER_NULL) { 528 admin = getProfileOrDeviceOwner(context, getUserHandleOf(managedProfileId)); 529 } 530 return admin; 531 } 532 } 533 534 /** 535 * Check if user control over metered data usage of {@code packageName} is disabled by the 536 * profile or device owner. 537 * 538 * @return EnforcedAdmin object containing the enforced admin component and admin user details, 539 * or {@code null} if the user control is not disabled. 540 */ checkIfMeteredDataUsageUserControlDisabled(Context context, String packageName, int userId)541 public static EnforcedAdmin checkIfMeteredDataUsageUserControlDisabled(Context context, 542 String packageName, int userId) { 543 RoleManager roleManager = context.getSystemService(RoleManager.class); 544 UserHandle userHandle = getUserHandleOf(userId); 545 if (roleManager.getRoleHoldersAsUser(ROLE_FINANCED_DEVICE_KIOSK, userHandle) 546 .contains(packageName) 547 || roleManager.getRoleHoldersAsUser(ROLE_DEVICE_LOCK_CONTROLLER, userHandle) 548 .contains(packageName)) { 549 // There is no actual device admin for a financed device, but metered data usage 550 // control should still be disabled for both controller and kiosk apps. 551 return new EnforcedAdmin(); 552 } 553 554 final EnforcedAdmin enforcedAdmin = getProfileOrDeviceOwner(context, 555 userHandle); 556 if (enforcedAdmin == null) { 557 return null; 558 } 559 560 final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( 561 Context.DEVICE_POLICY_SERVICE); 562 return dpm.isMeteredDataDisabledPackageForUser(enforcedAdmin.component, packageName, userId) 563 ? enforcedAdmin : null; 564 } 565 566 /** 567 * Checks if an admin has enforced minimum password quality or complexity requirements on the 568 * given user. 569 * 570 * @return EnforcedAdmin Object containing the enforced admin component and admin user details, 571 * or {@code null} if no quality requirements are set. If the requirements are set by 572 * multiple device admins, then the admin component will be set to {@code null} and userId to 573 * {@link UserHandle#USER_NULL}. 574 */ checkIfPasswordQualityIsSet(Context context, int userId)575 public static EnforcedAdmin checkIfPasswordQualityIsSet(Context context, int userId) { 576 final LockSettingCheck check = 577 (DevicePolicyManager dpm, ComponentName admin, @UserIdInt int checkUser) -> 578 dpm.getPasswordQuality(admin, checkUser) 579 > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; 580 581 final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( 582 Context.DEVICE_POLICY_SERVICE); 583 if (dpm == null) { 584 return null; 585 } 586 587 LockPatternUtils lockPatternUtils = new LockPatternUtils(context); 588 final int aggregatedComplexity = dpm.getAggregatedPasswordComplexityForUser(userId); 589 if (aggregatedComplexity > DevicePolicyManager.PASSWORD_COMPLEXITY_NONE) { 590 // First, check if there's a Device Owner. If so, then only it can apply password 591 // complexity requiremnts (there can be no secondary profiles). 592 final UserHandle deviceOwnerUser = dpm.getDeviceOwnerUser(); 593 if (deviceOwnerUser != null) { 594 return new EnforcedAdmin(dpm.getDeviceOwnerComponentOnAnyUser(), deviceOwnerUser); 595 } 596 597 // The complexity could be enforced by a Profile Owner - either in the current user 598 // or the current user is the parent user that is affected by the profile owner. 599 for (UserInfo userInfo : UserManager.get(context).getProfiles(userId)) { 600 final ComponentName profileOwnerComponent = dpm.getProfileOwnerAsUser(userInfo.id); 601 if (profileOwnerComponent != null) { 602 return new EnforcedAdmin(profileOwnerComponent, getUserHandleOf(userInfo.id)); 603 } 604 } 605 606 // Should not get here: A Device Owner or Profile Owner should be found. 607 throw new IllegalStateException( 608 String.format("Could not find admin enforcing complexity %d for user %d", 609 aggregatedComplexity, userId)); 610 } 611 612 if (sProxy.isSeparateProfileChallengeEnabled(lockPatternUtils, userId)) { 613 // userId is managed profile and has a separate challenge, only consider 614 // the admins in that user. 615 final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userId); 616 if (admins == null) { 617 return null; 618 } 619 EnforcedAdmin enforcedAdmin = null; 620 final UserHandle user = getUserHandleOf(userId); 621 for (ComponentName admin : admins) { 622 if (check.isEnforcing(dpm, admin, userId)) { 623 if (enforcedAdmin == null) { 624 enforcedAdmin = new EnforcedAdmin(admin, user); 625 } else { 626 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN; 627 } 628 } 629 } 630 return enforcedAdmin; 631 } else { 632 return checkForLockSetting(context, userId, check); 633 } 634 } 635 636 /** 637 * Checks if any admin has set maximum time to lock. 638 * 639 * @return EnforcedAdmin Object containing the enforced admin component and admin user details, 640 * or {@code null} if no admin has set this restriction. If multiple admins has set this, then 641 * the admin component will be set to {@code null} and userId to {@link UserHandle#USER_NULL} 642 */ checkIfMaximumTimeToLockIsSet(Context context)643 public static EnforcedAdmin checkIfMaximumTimeToLockIsSet(Context context) { 644 return checkForLockSetting(context, UserHandle.myUserId(), 645 (DevicePolicyManager dpm, ComponentName admin, @UserIdInt int userId) -> 646 dpm.getMaximumTimeToLock(admin, userId) > 0); 647 } 648 649 private interface LockSettingCheck { isEnforcing(DevicePolicyManager dpm, ComponentName admin, @UserIdInt int userId)650 boolean isEnforcing(DevicePolicyManager dpm, ComponentName admin, @UserIdInt int userId); 651 } 652 653 /** 654 * Checks whether any of the user's profiles enforce the lock setting. A managed profile is only 655 * included if it does not have a separate challenge. 656 * 657 * The user identified by {@param userId} is always included. 658 */ checkForLockSetting( Context context, @UserIdInt int userId, LockSettingCheck check)659 private static EnforcedAdmin checkForLockSetting( 660 Context context, @UserIdInt int userId, LockSettingCheck check) { 661 final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( 662 Context.DEVICE_POLICY_SERVICE); 663 if (dpm == null) { 664 return null; 665 } 666 final LockPatternUtils lockPatternUtils = new LockPatternUtils(context); 667 EnforcedAdmin enforcedAdmin = null; 668 // Return all admins for this user and the profiles that are visible from this 669 // user that do not use a separate work challenge. 670 for (UserInfo userInfo : UserManager.get(context).getProfiles(userId)) { 671 final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userInfo.id); 672 if (admins == null) { 673 continue; 674 } 675 final UserHandle user = getUserHandleOf(userInfo.id); 676 final boolean isSeparateProfileChallengeEnabled = 677 sProxy.isSeparateProfileChallengeEnabled(lockPatternUtils, userInfo.id); 678 for (ComponentName admin : admins) { 679 if (!isSeparateProfileChallengeEnabled) { 680 if (check.isEnforcing(dpm, admin, userInfo.id)) { 681 if (enforcedAdmin == null) { 682 enforcedAdmin = new EnforcedAdmin(admin, user); 683 } else { 684 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN; 685 } 686 // This same admins could have set policies both on the managed profile 687 // and on the parent. So, if the admin has set the policy on the 688 // managed profile here, we don't need to further check if that admin 689 // has set policy on the parent admin. 690 continue; 691 } 692 } 693 if (userInfo.isManagedProfile()) { 694 // If userInfo.id is a managed profile, we also need to look at 695 // the policies set on the parent. 696 DevicePolicyManager parentDpm = sProxy.getParentProfileInstance(dpm, userInfo); 697 if (check.isEnforcing(parentDpm, admin, userInfo.id)) { 698 if (enforcedAdmin == null) { 699 enforcedAdmin = new EnforcedAdmin(admin, user); 700 } else { 701 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN; 702 } 703 } 704 } 705 } 706 } 707 return enforcedAdmin; 708 } 709 getDeviceOwner(Context context)710 public static EnforcedAdmin getDeviceOwner(Context context) { 711 return getDeviceOwner(context, null); 712 } 713 getDeviceOwner(Context context, String enforcedRestriction)714 private static EnforcedAdmin getDeviceOwner(Context context, String enforcedRestriction) { 715 final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( 716 Context.DEVICE_POLICY_SERVICE); 717 if (dpm == null) { 718 return null; 719 } 720 ComponentName adminComponent = dpm.getDeviceOwnerComponentOnAnyUser(); 721 if (adminComponent != null) { 722 return new EnforcedAdmin( 723 adminComponent, enforcedRestriction, dpm.getDeviceOwnerUser()); 724 } 725 return null; 726 } 727 getProfileOwner(Context context, int userId)728 private static EnforcedAdmin getProfileOwner(Context context, int userId) { 729 return getProfileOwner(context, null, userId); 730 } 731 getProfileOwner( Context context, String enforcedRestriction, int userId)732 private static EnforcedAdmin getProfileOwner( 733 Context context, String enforcedRestriction, int userId) { 734 if (userId == UserHandle.USER_NULL) { 735 return null; 736 } 737 final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( 738 Context.DEVICE_POLICY_SERVICE); 739 if (dpm == null) { 740 return null; 741 } 742 ComponentName adminComponent = dpm.getProfileOwnerAsUser(userId); 743 if (adminComponent != null) { 744 return new EnforcedAdmin(adminComponent, enforcedRestriction, getUserHandleOf(userId)); 745 } 746 return null; 747 } 748 749 /** 750 * Set the menu item as disabled by admin by adding a restricted padlock at the end of the 751 * text and set the click listener which will send an intent to show the admin support details 752 * dialog. If the admin is null, remove the padlock and disabled color span. When the admin is 753 * null, we also set the OnMenuItemClickListener to null, so if you want to set a custom 754 * OnMenuItemClickListener, set it after calling this method. 755 */ setMenuItemAsDisabledByAdmin(final Context context, final MenuItem item, final EnforcedAdmin admin)756 public static void setMenuItemAsDisabledByAdmin(final Context context, 757 final MenuItem item, final EnforcedAdmin admin) { 758 SpannableStringBuilder sb = new SpannableStringBuilder(item.getTitle()); 759 removeExistingRestrictedSpans(sb); 760 761 if (admin != null) { 762 final int disabledColor = getColorAttrDefaultColor(context, 763 android.R.attr.textColorHint); 764 sb.setSpan(new ForegroundColorSpan(disabledColor), 0, sb.length(), 765 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 766 ImageSpan image = new RestrictedLockImageSpan(context); 767 sb.append(" ", image, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 768 769 item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { 770 @Override 771 public boolean onMenuItemClick(MenuItem item) { 772 sendShowAdminSupportDetailsIntent(context, admin); 773 return true; 774 } 775 }); 776 } else { 777 item.setOnMenuItemClickListener(null); 778 } 779 item.setTitle(sb); 780 } 781 removeExistingRestrictedSpans(SpannableStringBuilder sb)782 private static void removeExistingRestrictedSpans(SpannableStringBuilder sb) { 783 final int length = sb.length(); 784 RestrictedLockImageSpan[] imageSpans = sb.getSpans(length - 1, length, 785 RestrictedLockImageSpan.class); 786 for (ImageSpan span : imageSpans) { 787 final int start = sb.getSpanStart(span); 788 final int end = sb.getSpanEnd(span); 789 sb.removeSpan(span); 790 sb.delete(start, end); 791 } 792 ForegroundColorSpan[] colorSpans = sb.getSpans(0, length, ForegroundColorSpan.class); 793 for (ForegroundColorSpan span : colorSpans) { 794 sb.removeSpan(span); 795 } 796 } 797 isAdminInCurrentUserOrProfile(Context context, ComponentName admin)798 public static boolean isAdminInCurrentUserOrProfile(Context context, ComponentName admin) { 799 DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( 800 Context.DEVICE_POLICY_SERVICE); 801 UserManager um = UserManager.get(context); 802 for (UserInfo userInfo : um.getProfiles(UserHandle.myUserId())) { 803 if (dpm.isAdminActiveAsUser(admin, userInfo.id)) { 804 return true; 805 } 806 } 807 return false; 808 } 809 setTextViewPadlock(Context context, TextView textView, boolean showPadlock)810 public static void setTextViewPadlock(Context context, 811 TextView textView, boolean showPadlock) { 812 final SpannableStringBuilder sb = new SpannableStringBuilder(textView.getText()); 813 removeExistingRestrictedSpans(sb); 814 if (showPadlock) { 815 final ImageSpan image = new RestrictedLockImageSpan(context); 816 sb.append(" ", image, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 817 } 818 textView.setText(sb); 819 } 820 821 /** 822 * Takes a {@link android.widget.TextView} and applies an alpha so that the text looks like 823 * disabled and appends a padlock to the text. This assumes that there are no 824 * ForegroundColorSpans and RestrictedLockImageSpans used on the TextView. 825 */ setTextViewAsDisabledByAdmin(Context context, TextView textView, boolean disabled)826 public static void setTextViewAsDisabledByAdmin(Context context, 827 TextView textView, boolean disabled) { 828 final SpannableStringBuilder sb = new SpannableStringBuilder(textView.getText()); 829 removeExistingRestrictedSpans(sb); 830 if (disabled) { 831 final int disabledColor = Utils.getDisabled(context, 832 textView.getCurrentTextColor()); 833 sb.setSpan(new ForegroundColorSpan(disabledColor), 0, sb.length(), 834 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 835 textView.setCompoundDrawables(null, null, getRestrictedPadlock(context), null); 836 textView.setCompoundDrawablePadding(context.getResources().getDimensionPixelSize( 837 R.dimen.restricted_icon_padding)); 838 } else { 839 textView.setCompoundDrawables(null, null, null, null); 840 } 841 textView.setText(sb); 842 } 843 844 /** 845 * Checks whether MTE (Advanced memory protection) controls are disabled by the enterprise 846 * policy. 847 */ 848 @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) checkIfMteIsDisabled(Context context)849 public static EnforcedAdmin checkIfMteIsDisabled(Context context) { 850 final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class); 851 if (dpm.getMtePolicy() == MTE_NOT_CONTROLLED_BY_POLICY) { 852 return null; 853 } 854 EnforcingAdmin enforcingAdmin = context.getSystemService(DevicePolicyManager.class) 855 .getEnforcingAdmin(context.getUserId(), MEMORY_TAGGING_POLICY); 856 if (enforcingAdmin == null) { 857 Log.w(LOG_TAG, "MTE is controlled by policy but could not find enforcing admin."); 858 } 859 860 return EnforcedAdmin.createDefaultEnforcedAdminWithRestriction(MEMORY_TAGGING_POLICY); 861 } 862 863 /** 864 * Checks if the identifier is enforced by advanced protection. 865 */ 866 @RequiresApi(Build.VERSION_CODES.BAKLAVA) isPolicyEnforcedByAdvancedProtection(Context context, String identifier, int userId)867 public static boolean isPolicyEnforcedByAdvancedProtection(Context context, String identifier, 868 int userId) { 869 if (!android.security.Flags.aapmApi()) return false; 870 if (identifier == null) return false; 871 EnforcingAdmin admin = context.getSystemService(DevicePolicyManager.class) 872 .getEnforcingAdmin(userId, identifier); 873 if (admin == null) return false; 874 return admin.getAuthority() instanceof UnknownAuthority authority 875 && AdvancedProtectionManager.ADVANCED_PROTECTION_SYSTEM_ENTITY.equals( 876 authority.getName()); 877 } 878 879 /** 880 * Check if there are restrictions on an application from being a Credential Manager provider. 881 * 882 * @return EnforcedAdmin Object containing the enforced admin component and admin user details, 883 * or {@code null} if the setting is not managed. 884 */ checkIfApplicationCanBeCredentialManagerProvider( @onNull Context context, @NonNull String packageName)885 public static @Nullable EnforcedAdmin checkIfApplicationCanBeCredentialManagerProvider( 886 @NonNull Context context, @NonNull String packageName) { 887 final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class); 888 final PackagePolicy pp = dpm.getCredentialManagerPolicy(); 889 890 if (pp == null || pp.isPackageAllowed(packageName, new HashSet<>())) { 891 return null; 892 } 893 894 EnforcedAdmin admin = RestrictedLockUtilsInternal.getDeviceOwner(context); 895 if (admin != null) { 896 return admin; 897 } 898 int profileId = getManagedProfileId(context, context.getUserId()); 899 return RestrictedLockUtils.getProfileOrDeviceOwner(context, UserHandle.of(profileId)); 900 } 901 902 /** 903 * Static {@link LockPatternUtils} and {@link DevicePolicyManager} wrapper for testing purposes. 904 * {@link LockPatternUtils} is an internal API not supported by robolectric. 905 * {@link DevicePolicyManager} has a {@code getProfileParent} not yet suppored by robolectric. 906 */ 907 @VisibleForTesting 908 static Proxy sProxy = new Proxy(); 909 910 @VisibleForTesting 911 static class Proxy { isSeparateProfileChallengeEnabled(LockPatternUtils utils, int userHandle)912 public boolean isSeparateProfileChallengeEnabled(LockPatternUtils utils, int userHandle) { 913 return utils.isSeparateProfileChallengeEnabled(userHandle); 914 } 915 getParentProfileInstance(DevicePolicyManager dpm, UserInfo ui)916 public DevicePolicyManager getParentProfileInstance(DevicePolicyManager dpm, UserInfo ui) { 917 return dpm.getParentProfileInstance(ui); 918 } 919 } 920 } 921