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