1 /* 2 * Copyright (C) 2018 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.role.controller.model; 18 19 import android.app.ActivityManager; 20 import android.app.admin.DevicePolicyManager; 21 import android.app.ecm.EnhancedConfirmationManager; 22 import android.app.role.RoleManager; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.pm.ApplicationInfo; 27 import android.content.pm.PackageManager; 28 import android.content.pm.SharedLibraryInfo; 29 import android.content.pm.Signature; 30 import android.content.res.Resources; 31 import android.os.Build; 32 import android.os.UserHandle; 33 import android.os.UserManager; 34 import android.permission.flags.Flags; 35 import android.provider.Settings; 36 import android.text.TextUtils; 37 import android.util.ArrayMap; 38 import android.util.ArraySet; 39 import android.util.Log; 40 41 import androidx.annotation.NonNull; 42 import androidx.annotation.Nullable; 43 import androidx.annotation.StringRes; 44 45 import com.android.modules.utils.build.SdkLevel; 46 import com.android.role.controller.util.CollectionUtils; 47 import com.android.role.controller.util.PackageUtils; 48 import com.android.role.controller.util.RoleManagerCompat; 49 import com.android.role.controller.util.UserUtils; 50 51 import java.util.ArrayList; 52 import java.util.Collections; 53 import java.util.List; 54 import java.util.Objects; 55 56 /** 57 * Specifies a role and its properties. 58 * <p> 59 * A role is a unique name within the system associated with certain privileges. There can be 60 * multiple applications qualifying for a role, but only a subset of them can become role holders. 61 * To qualify for a role, an application must meet certain requirements, including defining certain 62 * components in its manifest. Then the application will need user consent to become the role 63 * holder. 64 * <p> 65 * Upon becoming a role holder, the application may be granted certain permissions, have certain 66 * app ops set to certain modes and certain {@code Activity} components configured as preferred for 67 * certain {@code Intent} actions. When an application loses its role, these privileges will also be 68 * revoked. 69 * 70 * @see android.app.role.RoleManager 71 */ 72 public class Role { 73 74 private static final String LOG_TAG = Role.class.getSimpleName(); 75 76 private static final boolean DEBUG = false; 77 78 private static final String PACKAGE_NAME_ANDROID_SYSTEM = "android"; 79 80 private static final String DEFAULT_HOLDER_SEPARATOR = ";"; 81 82 private static final String CERTIFICATE_SEPARATOR = ":"; 83 84 /** 85 * The name of this role. Must be unique. 86 */ 87 @NonNull 88 private final String mName; 89 90 /** 91 * Whether this role allows bypassing role holder qualification. 92 */ 93 private final boolean mAllowBypassingQualification; 94 95 /** 96 * The behavior of this role. 97 */ 98 @Nullable 99 private final RoleBehavior mBehavior; 100 101 @Nullable 102 private final String mDefaultHoldersResourceName; 103 104 /** 105 * The string resource for the description of this role. 106 */ 107 @StringRes 108 private final int mDescriptionResource; 109 110 /** 111 * Whether this role is exclusive, i.e. allows at most one holder. 112 */ 113 private final boolean mExclusive; 114 115 /** 116 * Whether this role should fall back to the default holder. 117 */ 118 private final boolean mFallBackToDefaultHolder; 119 120 /** 121 * The string resource for the label of this role. 122 */ 123 @StringRes 124 private final int mLabelResource; 125 126 /** 127 * The maximum SDK version for this role to be available. 128 */ 129 private final int mMaxSdkVersion; 130 131 /** 132 * The minimum SDK version for this role to be available. 133 */ 134 private final int mMinSdkVersion; 135 136 /** 137 * Whether this role should only grant privileges when a role holder is actively added. 138 */ 139 private final boolean mOnlyGrantWhenAdded; 140 141 /** 142 * Whether this role should override user's choice about privileges when granting. 143 */ 144 private final boolean mOverrideUserWhenGranting; 145 146 /** 147 * The string resource for the request description of this role, shown below the selected app in 148 * the request role dialog. 149 */ 150 @StringRes 151 private final int mRequestDescriptionResource; 152 153 /** 154 * The string resource for the request title of this role, shown as the title of the request 155 * role dialog. 156 */ 157 @StringRes 158 private final int mRequestTitleResource; 159 160 /** 161 * Whether this role is requestable by applications with 162 * {@link android.app.role.RoleManager#createRequestRoleIntent(String)}. 163 */ 164 private final boolean mRequestable; 165 166 /** 167 * The string resource for search keywords of this role, in addition to the label of this role, 168 * if it's non-zero. 169 */ 170 @StringRes 171 private final int mSearchKeywordsResource; 172 173 /** 174 * The string resource for the short label of this role, currently used when in a list of roles. 175 */ 176 @StringRes 177 private final int mShortLabelResource; 178 179 /** 180 * Whether the UI for this role will show the "None" item. Only valid if this role is 181 * {@link #mExclusive exclusive}, and {@link #getFallbackHolder(Context)} should also return 182 * empty to allow actually selecting "None". 183 */ 184 private final boolean mShowNone; 185 186 /** 187 * Whether this role is static, i.e. the role will always be assigned to its default holders. 188 */ 189 private final boolean mStatic; 190 191 /** 192 * Whether this role only accepts system apps as its holders. 193 */ 194 private final boolean mSystemOnly; 195 196 /** 197 * Whether this role is visible to user. 198 */ 199 private final boolean mVisible; 200 201 /** 202 * The required components for an application to qualify for this role. 203 */ 204 @NonNull 205 private final List<RequiredComponent> mRequiredComponents; 206 207 /** 208 * The permissions to be granted by this role. 209 */ 210 @NonNull 211 private final List<Permission> mPermissions; 212 213 /** 214 * The app op permissions to be granted by this role. 215 */ 216 @NonNull 217 private final List<Permission> mAppOpPermissions; 218 219 /** 220 * The app ops to be set to allowed by this role. 221 */ 222 @NonNull 223 private final List<AppOp> mAppOps; 224 225 /** 226 * The set of preferred {@code Activity} configurations to be configured by this role. 227 */ 228 @NonNull 229 private final List<PreferredActivity> mPreferredActivities; 230 231 @Nullable 232 private final String mUiBehaviorName; 233 Role(@onNull String name, boolean allowBypassingQualification, @Nullable RoleBehavior behavior, @Nullable String defaultHoldersResourceName, @StringRes int descriptionResource, boolean exclusive, boolean fallBackToDefaultHolder, @StringRes int labelResource, int maxSdkVersion, int minSdkVersion, boolean onlyGrantWhenAdded, boolean overrideUserWhenGranting, @StringRes int requestDescriptionResource, @StringRes int requestTitleResource, boolean requestable, @StringRes int searchKeywordsResource, @StringRes int shortLabelResource, boolean showNone, boolean statik, boolean systemOnly, boolean visible, @NonNull List<RequiredComponent> requiredComponents, @NonNull List<Permission> permissions, @NonNull List<Permission> appOpPermissions, @NonNull List<AppOp> appOps, @NonNull List<PreferredActivity> preferredActivities, @Nullable String uiBehaviorName)234 public Role(@NonNull String name, boolean allowBypassingQualification, 235 @Nullable RoleBehavior behavior, @Nullable String defaultHoldersResourceName, 236 @StringRes int descriptionResource, boolean exclusive, boolean fallBackToDefaultHolder, 237 @StringRes int labelResource, int maxSdkVersion, int minSdkVersion, 238 boolean onlyGrantWhenAdded, boolean overrideUserWhenGranting, 239 @StringRes int requestDescriptionResource, @StringRes int requestTitleResource, 240 boolean requestable, @StringRes int searchKeywordsResource, 241 @StringRes int shortLabelResource, boolean showNone, boolean statik, boolean systemOnly, 242 boolean visible, @NonNull List<RequiredComponent> requiredComponents, 243 @NonNull List<Permission> permissions, @NonNull List<Permission> appOpPermissions, 244 @NonNull List<AppOp> appOps, @NonNull List<PreferredActivity> preferredActivities, 245 @Nullable String uiBehaviorName) { 246 mName = name; 247 mAllowBypassingQualification = allowBypassingQualification; 248 mBehavior = behavior; 249 mDefaultHoldersResourceName = defaultHoldersResourceName; 250 mDescriptionResource = descriptionResource; 251 mExclusive = exclusive; 252 mFallBackToDefaultHolder = fallBackToDefaultHolder; 253 mLabelResource = labelResource; 254 mMaxSdkVersion = maxSdkVersion; 255 mMinSdkVersion = minSdkVersion; 256 mOnlyGrantWhenAdded = onlyGrantWhenAdded; 257 mOverrideUserWhenGranting = overrideUserWhenGranting; 258 mRequestDescriptionResource = requestDescriptionResource; 259 mRequestTitleResource = requestTitleResource; 260 mRequestable = requestable; 261 mSearchKeywordsResource = searchKeywordsResource; 262 mShortLabelResource = shortLabelResource; 263 mShowNone = showNone; 264 mStatic = statik; 265 mSystemOnly = systemOnly; 266 mVisible = visible; 267 mRequiredComponents = requiredComponents; 268 mPermissions = permissions; 269 mAppOpPermissions = appOpPermissions; 270 mAppOps = appOps; 271 mPreferredActivities = preferredActivities; 272 mUiBehaviorName = uiBehaviorName; 273 } 274 275 @NonNull getName()276 public String getName() { 277 return mName; 278 } 279 280 @Nullable getBehavior()281 public RoleBehavior getBehavior() { 282 return mBehavior; 283 } 284 285 @StringRes getDescriptionResource()286 public int getDescriptionResource() { 287 return mDescriptionResource; 288 } 289 isExclusive()290 public boolean isExclusive() { 291 return mExclusive; 292 } 293 294 @StringRes getLabelResource()295 public int getLabelResource() { 296 return mLabelResource; 297 } 298 299 @StringRes getRequestDescriptionResource()300 public int getRequestDescriptionResource() { 301 return mRequestDescriptionResource; 302 } 303 304 @StringRes getRequestTitleResource()305 public int getRequestTitleResource() { 306 return mRequestTitleResource; 307 } 308 isRequestable()309 public boolean isRequestable() { 310 return mRequestable; 311 } 312 313 @StringRes getSearchKeywordsResource()314 public int getSearchKeywordsResource() { 315 return mSearchKeywordsResource; 316 } 317 318 @StringRes getShortLabelResource()319 public int getShortLabelResource() { 320 return mShortLabelResource; 321 } 322 323 /** 324 * @see #mOnlyGrantWhenAdded 325 */ shouldOnlyGrantWhenAdded()326 public boolean shouldOnlyGrantWhenAdded() { 327 return mOnlyGrantWhenAdded; 328 } 329 330 /** 331 * @see #mOverrideUserWhenGranting 332 */ shouldOverrideUserWhenGranting()333 public boolean shouldOverrideUserWhenGranting() { 334 return mOverrideUserWhenGranting; 335 } 336 337 /** 338 * @see #mShowNone 339 */ shouldShowNone()340 public boolean shouldShowNone() { 341 return mShowNone; 342 } 343 isVisible()344 public boolean isVisible() { 345 return mVisible; 346 } 347 348 @NonNull getRequiredComponents()349 public List<RequiredComponent> getRequiredComponents() { 350 return mRequiredComponents; 351 } 352 353 @NonNull getPermissions()354 public List<Permission> getPermissions() { 355 return mPermissions; 356 } 357 358 @NonNull getAppOpPermissions()359 public List<Permission> getAppOpPermissions() { 360 return mAppOpPermissions; 361 } 362 363 @NonNull getAppOps()364 public List<AppOp> getAppOps() { 365 return mAppOps; 366 } 367 368 @NonNull getPreferredActivities()369 public List<PreferredActivity> getPreferredActivities() { 370 return mPreferredActivities; 371 } 372 373 @Nullable getUiBehaviorName()374 public String getUiBehaviorName() { 375 return mUiBehaviorName; 376 } 377 378 /** 379 * Callback when this role is added to the system for the first time. 380 * 381 * @param user the user to add the role for 382 * @param context the {@code Context} to retrieve system services 383 */ onRoleAddedAsUser(@onNull UserHandle user, @NonNull Context context)384 public void onRoleAddedAsUser(@NonNull UserHandle user, @NonNull Context context) { 385 if (mBehavior != null) { 386 mBehavior.onRoleAddedAsUser(this, user, context); 387 } 388 } 389 390 /** 391 * Check whether this role is available. 392 * 393 * @param user the user to check for 394 * @param context the {@code Context} to retrieve system services 395 * 396 * @return whether this role is available. 397 */ isAvailableAsUser(@onNull UserHandle user, @NonNull Context context)398 public boolean isAvailableAsUser(@NonNull UserHandle user, @NonNull Context context) { 399 if (!isAvailableBySdkVersion()) { 400 return false; 401 } 402 if (mBehavior != null) { 403 return mBehavior.isAvailableAsUser(this, user, context); 404 } 405 return true; 406 } 407 408 /** 409 * Check whether this role is available based on SDK version. 410 * 411 * @return whether this role is available based on SDK version 412 */ isAvailableBySdkVersion()413 boolean isAvailableBySdkVersion() { 414 return (Build.VERSION.SDK_INT >= mMinSdkVersion 415 // Workaround to match the value 35 for V in roles.xml before SDK finalization. 416 || (mMinSdkVersion == 35 && SdkLevel.isAtLeastV())) 417 && Build.VERSION.SDK_INT <= mMaxSdkVersion; 418 } 419 isStatic()420 public boolean isStatic() { 421 return mStatic; 422 } 423 424 /** 425 * Get the default holders of this role, which will be added when the role is added for the 426 * first time. 427 * 428 * @param user the user of the role 429 * @param context the {@code Context} to retrieve system services 430 * @return the list of package names of the default holders 431 */ 432 @NonNull getDefaultHoldersAsUser(@onNull UserHandle user, @NonNull Context context)433 public List<String> getDefaultHoldersAsUser(@NonNull UserHandle user, 434 @NonNull Context context) { 435 if (mBehavior != null) { 436 List<String> defaultHolders = mBehavior.getDefaultHoldersAsUser(this, user, context); 437 if (defaultHolders != null) { 438 return defaultHolders; 439 } 440 } 441 442 if (mDefaultHoldersResourceName == null) { 443 return Collections.emptyList(); 444 } 445 446 Resources resources = context.getResources(); 447 int resourceId = resources.getIdentifier(mDefaultHoldersResourceName, "string", "android"); 448 if (resourceId == 0) { 449 Log.w(LOG_TAG, "Cannot find resource for default holder: " 450 + mDefaultHoldersResourceName); 451 return Collections.emptyList(); 452 } 453 454 String defaultHolders; 455 try { 456 defaultHolders = resources.getString(resourceId); 457 } catch (Resources.NotFoundException e) { 458 Log.w(LOG_TAG, "Cannot get resource for default holder: " + mDefaultHoldersResourceName, 459 e); 460 return Collections.emptyList(); 461 } 462 if (TextUtils.isEmpty(defaultHolders)) { 463 return Collections.emptyList(); 464 } 465 466 if (isExclusive()) { 467 String packageName = getQualifiedDefaultHolderPackageNameAsUser(defaultHolders, user, 468 context); 469 if (packageName == null) { 470 return Collections.emptyList(); 471 } 472 return Collections.singletonList(packageName); 473 } else { 474 List<String> packageNames = new ArrayList<>(); 475 for (String defaultHolder : defaultHolders.split(DEFAULT_HOLDER_SEPARATOR)) { 476 String packageName = getQualifiedDefaultHolderPackageNameAsUser(defaultHolder, 477 user, context); 478 if (packageName != null) { 479 packageNames.add(packageName); 480 } 481 } 482 return packageNames; 483 } 484 } 485 486 @Nullable getQualifiedDefaultHolderPackageNameAsUser(@onNull String defaultHolder, @NonNull UserHandle user, @NonNull Context context)487 private String getQualifiedDefaultHolderPackageNameAsUser(@NonNull String defaultHolder, 488 @NonNull UserHandle user, @NonNull Context context) { 489 String packageName; 490 byte[] certificate; 491 int certificateSeparatorIndex = defaultHolder.indexOf(CERTIFICATE_SEPARATOR); 492 if (certificateSeparatorIndex != -1) { 493 packageName = defaultHolder.substring(0, certificateSeparatorIndex); 494 String certificateString = defaultHolder.substring(certificateSeparatorIndex + 1); 495 try { 496 certificate = new Signature(certificateString).toByteArray(); 497 } catch (IllegalArgumentException e) { 498 Log.w(LOG_TAG, "Cannot parse signing certificate: " + defaultHolder, e); 499 return null; 500 } 501 } else { 502 packageName = defaultHolder; 503 certificate = null; 504 } 505 506 if (certificate != null) { 507 Context userContext = UserUtils.getUserContext(context, user); 508 PackageManager userPackageManager = userContext.getPackageManager(); 509 if (!userPackageManager.hasSigningCertificate(packageName, certificate, 510 PackageManager.CERT_INPUT_SHA256)) { 511 Log.w(LOG_TAG, "Default holder doesn't have required signing certificate: " 512 + defaultHolder); 513 return null; 514 } 515 } else { 516 ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, 517 user, context); 518 if (applicationInfo == null) { 519 Log.w(LOG_TAG, "Cannot get ApplicationInfo for default holder: " + packageName); 520 return null; 521 } 522 if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { 523 Log.w(LOG_TAG, "Default holder didn't specify a signing certificate and isn't a" 524 + " system app: " + packageName); 525 return null; 526 } 527 } 528 529 return packageName; 530 } 531 532 /** 533 * Get the fallback holder of this role, which will be added whenever there are no role holders. 534 * <p> 535 * Should return {@code null} if this role {@link #mShowNone shows a "None" item}. 536 * 537 * @param user the user of the role 538 * @param context the {@code Context} to retrieve system services 539 * @return the package name of the fallback holder, or {@code null} if none 540 */ 541 @Nullable getFallbackHolderAsUser(@onNull UserHandle user, @NonNull Context context)542 public String getFallbackHolderAsUser(@NonNull UserHandle user, @NonNull Context context) { 543 if (!RoleManagerCompat.isRoleFallbackEnabledAsUser(this, user, context)) { 544 return null; 545 } 546 if (mFallBackToDefaultHolder) { 547 return CollectionUtils.firstOrNull(getDefaultHoldersAsUser(user, context)); 548 } 549 if (mBehavior != null) { 550 return mBehavior.getFallbackHolderAsUser(this, user, context); 551 } 552 return null; 553 } 554 555 /** 556 * Check whether this role is allowed to bypass qualification, if enabled globally. 557 * 558 * @param context the {@code Context} to retrieve system services 559 * 560 * @return whether this role is allowed to bypass qualification 561 */ shouldAllowBypassingQualification(@onNull Context context)562 public boolean shouldAllowBypassingQualification(@NonNull Context context) { 563 if (mBehavior != null) { 564 Boolean allowBypassingQualification = mBehavior.shouldAllowBypassingQualification(this, 565 context); 566 if (allowBypassingQualification != null) { 567 return allowBypassingQualification; 568 } 569 } 570 return mAllowBypassingQualification; 571 } 572 573 /** 574 * Check whether a package is qualified for this role, i.e. whether it contains all the required 575 * components (plus meeting some other general restrictions). 576 * 577 * @param packageName the package name to check for 578 * @param user the user to check for 579 * @param context the {@code Context} to retrieve system services 580 * 581 * @return whether the package is qualified for a role 582 */ isPackageQualifiedAsUser(@onNull String packageName, @NonNull UserHandle user, @NonNull Context context)583 public boolean isPackageQualifiedAsUser(@NonNull String packageName, @NonNull UserHandle user, 584 @NonNull Context context) { 585 RoleManager roleManager = context.getSystemService(RoleManager.class); 586 if (shouldAllowBypassingQualification(context) 587 && RoleManagerCompat.isBypassingRoleQualification(roleManager)) { 588 return true; 589 } 590 591 ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, user, 592 context); 593 if (applicationInfo == null) { 594 Log.w(LOG_TAG, "Cannot get ApplicationInfo for package: " + packageName); 595 return false; 596 } 597 if (!isPackageMinimallyQualifiedAsUser(applicationInfo, user, context)) { 598 return false; 599 } 600 601 if (mBehavior != null) { 602 Boolean isPackageQualified = mBehavior.isPackageQualifiedAsUser(this, packageName, 603 user, context); 604 if (isPackageQualified != null) { 605 return isPackageQualified; 606 } 607 } 608 609 int requiredComponentsSize = mRequiredComponents.size(); 610 for (int i = 0; i < requiredComponentsSize; i++) { 611 RequiredComponent requiredComponent = mRequiredComponents.get(i); 612 613 if (!requiredComponent.isRequired(applicationInfo)) { 614 continue; 615 } 616 617 if (requiredComponent.getQualifyingComponentForPackageAsUser(packageName, user, context) 618 == null) { 619 Log.i(LOG_TAG, packageName + " not qualified for " + mName 620 + " due to missing " + requiredComponent); 621 return false; 622 } 623 } 624 625 if (mStatic && !getDefaultHoldersAsUser(user, context).contains(packageName)) { 626 return false; 627 } 628 629 return true; 630 } 631 632 /** 633 * Get the list of packages that are qualified for this role, i.e. packages containing all the 634 * required components (plus meeting some other general restrictions). 635 * 636 * @param user the user to get the qualifying packages. 637 * @param context the {@code Context} to retrieve system services 638 * 639 * @return the list of packages that are qualified for this role 640 */ 641 @NonNull getQualifyingPackagesAsUser(@onNull UserHandle user, @NonNull Context context)642 public List<String> getQualifyingPackagesAsUser(@NonNull UserHandle user, 643 @NonNull Context context) { 644 List<String> qualifyingPackages = null; 645 646 if (mBehavior != null) { 647 qualifyingPackages = mBehavior.getQualifyingPackagesAsUser(this, user, context); 648 } 649 650 ArrayMap<String, ApplicationInfo> packageApplicationInfoMap = new ArrayMap<>(); 651 if (qualifyingPackages == null) { 652 ArrayMap<String, ArraySet<RequiredComponent>> packageRequiredComponentsMap = 653 new ArrayMap<>(); 654 int requiredComponentsSize = mRequiredComponents.size(); 655 for (int requiredComponentsIndex = 0; requiredComponentsIndex < requiredComponentsSize; 656 requiredComponentsIndex++) { 657 RequiredComponent requiredComponent = mRequiredComponents.get( 658 requiredComponentsIndex); 659 660 if (!requiredComponent.isAvailable()) { 661 continue; 662 } 663 664 // This returns at most one component per package. 665 List<ComponentName> qualifyingComponents = 666 requiredComponent.getQualifyingComponentsAsUser(user, context); 667 int qualifyingComponentsSize = qualifyingComponents.size(); 668 for (int qualifyingComponentsIndex = 0; 669 qualifyingComponentsIndex < qualifyingComponentsSize; 670 ++qualifyingComponentsIndex) { 671 ComponentName componentName = qualifyingComponents.get( 672 qualifyingComponentsIndex); 673 674 String packageName = componentName.getPackageName(); 675 ArraySet<RequiredComponent> packageRequiredComponents = 676 packageRequiredComponentsMap.get(packageName); 677 if (packageRequiredComponents == null) { 678 packageRequiredComponents = new ArraySet<>(); 679 packageRequiredComponentsMap.put(packageName, packageRequiredComponents); 680 } 681 packageRequiredComponents.add(requiredComponent); 682 } 683 } 684 685 qualifyingPackages = new ArrayList<>(); 686 int packageRequiredComponentsMapSize = packageRequiredComponentsMap.size(); 687 for (int packageRequiredComponentsMapIndex = 0; 688 packageRequiredComponentsMapIndex < packageRequiredComponentsMapSize; 689 packageRequiredComponentsMapIndex++) { 690 String packageName = packageRequiredComponentsMap.keyAt( 691 packageRequiredComponentsMapIndex); 692 ArraySet<RequiredComponent> packageRequiredComponents = 693 packageRequiredComponentsMap.valueAt(packageRequiredComponentsMapIndex); 694 695 ApplicationInfo applicationInfo = packageApplicationInfoMap.get(packageName); 696 if (applicationInfo == null) { 697 applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, user, 698 context); 699 if (applicationInfo == null) { 700 Log.w(LOG_TAG, "Cannot get ApplicationInfo for package: " + packageName 701 + ", user: " + user.getIdentifier()); 702 continue; 703 } 704 packageApplicationInfoMap.put(packageName, applicationInfo); 705 } 706 707 boolean hasAllRequiredComponents = true; 708 for (int requiredComponentsIndex = 0; 709 requiredComponentsIndex < requiredComponentsSize; 710 requiredComponentsIndex++) { 711 RequiredComponent requiredComponent = mRequiredComponents.get( 712 requiredComponentsIndex); 713 714 if (!requiredComponent.isRequired(applicationInfo)) { 715 continue; 716 } 717 718 if (!packageRequiredComponents.contains(requiredComponent)) { 719 hasAllRequiredComponents = false; 720 break; 721 } 722 } 723 724 if (hasAllRequiredComponents) { 725 qualifyingPackages.add(packageName); 726 } 727 } 728 } 729 730 int qualifyingPackagesSize = qualifyingPackages.size(); 731 for (int i = 0; i < qualifyingPackagesSize; ) { 732 String packageName = qualifyingPackages.get(i); 733 734 ApplicationInfo applicationInfo = packageApplicationInfoMap.get(packageName); 735 if (applicationInfo == null) { 736 applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, user, 737 context); 738 if (applicationInfo == null) { 739 Log.w(LOG_TAG, "Cannot get ApplicationInfo for package: " + packageName 740 + ", user: " + user.getIdentifier()); 741 continue; 742 } 743 packageApplicationInfoMap.put(packageName, applicationInfo); 744 } 745 746 if (!isPackageMinimallyQualifiedAsUser(applicationInfo, user, context)) { 747 qualifyingPackages.remove(i); 748 qualifyingPackagesSize--; 749 } else { 750 i++; 751 } 752 } 753 754 return qualifyingPackages; 755 } 756 isPackageMinimallyQualifiedAsUser(@onNull ApplicationInfo applicationInfo, @NonNull UserHandle user, @NonNull Context context)757 private boolean isPackageMinimallyQualifiedAsUser(@NonNull ApplicationInfo applicationInfo, 758 @NonNull UserHandle user, 759 @NonNull Context context) { 760 String packageName = applicationInfo.packageName; 761 if (Objects.equals(packageName, PACKAGE_NAME_ANDROID_SYSTEM)) { 762 return false; 763 } 764 765 if (mSystemOnly && (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { 766 return false; 767 } 768 769 if (!applicationInfo.enabled) { 770 return false; 771 } 772 773 if (applicationInfo.isInstantApp()) { 774 return false; 775 } 776 777 PackageManager userPackageManager = UserUtils.getUserContext(context, user) 778 .getPackageManager(); 779 List<SharedLibraryInfo> declaredLibraries = userPackageManager.getDeclaredSharedLibraries( 780 packageName, 0); 781 final int libCount = declaredLibraries.size(); 782 for (int i = 0; i < libCount; i++) { 783 SharedLibraryInfo sharedLibrary = declaredLibraries.get(i); 784 if (sharedLibrary.getType() != SharedLibraryInfo.TYPE_DYNAMIC) { 785 return false; 786 } 787 } 788 789 return true; 790 } 791 792 /** 793 * Grant this role to an application. 794 * 795 * @param packageName the package name of the application to be granted this role to 796 * @param dontKillApp whether this application should not be killed despite changes 797 * @param overrideUser whether to override user when granting privileges 798 * @param user the user of the application 799 * @param context the {@code Context} to retrieve system services 800 */ grantAsUser(@onNull String packageName, boolean dontKillApp, boolean overrideUser, @NonNull UserHandle user, @NonNull Context context)801 public void grantAsUser(@NonNull String packageName, boolean dontKillApp, 802 boolean overrideUser, @NonNull UserHandle user, @NonNull Context context) { 803 boolean permissionOrAppOpChanged = Permissions.grantAsUser(packageName, 804 Permissions.filterBySdkVersionAsUser(mPermissions, user, context), 805 SdkLevel.isAtLeastS() ? !mSystemOnly : true, overrideUser, true, false, false, 806 user, context); 807 808 List<String> appOpPermissionsToGrant = 809 Permissions.filterBySdkVersionAsUser(mAppOpPermissions, user, context); 810 int appOpPermissionsSize = appOpPermissionsToGrant.size(); 811 for (int i = 0; i < appOpPermissionsSize; i++) { 812 String appOpPermission = appOpPermissionsToGrant.get(i); 813 AppOpPermissions.grantAsUser(packageName, appOpPermission, overrideUser, user, context); 814 } 815 816 int appOpsSize = mAppOps.size(); 817 for (int i = 0; i < appOpsSize; i++) { 818 AppOp appOp = mAppOps.get(i); 819 appOp.grantAsUser(packageName, user, context); 820 } 821 822 int preferredActivitiesSize = mPreferredActivities.size(); 823 for (int i = 0; i < preferredActivitiesSize; i++) { 824 PreferredActivity preferredActivity = mPreferredActivities.get(i); 825 preferredActivity.configureAsUser(packageName, user, context); 826 } 827 828 if (mBehavior != null) { 829 mBehavior.grantAsUser(this, packageName, user, context); 830 } 831 832 if (!dontKillApp && permissionOrAppOpChanged 833 && !Permissions.isRuntimePermissionsSupportedAsUser(packageName, user, context)) { 834 killAppAsUser(packageName, user, context); 835 } 836 } 837 838 /** 839 * Revoke this role from an application. 840 * 841 * @param packageName the package name of the application to be granted this role to 842 * @param dontKillApp whether this application should not be killed despite changes 843 * @param overrideSystemFixedPermissions whether system-fixed permissions can be revoked 844 * @param user the user of the role 845 * @param context the {@code Context} to retrieve system services 846 */ revokeAsUser(@onNull String packageName, boolean dontKillApp, boolean overrideSystemFixedPermissions, @NonNull UserHandle user, @NonNull Context context)847 public void revokeAsUser(@NonNull String packageName, boolean dontKillApp, 848 boolean overrideSystemFixedPermissions, @NonNull UserHandle user, 849 @NonNull Context context) { 850 Context userContext = UserUtils.getUserContext(context, user); 851 RoleManager userRoleManager = userContext.getSystemService(RoleManager.class); 852 List<String> otherRoleNames = userRoleManager.getHeldRolesFromController(packageName); 853 otherRoleNames.remove(mName); 854 855 List<String> permissionsToRevoke = 856 Permissions.filterBySdkVersionAsUser(mPermissions, user, context); 857 ArrayMap<String, Role> roles = Roles.get(context); 858 int otherRoleNamesSize = otherRoleNames.size(); 859 for (int i = 0; i < otherRoleNamesSize; i++) { 860 String roleName = otherRoleNames.get(i); 861 Role role = roles.get(roleName); 862 permissionsToRevoke.removeAll( 863 Permissions.filterBySdkVersionAsUser(role.mPermissions, user, context)); 864 } 865 866 boolean permissionOrAppOpChanged = Permissions.revokeAsUser(packageName, 867 permissionsToRevoke, true, false, overrideSystemFixedPermissions, user, context); 868 869 List<String> appOpPermissionsToRevoke = Permissions.filterBySdkVersionAsUser( 870 mAppOpPermissions, user, context); 871 for (int i = 0; i < otherRoleNamesSize; i++) { 872 String roleName = otherRoleNames.get(i); 873 Role role = roles.get(roleName); 874 appOpPermissionsToRevoke.removeAll( 875 Permissions.filterBySdkVersionAsUser(role.mAppOpPermissions, user, context)); 876 } 877 int appOpPermissionsSize = appOpPermissionsToRevoke.size(); 878 for (int i = 0; i < appOpPermissionsSize; i++) { 879 String appOpPermission = appOpPermissionsToRevoke.get(i); 880 AppOpPermissions.revokeAsUser(packageName, appOpPermission, user, context); 881 } 882 883 List<AppOp> appOpsToRevoke = new ArrayList<>(mAppOps); 884 for (int i = 0; i < otherRoleNamesSize; i++) { 885 String roleName = otherRoleNames.get(i); 886 Role role = roles.get(roleName); 887 appOpsToRevoke.removeAll(role.mAppOps); 888 } 889 int appOpsSize = appOpsToRevoke.size(); 890 for (int i = 0; i < appOpsSize; i++) { 891 AppOp appOp = appOpsToRevoke.get(i); 892 appOp.revokeAsUser(packageName, user, context); 893 } 894 895 // TODO: Revoke preferred activities? But this is unnecessary for most roles using it as 896 // they have fallback holders. Moreover, clearing the preferred activity might result in 897 // other system components listening to preferred activity change get notified for the 898 // wrong thing when we are removing a exclusive role holder for adding another. 899 900 if (mBehavior != null) { 901 mBehavior.revokeAsUser(this, packageName, user, context); 902 } 903 904 if (!dontKillApp && permissionOrAppOpChanged) { 905 killAppAsUser(packageName, user, context); 906 } 907 } 908 killAppAsUser(@onNull String packageName, @NonNull UserHandle user, @NonNull Context context)909 private void killAppAsUser(@NonNull String packageName, @NonNull UserHandle user, 910 @NonNull Context context) { 911 if (DEBUG) { 912 Log.i(LOG_TAG, "Killing " + packageName + " due to " 913 + Thread.currentThread().getStackTrace()[3].getMethodName() 914 + "(" + mName + ")"); 915 } 916 ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, user, 917 context); 918 if (applicationInfo == null) { 919 Log.w(LOG_TAG, "Cannot get ApplicationInfo for package: " + packageName); 920 return; 921 } 922 ActivityManager activityManager = context.getSystemService(ActivityManager.class); 923 activityManager.killUid(applicationInfo.uid, "Permission or app op changed"); 924 } 925 926 /** 927 * Callback when a role holder (other than "none") was added. 928 * 929 * @param packageName the package name of the role holder 930 * @param user the user for the role 931 * @param context the {@code Context} to retrieve system services 932 */ onHolderAddedAsUser(@onNull String packageName, @NonNull UserHandle user, @NonNull Context context)933 public void onHolderAddedAsUser(@NonNull String packageName, @NonNull UserHandle user, 934 @NonNull Context context) { 935 RoleManagerCompat.setRoleFallbackEnabledAsUser(this, true, user, context); 936 } 937 938 /** 939 * Callback when a role holder (other than "none") was selected in the UI and added 940 * successfully. 941 * 942 * @param packageName the package name of the role holder 943 * @param user the user for the role 944 * @param context the {@code Context} to retrieve system services 945 */ onHolderSelectedAsUser(@onNull String packageName, @NonNull UserHandle user, @NonNull Context context)946 public void onHolderSelectedAsUser(@NonNull String packageName, @NonNull UserHandle user, 947 @NonNull Context context) { 948 if (mBehavior != null) { 949 mBehavior.onHolderSelectedAsUser(this, packageName, user, context); 950 } 951 } 952 953 /** 954 * Callback when a role holder changed. 955 * 956 * @param user the user for the role 957 * @param context the {@code Context} to retrieve system services 958 */ onHolderChangedAsUser(@onNull UserHandle user, @NonNull Context context)959 public void onHolderChangedAsUser(@NonNull UserHandle user, 960 @NonNull Context context) { 961 if (mBehavior != null) { 962 mBehavior.onHolderChangedAsUser(this, user, context); 963 } 964 } 965 966 /** 967 * Callback when the "none" role holder was selected in the UI. 968 * 969 * @param user the user for the role 970 * @param context the {@code Context} to retrieve system services 971 */ onNoneHolderSelectedAsUser(@onNull UserHandle user, @NonNull Context context)972 public void onNoneHolderSelectedAsUser(@NonNull UserHandle user, @NonNull Context context) { 973 RoleManagerCompat.setRoleFallbackEnabledAsUser(this, false, user, context); 974 } 975 976 /** 977 * Check whether this role should be visible to user. 978 * 979 * @param user the user to check for 980 * @param context the {@code Context} to retrieve system services 981 * 982 * @return whether this role should be visible to user 983 */ isVisibleAsUser(@onNull UserHandle user, @NonNull Context context)984 public boolean isVisibleAsUser(@NonNull UserHandle user, @NonNull Context context) { 985 RoleBehavior behavior = getBehavior(); 986 if (behavior == null) { 987 return isVisible(); 988 } 989 return isVisible() && behavior.isVisibleAsUser(this, user, context); 990 } 991 992 /** 993 * Check whether a qualifying application should be visible to user. 994 * 995 * @param applicationInfo the {@link ApplicationInfo} for the application 996 * @param user the user for the application 997 * @param context the {@code Context} to retrieve system services 998 * 999 * @return whether the qualifying application should be visible to user 1000 */ isApplicationVisibleAsUser(@onNull ApplicationInfo applicationInfo, @NonNull UserHandle user, @NonNull Context context)1001 public boolean isApplicationVisibleAsUser(@NonNull ApplicationInfo applicationInfo, 1002 @NonNull UserHandle user, @NonNull Context context) { 1003 RoleBehavior behavior = getBehavior(); 1004 if (behavior == null) { 1005 return true; 1006 } 1007 return behavior.isApplicationVisibleAsUser(this, applicationInfo, user, context); 1008 } 1009 1010 /** 1011 * Check whether this role is restricted and return the {@code Intent} for the restriction if it 1012 * is. 1013 * <p> 1014 * If a role is restricted, it is implied that all applications are restricted for the role as 1015 * well. 1016 * 1017 * @param user the user to check for 1018 * @param context the {@code Context} to retrieve system services 1019 * 1020 * @return the {@code Intent} for the restriction if this role is restricted, or {@code null} 1021 * otherwise. 1022 */ 1023 @Nullable getRestrictionIntentAsUser(@onNull UserHandle user, @NonNull Context context)1024 public Intent getRestrictionIntentAsUser(@NonNull UserHandle user, @NonNull Context context) { 1025 if (SdkLevel.isAtLeastU() && mExclusive) { 1026 UserManager userManager = context.getSystemService(UserManager.class); 1027 if (userManager.hasUserRestrictionForUser(UserManager.DISALLOW_CONFIG_DEFAULT_APPS, 1028 user)) { 1029 return new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS) 1030 .putExtra(DevicePolicyManager.EXTRA_RESTRICTION, 1031 UserManager.DISALLOW_CONFIG_DEFAULT_APPS); 1032 } 1033 } 1034 return null; 1035 } 1036 1037 /** 1038 * Check whether an application is restricted for this role and return the {@code Intent} for 1039 * the restriction if it is. 1040 * <p> 1041 * If a role is restricted, it is implied that all applications are restricted for the role as 1042 * well. 1043 * 1044 * @param applicationInfo the {@link ApplicationInfo} for the application 1045 * @param user the user to check for 1046 * @param context the {@code Context} to retrieve system services 1047 * 1048 * @return the {@code Intent} for the restriction if the application is restricted for this 1049 * role, or {@code null} otherwise. 1050 */ 1051 @Nullable getApplicationRestrictionIntentAsUser(@onNull ApplicationInfo applicationInfo, @NonNull UserHandle user, @NonNull Context context)1052 public Intent getApplicationRestrictionIntentAsUser(@NonNull ApplicationInfo applicationInfo, 1053 @NonNull UserHandle user, @NonNull Context context) { 1054 if (SdkLevel.isAtLeastV() && Flags.enhancedConfirmationModeApisEnabled()) { 1055 Context userContext = UserUtils.getUserContext(context, user); 1056 EnhancedConfirmationManager userEnhancedConfirmationManager = 1057 userContext.getSystemService(EnhancedConfirmationManager.class); 1058 String packageName = applicationInfo.packageName; 1059 boolean isRestricted; 1060 try { 1061 isRestricted = userEnhancedConfirmationManager.isRestricted(packageName, mName); 1062 } catch (PackageManager.NameNotFoundException e) { 1063 Log.w(LOG_TAG, "Cannot check enhanced confirmation restriction for package: " 1064 + packageName, e); 1065 isRestricted = false; 1066 } 1067 if (isRestricted) { 1068 try { 1069 return userEnhancedConfirmationManager.createRestrictedSettingDialogIntent( 1070 packageName, mName); 1071 } catch (PackageManager.NameNotFoundException e) { 1072 Log.w(LOG_TAG, "Cannot create enhanced confirmation restriction intent for" 1073 + " package: " + packageName, e); 1074 } 1075 } 1076 } 1077 return getRestrictionIntentAsUser(user, context); 1078 } 1079 1080 @Override toString()1081 public String toString() { 1082 return "Role{" 1083 + "mName='" + mName + '\'' 1084 + ", mAllowBypassingQualification=" + mAllowBypassingQualification 1085 + ", mBehavior=" + mBehavior 1086 + ", mDefaultHoldersResourceName=" + mDefaultHoldersResourceName 1087 + ", mDescriptionResource=" + mDescriptionResource 1088 + ", mExclusive=" + mExclusive 1089 + ", mFallBackToDefaultHolder=" + mFallBackToDefaultHolder 1090 + ", mLabelResource=" + mLabelResource 1091 + ", mMaxSdkVersion=" + mMaxSdkVersion 1092 + ", mMinSdkVersion=" + mMinSdkVersion 1093 + ", mOnlyGrantWhenAdded=" + mOnlyGrantWhenAdded 1094 + ", mOverrideUserWhenGranting=" + mOverrideUserWhenGranting 1095 + ", mRequestDescriptionResource=" + mRequestDescriptionResource 1096 + ", mRequestTitleResource=" + mRequestTitleResource 1097 + ", mRequestable=" + mRequestable 1098 + ", mSearchKeywordsResource=" + mSearchKeywordsResource 1099 + ", mShortLabelResource=" + mShortLabelResource 1100 + ", mShowNone=" + mShowNone 1101 + ", mStatic=" + mStatic 1102 + ", mSystemOnly=" + mSystemOnly 1103 + ", mVisible=" + mVisible 1104 + ", mRequiredComponents=" + mRequiredComponents 1105 + ", mPermissions=" + mPermissions 1106 + ", mAppOpPermissions=" + mAppOpPermissions 1107 + ", mAppOps=" + mAppOps 1108 + ", mPreferredActivities=" + mPreferredActivities 1109 + ", mUiBehaviorName=" + mUiBehaviorName 1110 + '}'; 1111 } 1112 } 1113