1 /*
2  * Copyright (C) 2006 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.server.pm.permission;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.UserIdInt;
23 import android.content.pm.PackageManager;
24 import android.content.pm.PackageManagerInternal;
25 import android.content.pm.PermissionInfo;
26 import android.os.Build;
27 import android.os.UserHandle;
28 import android.util.Log;
29 import android.util.Slog;
30 
31 import com.android.server.pm.PackageManagerService;
32 import com.android.server.pm.pkg.PackageState;
33 import com.android.server.pm.pkg.component.ParsedPermission;
34 
35 import libcore.util.EmptyArray;
36 
37 import java.lang.annotation.Retention;
38 import java.lang.annotation.RetentionPolicy;
39 import java.util.Collection;
40 import java.util.Objects;
41 import java.util.Set;
42 
43 /**
44  * Permission definition.
45  */
46 public final class Permission {
47     private static final String TAG = "Permission";
48 
49     public static final int TYPE_MANIFEST = LegacyPermission.TYPE_MANIFEST;
50     public static final int TYPE_CONFIG = LegacyPermission.TYPE_CONFIG;
51     public static final int TYPE_DYNAMIC = LegacyPermission.TYPE_DYNAMIC;
52     @IntDef({
53             TYPE_MANIFEST,
54             TYPE_CONFIG,
55             TYPE_DYNAMIC,
56     })
57     @Retention(RetentionPolicy.SOURCE)
58     public @interface PermissionType {}
59 
60     @IntDef({
61             PermissionInfo.PROTECTION_DANGEROUS,
62             PermissionInfo.PROTECTION_NORMAL,
63             PermissionInfo.PROTECTION_SIGNATURE,
64             PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM,
65             PermissionInfo.PROTECTION_INTERNAL,
66     })
67     @Retention(RetentionPolicy.SOURCE)
68     public @interface ProtectionLevel {}
69 
70     @NonNull
71     private PermissionInfo mPermissionInfo;
72 
73     private boolean mReconciled;
74 
75     @PermissionType
76     private final int mType;
77 
78     /** UID that owns the definition of this permission */
79     private int mUid;
80 
81     /** Additional GIDs given to apps granted this permission */
82     @NonNull
83     private int[] mGids = EmptyArray.INT;
84 
85     /**
86      * Flag indicating that {@link #mGids} should be adjusted based on the
87      * {@link UserHandle} the granted app is running as.
88      */
89     private boolean mGidsPerUser;
90 
91     private boolean mDefinitionChanged;
92 
Permission(@onNull String name, @NonNull String packageName, @PermissionType int type)93     public Permission(@NonNull String name, @NonNull String packageName,
94             @PermissionType int type) {
95         mPermissionInfo = new PermissionInfo();
96         mPermissionInfo.name = name;
97         mPermissionInfo.packageName = packageName;
98         // Default to most conservative protection level.
99         mPermissionInfo.protectionLevel = PermissionInfo.PROTECTION_SIGNATURE;
100         mType = type;
101     }
102 
Permission(@onNull PermissionInfo permissionInfo, @PermissionType int type)103     public Permission(@NonNull PermissionInfo permissionInfo, @PermissionType int type) {
104         mPermissionInfo = permissionInfo;
105         mType = type;
106     }
107 
Permission(@onNull PermissionInfo permissionInfo, @PermissionType int type, boolean reconciled, int uid, int[] gids, boolean gidsPerUser)108     public Permission(@NonNull PermissionInfo permissionInfo, @PermissionType int type,
109             boolean reconciled, int uid, int[] gids, boolean gidsPerUser) {
110         this(permissionInfo, type);
111         mReconciled = reconciled;
112         mUid = uid;
113         mGids = gids;
114         mGidsPerUser = gidsPerUser;
115     }
116 
117     @NonNull
getPermissionInfo()118     public PermissionInfo getPermissionInfo() {
119         return mPermissionInfo;
120     }
121 
setPermissionInfo(@ullable PermissionInfo permissionInfo)122     public void setPermissionInfo(@Nullable PermissionInfo permissionInfo) {
123         if (permissionInfo != null) {
124             mPermissionInfo = permissionInfo;
125         } else {
126             final PermissionInfo newPermissionInfo = new PermissionInfo();
127             newPermissionInfo.name = mPermissionInfo.name;
128             newPermissionInfo.packageName = mPermissionInfo.packageName;
129             newPermissionInfo.protectionLevel = mPermissionInfo.protectionLevel;
130             mPermissionInfo = newPermissionInfo;
131         }
132         mReconciled = permissionInfo != null;
133     }
134 
135     @NonNull
getName()136     public String getName() {
137         return mPermissionInfo.name;
138     }
139 
getProtectionLevel()140     public int getProtectionLevel() {
141         return mPermissionInfo.protectionLevel;
142     }
143 
144     @NonNull
getPackageName()145     public String getPackageName() {
146         return mPermissionInfo.packageName;
147     }
148 
getType()149     public int getType() {
150         return mType;
151     }
152 
getUid()153     public int getUid() {
154         return mUid;
155     }
156 
hasGids()157     public boolean hasGids() {
158         return mGids.length != 0;
159     }
160 
161     @NonNull
getRawGids()162     public int[] getRawGids() {
163         return mGids;
164     }
165 
areGidsPerUser()166     public boolean areGidsPerUser() {
167         return mGidsPerUser;
168     }
169 
setGids(@onNull int[] gids, boolean gidsPerUser)170     public void setGids(@NonNull int[] gids, boolean gidsPerUser) {
171         mGids = gids;
172         mGidsPerUser = gidsPerUser;
173     }
174 
175     @NonNull
computeGids(@serIdInt int userId)176     public int[] computeGids(@UserIdInt int userId) {
177         if (mGidsPerUser) {
178             final int[] userGids = new int[mGids.length];
179             for (int i = 0; i < mGids.length; i++) {
180                 final int gid = mGids[i];
181                 userGids[i] = UserHandle.getUid(userId, gid);
182             }
183             return userGids;
184         } else {
185             return mGids.length != 0 ? mGids.clone() : mGids;
186         }
187     }
188 
isDefinitionChanged()189     public boolean isDefinitionChanged() {
190         return mDefinitionChanged;
191     }
192 
setDefinitionChanged(boolean definitionChanged)193     public void setDefinitionChanged(boolean definitionChanged) {
194         mDefinitionChanged = definitionChanged;
195     }
196 
calculateFootprint(@onNull Permission permission)197     public int calculateFootprint(@NonNull Permission permission) {
198         if (mUid == permission.mUid) {
199             return permission.mPermissionInfo.name.length()
200                     + permission.mPermissionInfo.calculateFootprint();
201         }
202         return 0;
203     }
204 
isPermission(@onNull ParsedPermission parsedPermission)205     public boolean isPermission(@NonNull ParsedPermission parsedPermission) {
206         if (mPermissionInfo == null) {
207             return false;
208         }
209         return Objects.equals(mPermissionInfo.packageName, parsedPermission.getPackageName())
210                 && Objects.equals(mPermissionInfo.name, parsedPermission.getName());
211     }
212 
isDynamic()213     public boolean isDynamic() {
214         return mType == TYPE_DYNAMIC;
215     }
216 
isNormal()217     public boolean isNormal() {
218         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
219                 == PermissionInfo.PROTECTION_NORMAL;
220     }
isRuntime()221     public boolean isRuntime() {
222         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
223                 == PermissionInfo.PROTECTION_DANGEROUS;
224     }
225 
isRemoved()226     public boolean isRemoved() {
227         return (mPermissionInfo.flags & PermissionInfo.FLAG_REMOVED) != 0;
228     }
229 
isSoftRestricted()230     public boolean isSoftRestricted() {
231         return (mPermissionInfo.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0;
232     }
233 
isHardRestricted()234     public boolean isHardRestricted() {
235         return (mPermissionInfo.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0;
236     }
237 
isHardOrSoftRestricted()238     public boolean isHardOrSoftRestricted() {
239         return (mPermissionInfo.flags & (PermissionInfo.FLAG_HARD_RESTRICTED
240                 | PermissionInfo.FLAG_SOFT_RESTRICTED)) != 0;
241     }
242 
isImmutablyRestricted()243     public boolean isImmutablyRestricted() {
244         return (mPermissionInfo.flags & PermissionInfo.FLAG_IMMUTABLY_RESTRICTED) != 0;
245     }
246 
isSignature()247     public boolean isSignature() {
248         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
249                 == PermissionInfo.PROTECTION_SIGNATURE;
250     }
251 
isInternal()252     public boolean isInternal() {
253         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
254                 == PermissionInfo.PROTECTION_INTERNAL;
255     }
256 
isAppOp()257     public boolean isAppOp() {
258         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0;
259     }
260 
isDevelopment()261     public boolean isDevelopment() {
262         return isSignature() && (mPermissionInfo.protectionLevel
263                 & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0;
264     }
265 
isInstaller()266     public boolean isInstaller() {
267         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTALLER) != 0;
268     }
269 
isInstant()270     public boolean isInstant() {
271         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0;
272     }
273 
isOem()274     public boolean isOem() {
275         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_OEM) != 0;
276     }
277 
isPre23()278     public boolean isPre23() {
279         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_PRE23) != 0;
280     }
281 
isPreInstalled()282     public boolean isPreInstalled() {
283         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_PREINSTALLED) != 0;
284     }
285 
isPrivileged()286     public boolean isPrivileged() {
287         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0;
288     }
289 
isRuntimeOnly()290     public boolean isRuntimeOnly() {
291         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) != 0;
292     }
293 
isSetup()294     public boolean isSetup() {
295         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_SETUP) != 0;
296     }
297 
isVerifier()298     public boolean isVerifier() {
299         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_VERIFIER) != 0;
300     }
301 
isVendorPrivileged()302     public boolean isVendorPrivileged() {
303         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_VENDOR_PRIVILEGED)
304                 != 0;
305     }
306 
isSystemTextClassifier()307     public boolean isSystemTextClassifier() {
308         return (mPermissionInfo.protectionLevel
309                 & PermissionInfo.PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER) != 0;
310     }
311 
isConfigurator()312     public boolean isConfigurator() {
313         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_CONFIGURATOR) != 0;
314     }
315 
isIncidentReportApprover()316     public boolean isIncidentReportApprover() {
317         return (mPermissionInfo.protectionLevel
318                 & PermissionInfo.PROTECTION_FLAG_INCIDENT_REPORT_APPROVER) != 0;
319     }
320 
isAppPredictor()321     public boolean isAppPredictor() {
322         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_APP_PREDICTOR)
323                 != 0;
324     }
325 
isCompanion()326     public boolean isCompanion() {
327         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_COMPANION) != 0;
328     }
329 
isModule()330     public boolean isModule() {
331         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_MODULE) != 0;
332     }
333 
isRetailDemo()334     public boolean isRetailDemo() {
335         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_RETAIL_DEMO) != 0;
336     }
337 
isRecents()338     public boolean isRecents() {
339         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_RECENTS) != 0;
340     }
341 
isRole()342     public boolean isRole() {
343         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_ROLE) != 0;
344     }
345 
isKnownSigner()346     public boolean isKnownSigner() {
347         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_KNOWN_SIGNER) != 0;
348     }
349 
getKnownCerts()350     public Set<String> getKnownCerts() {
351         return mPermissionInfo.knownCerts;
352     }
353 
transfer(@onNull String oldPackageName, @NonNull String newPackageName)354     public void transfer(@NonNull String oldPackageName, @NonNull String newPackageName) {
355         if (!oldPackageName.equals(mPermissionInfo.packageName)) {
356             return;
357         }
358         final PermissionInfo newPermissionInfo = new PermissionInfo();
359         newPermissionInfo.name = mPermissionInfo.name;
360         newPermissionInfo.packageName = newPackageName;
361         newPermissionInfo.protectionLevel = mPermissionInfo.protectionLevel;
362         mPermissionInfo = newPermissionInfo;
363         mReconciled = false;
364         mUid = 0;
365         mGids = EmptyArray.INT;
366         mGidsPerUser = false;
367     }
368 
addToTree(@rotectionLevel int protectionLevel, @NonNull PermissionInfo permissionInfo, @NonNull Permission permissionTree)369     public boolean addToTree(@ProtectionLevel int protectionLevel,
370             @NonNull PermissionInfo permissionInfo, @NonNull Permission permissionTree) {
371         final boolean changed =
372                 (mPermissionInfo.protectionLevel != protectionLevel
373                     || !mReconciled
374                     || mUid != permissionTree.mUid
375                     || !Objects.equals(mPermissionInfo.packageName,
376                             permissionTree.mPermissionInfo.packageName)
377                     || !comparePermissionInfos(mPermissionInfo, permissionInfo));
378         mPermissionInfo = new PermissionInfo(permissionInfo);
379         mPermissionInfo.packageName = permissionTree.mPermissionInfo.packageName;
380         mPermissionInfo.protectionLevel = protectionLevel;
381         mReconciled = true;
382         mUid = permissionTree.mUid;
383         return changed;
384     }
385 
updateDynamicPermission(@onNull Collection<Permission> permissionTrees)386     public void updateDynamicPermission(@NonNull Collection<Permission> permissionTrees) {
387         if (PackageManagerService.DEBUG_SETTINGS) {
388             Log.v(TAG, "Dynamic permission: name=" + getName() + " pkg=" + getPackageName()
389                     + " info=" + mPermissionInfo);
390         }
391         if (mType == TYPE_DYNAMIC) {
392             final Permission tree = findPermissionTree(permissionTrees, mPermissionInfo.name);
393             if (tree != null) {
394                 mPermissionInfo.packageName = tree.mPermissionInfo.packageName;
395                 mReconciled = true;
396                 mUid = tree.mUid;
397             }
398         }
399     }
400 
isOverridingSystemPermission(@ullable Permission permission, @NonNull PermissionInfo permissionInfo, @NonNull PackageManagerInternal packageManagerInternal)401     public static boolean isOverridingSystemPermission(@Nullable Permission permission,
402             @NonNull PermissionInfo permissionInfo,
403             @NonNull PackageManagerInternal packageManagerInternal) {
404         if (permission == null || Objects.equals(permission.mPermissionInfo.packageName,
405                 permissionInfo.packageName)) {
406             return false;
407         }
408         if (!permission.mReconciled) {
409             return false;
410         }
411         var currentPackageState = packageManagerInternal.getPackageStateInternal(
412                 permission.mPermissionInfo.packageName);
413         if (currentPackageState == null) {
414             return false;
415         }
416         return currentPackageState.isSystem();
417     }
418 
419     @NonNull
createOrUpdate(@ullable Permission permission, @NonNull PermissionInfo permissionInfo, @NonNull PackageState packageState, @NonNull Collection<Permission> permissionTrees, boolean isOverridingSystemPermission)420     public static Permission createOrUpdate(@Nullable Permission permission,
421             @NonNull PermissionInfo permissionInfo, @NonNull PackageState packageState,
422             @NonNull Collection<Permission> permissionTrees, boolean isOverridingSystemPermission) {
423         // Allow system apps to redefine non-system permissions
424         boolean ownerChanged = false;
425         if (permission != null && !Objects.equals(permission.mPermissionInfo.packageName,
426                 permissionInfo.packageName)) {
427             if (packageState.isSystem()) {
428                 if (permission.mType == Permission.TYPE_CONFIG && !permission.mReconciled) {
429                     // It's a built-in permission and no owner, take ownership now
430                     permission.mPermissionInfo = permissionInfo;
431                     permission.mReconciled = true;
432                     permission.mUid = packageState.getAppId();
433                 } else if (!isOverridingSystemPermission) {
434                     Slog.w(TAG, "New decl " + packageState + " of permission  "
435                             + permissionInfo.name + " is system; overriding "
436                             + permission.mPermissionInfo.packageName);
437                     ownerChanged = true;
438                     permission = null;
439                 }
440             }
441         }
442         boolean wasNonInternal = permission != null && permission.mType != TYPE_CONFIG
443                 && !permission.isInternal();
444         boolean wasNonRuntime = permission != null && permission.mType != TYPE_CONFIG
445                 && !permission.isRuntime();
446         if (permission == null) {
447             permission = new Permission(permissionInfo.name, permissionInfo.packageName,
448                     TYPE_MANIFEST);
449         }
450         StringBuilder r = null;
451         if (!permission.mReconciled) {
452             if (permission.mPermissionInfo.packageName == null
453                     || permission.mPermissionInfo.packageName.equals(permissionInfo.packageName)) {
454                 final Permission tree = findPermissionTree(permissionTrees, permissionInfo.name);
455                 if (tree == null
456                         || tree.mPermissionInfo.packageName.equals(permissionInfo.packageName)) {
457                     permission.mPermissionInfo = permissionInfo;
458                     permission.mReconciled = true;
459                     permission.mUid = packageState.getAppId();
460                     if (PackageManagerService.DEBUG_PACKAGE_SCANNING) {
461                         if (r == null) {
462                             r = new StringBuilder(256);
463                         } else {
464                             r.append(' ');
465                         }
466                         r.append(permissionInfo.name);
467                     }
468                 } else {
469                     Slog.w(TAG, "Permission " + permissionInfo.name + " from package "
470                             + permissionInfo.packageName + " ignored: base tree "
471                             + tree.mPermissionInfo.name + " is from package "
472                             + tree.mPermissionInfo.packageName);
473                 }
474             } else {
475                 Slog.w(TAG, "Permission " + permissionInfo.name + " from package "
476                         + permissionInfo.packageName + " ignored: original from "
477                         + permission.mPermissionInfo.packageName);
478             }
479         } else if (PackageManagerService.DEBUG_PACKAGE_SCANNING) {
480             if (r == null) {
481                 r = new StringBuilder(256);
482             } else {
483                 r.append(' ');
484             }
485             r.append("DUP:");
486             r.append(permissionInfo.name);
487         }
488         if ((permission.isInternal() && (ownerChanged || wasNonInternal))
489                 || (permission.isRuntime() && (ownerChanged || wasNonRuntime))) {
490             // If this is an internal/runtime permission and the owner has changed, or this wasn't a
491             // internal/runtime permission, then permission state should be cleaned up.
492             permission.mDefinitionChanged = true;
493         }
494         if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) {
495             Log.d(TAG, "  Permissions: " + r);
496         }
497         return permission;
498     }
499 
500     @NonNull
enforcePermissionTree(@onNull Collection<Permission> permissionTrees, @NonNull String permissionName, int callingUid)501     public static Permission enforcePermissionTree(@NonNull Collection<Permission> permissionTrees,
502             @NonNull String permissionName, int callingUid) {
503         if (permissionName != null) {
504             final Permission permissionTree = Permission.findPermissionTree(permissionTrees,
505                     permissionName);
506             if (permissionTree != null) {
507                 if (permissionTree.getUid() == UserHandle.getAppId(callingUid)) {
508                     return permissionTree;
509                 }
510             }
511         }
512         throw new SecurityException("Calling uid " + callingUid
513             + " is not allowed to add to or remove from the permission tree");
514     }
515 
516     @Nullable
findPermissionTree(@onNull Collection<Permission> permissionTrees, @NonNull String permissionName)517     private static Permission findPermissionTree(@NonNull Collection<Permission> permissionTrees,
518             @NonNull String permissionName) {
519         for (final Permission permissionTree : permissionTrees) {
520             final String permissionTreeName = permissionTree.getName();
521             if (permissionName.startsWith(permissionTreeName)
522                     && permissionName.length() > permissionTreeName.length()
523                     && permissionName.charAt(permissionTreeName.length()) == '.') {
524                 return permissionTree;
525             }
526         }
527         return null;
528     }
529 
530     @Nullable
getBackgroundPermission()531     public String getBackgroundPermission() {
532         return mPermissionInfo.backgroundPermission;
533     }
534 
535     @Nullable
getGroup()536     public String getGroup() {
537         return mPermissionInfo.group;
538     }
539 
getProtection()540     public int getProtection() {
541         return mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
542     }
543 
getProtectionFlags()544     public int getProtectionFlags() {
545         return mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_FLAGS;
546     }
547 
548     @NonNull
generatePermissionInfo(int flags)549     public PermissionInfo generatePermissionInfo(int flags) {
550         return generatePermissionInfo(flags, Build.VERSION_CODES.CUR_DEVELOPMENT);
551     }
552 
553     @NonNull
generatePermissionInfo(int flags, int targetSdkVersion)554     public PermissionInfo generatePermissionInfo(int flags, int targetSdkVersion) {
555         final PermissionInfo permissionInfo;
556         if (mPermissionInfo != null) {
557             permissionInfo = new PermissionInfo(mPermissionInfo);
558             if ((flags & PackageManager.GET_META_DATA) != PackageManager.GET_META_DATA) {
559                 permissionInfo.metaData = null;
560             }
561         } else {
562             permissionInfo = new PermissionInfo();
563             permissionInfo.name = mPermissionInfo.name;
564             permissionInfo.packageName = mPermissionInfo.packageName;
565             permissionInfo.nonLocalizedLabel = mPermissionInfo.name;
566         }
567         // A Permission in PermissionRegistry is always installed.
568         permissionInfo.flags |= PermissionInfo.FLAG_INSTALLED;
569         if (targetSdkVersion >= Build.VERSION_CODES.O) {
570             permissionInfo.protectionLevel = mPermissionInfo.protectionLevel;
571         } else {
572             final int protection = mPermissionInfo.protectionLevel
573                     & PermissionInfo.PROTECTION_MASK_BASE;
574             if (protection == PermissionInfo.PROTECTION_SIGNATURE) {
575                 // Signature permission's protection flags are always reported.
576                 permissionInfo.protectionLevel = mPermissionInfo.protectionLevel;
577             } else {
578                 permissionInfo.protectionLevel = protection;
579             }
580         }
581         return permissionInfo;
582     }
583 
comparePermissionInfos(PermissionInfo pi1, PermissionInfo pi2)584     private static boolean comparePermissionInfos(PermissionInfo pi1, PermissionInfo pi2) {
585         if (pi1.icon != pi2.icon) return false;
586         if (pi1.logo != pi2.logo) return false;
587         if (pi1.protectionLevel != pi2.protectionLevel) return false;
588         if (!Objects.equals(pi1.name, pi2.name)) return false;
589         if (!Objects.equals(pi1.nonLocalizedLabel, pi2.nonLocalizedLabel)) return false;
590         // We'll take care of setting this one.
591         if (!Objects.equals(pi1.packageName, pi2.packageName)) return false;
592         // These are not currently stored in settings.
593         //if (!compareStrings(pi1.group, pi2.group)) return false;
594         //if (!compareStrings(pi1.nonLocalizedDescription, pi2.nonLocalizedDescription)) return false;
595         //if (pi1.labelRes != pi2.labelRes) return false;
596         //if (pi1.descriptionRes != pi2.descriptionRes) return false;
597         return true;
598     }
599 }
600