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