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