• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static android.Manifest.permission.READ_EXTERNAL_STORAGE;
20 import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
21 import static android.content.pm.PermissionInfo.PROTECTION_NORMAL;
22 import static android.content.pm.PermissionInfo.PROTECTION_SIGNATURE;
23 import static android.content.pm.PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM;
24 
25 import static com.android.server.pm.Settings.ATTR_NAME;
26 import static com.android.server.pm.Settings.ATTR_PACKAGE;
27 import static com.android.server.pm.Settings.TAG_ITEM;
28 
29 import android.annotation.IntDef;
30 import android.annotation.NonNull;
31 import android.annotation.Nullable;
32 import android.content.pm.PackageManagerInternal;
33 import android.content.pm.PermissionInfo;
34 import android.content.pm.parsing.component.ParsedPermission;
35 import android.os.UserHandle;
36 import android.util.Log;
37 import android.util.Slog;
38 
39 import com.android.server.pm.DumpState;
40 import com.android.server.pm.PackageManagerService;
41 import com.android.server.pm.PackageSetting;
42 import com.android.server.pm.PackageSettingBase;
43 import com.android.server.pm.parsing.PackageInfoUtils;
44 import com.android.server.pm.parsing.pkg.AndroidPackage;
45 
46 import org.xmlpull.v1.XmlPullParser;
47 import org.xmlpull.v1.XmlSerializer;
48 
49 import java.io.IOException;
50 import java.io.PrintWriter;
51 import java.lang.annotation.Retention;
52 import java.lang.annotation.RetentionPolicy;
53 import java.util.Arrays;
54 import java.util.Collection;
55 import java.util.Map;
56 import java.util.Objects;
57 import java.util.Set;
58 
59 public final class BasePermission {
60     static final String TAG = "PackageManager";
61 
62     public static final int TYPE_NORMAL = 0;
63     public static final int TYPE_BUILTIN = 1;
64     public static final int TYPE_DYNAMIC = 2;
65     @IntDef(value = {
66         TYPE_NORMAL,
67         TYPE_BUILTIN,
68         TYPE_DYNAMIC,
69     })
70     @Retention(RetentionPolicy.SOURCE)
71     public @interface PermissionType {}
72 
73     @IntDef(value = {
74         PROTECTION_DANGEROUS,
75         PROTECTION_NORMAL,
76         PROTECTION_SIGNATURE,
77         PROTECTION_SIGNATURE_OR_SYSTEM,
78     })
79     @Retention(RetentionPolicy.SOURCE)
80     public @interface ProtectionLevel {}
81 
82     final String name;
83 
84     final @PermissionType int type;
85 
86     private boolean mPermissionDefinitionChanged;
87 
88     String sourcePackageName;
89 
90     int protectionLevel;
91 
92     ParsedPermission perm;
93 
94     PermissionInfo pendingPermissionInfo;
95 
96     /** UID that owns the definition of this permission */
97     int uid;
98 
99     /** Additional GIDs given to apps granted this permission */
100     private int[] gids;
101 
102     /**
103      * Flag indicating that {@link #gids} should be adjusted based on the
104      * {@link UserHandle} the granted app is running as.
105      */
106     private boolean perUser;
107 
BasePermission(String _name, String _sourcePackageName, @PermissionType int _type)108     public BasePermission(String _name, String _sourcePackageName, @PermissionType int _type) {
109         name = _name;
110         sourcePackageName = _sourcePackageName;
111         type = _type;
112         // Default to most conservative protection level.
113         protectionLevel = PermissionInfo.PROTECTION_SIGNATURE;
114     }
115 
116     @Override
toString()117     public String toString() {
118         return "BasePermission{" + Integer.toHexString(System.identityHashCode(this)) + " " + name
119                 + "}";
120     }
121 
getName()122     public String getName() {
123         return name;
124     }
getProtectionLevel()125     public int getProtectionLevel() {
126         return protectionLevel;
127     }
getSourcePackageName()128     public String getSourcePackageName() {
129         return sourcePackageName;
130     }
131 
isPermissionDefinitionChanged()132     public boolean isPermissionDefinitionChanged() {
133         return mPermissionDefinitionChanged;
134     }
135 
getType()136     public int getType() {
137         return type;
138     }
getUid()139     public int getUid() {
140         return uid;
141     }
setGids(int[] gids, boolean perUser)142     public void setGids(int[] gids, boolean perUser) {
143         this.gids = gids;
144         this.perUser = perUser;
145     }
setPermission(@ullable ParsedPermission perm)146     public void setPermission(@Nullable ParsedPermission perm) {
147         this.perm = perm;
148     }
149 
setPermissionDefinitionChanged(boolean shouldOverride)150     public void setPermissionDefinitionChanged(boolean shouldOverride) {
151         mPermissionDefinitionChanged = shouldOverride;
152     }
153 
computeGids(int userId)154     public int[] computeGids(int userId) {
155         if (perUser) {
156             final int[] userGids = new int[gids.length];
157             for (int i = 0; i < gids.length; i++) {
158                 userGids[i] = UserHandle.getUid(userId, gids[i]);
159             }
160             return userGids;
161         } else {
162             return gids;
163         }
164     }
165 
calculateFootprint(BasePermission perm)166     public int calculateFootprint(BasePermission perm) {
167         if (uid == perm.uid) {
168             return perm.name.length() + perm.perm.calculateFootprint();
169         }
170         return 0;
171     }
172 
isPermission(ParsedPermission perm)173     public boolean isPermission(ParsedPermission perm) {
174         if (this.perm == null) {
175             return false;
176         }
177         return Objects.equals(this.perm.getPackageName(), perm.getPackageName())
178                 && Objects.equals(this.perm.getName(), perm.getName());
179     }
180 
isDynamic()181     public boolean isDynamic() {
182         return type == TYPE_DYNAMIC;
183     }
184 
185 
isNormal()186     public boolean isNormal() {
187         return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
188                 == PermissionInfo.PROTECTION_NORMAL;
189     }
isRuntime()190     public boolean isRuntime() {
191         return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
192                 == PermissionInfo.PROTECTION_DANGEROUS;
193     }
194 
isRemoved()195     public boolean isRemoved() {
196         return perm != null && (perm.getFlags() & PermissionInfo.FLAG_REMOVED) != 0;
197     }
198 
isSoftRestricted()199     public boolean isSoftRestricted() {
200         return perm != null && (perm.getFlags() & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0;
201     }
202 
isHardRestricted()203     public boolean isHardRestricted() {
204         return perm != null && (perm.getFlags() & PermissionInfo.FLAG_HARD_RESTRICTED) != 0;
205     }
206 
isHardOrSoftRestricted()207     public boolean isHardOrSoftRestricted() {
208         return perm != null && (perm.getFlags() & (PermissionInfo.FLAG_HARD_RESTRICTED
209                 | PermissionInfo.FLAG_SOFT_RESTRICTED)) != 0;
210     }
211 
isImmutablyRestricted()212     public boolean isImmutablyRestricted() {
213         return perm != null && (perm.getFlags() & PermissionInfo.FLAG_IMMUTABLY_RESTRICTED) != 0;
214     }
215 
isSignature()216     public boolean isSignature() {
217         return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) ==
218                 PermissionInfo.PROTECTION_SIGNATURE;
219     }
220 
isAppOp()221     public boolean isAppOp() {
222         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0;
223     }
isDevelopment()224     public boolean isDevelopment() {
225         return isSignature()
226                 && (protectionLevel & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0;
227     }
isInstaller()228     public boolean isInstaller() {
229         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTALLER) != 0;
230     }
isInstant()231     public boolean isInstant() {
232         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0;
233     }
isOEM()234     public boolean isOEM() {
235         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_OEM) != 0;
236     }
isPre23()237     public boolean isPre23() {
238         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_PRE23) != 0;
239     }
isPreInstalled()240     public boolean isPreInstalled() {
241         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_PREINSTALLED) != 0;
242     }
isPrivileged()243     public boolean isPrivileged() {
244         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0;
245     }
isRuntimeOnly()246     public boolean isRuntimeOnly() {
247         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) != 0;
248     }
isSetup()249     public boolean isSetup() {
250         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_SETUP) != 0;
251     }
isVerifier()252     public boolean isVerifier() {
253         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_VERIFIER) != 0;
254     }
isVendorPrivileged()255     public boolean isVendorPrivileged() {
256         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_VENDOR_PRIVILEGED) != 0;
257     }
isSystemTextClassifier()258     public boolean isSystemTextClassifier() {
259         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER)
260                 != 0;
261     }
isWellbeing()262     public boolean isWellbeing() {
263         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_WELLBEING) != 0;
264     }
isDocumenter()265     public boolean isDocumenter() {
266         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_DOCUMENTER) != 0;
267     }
isConfigurator()268     public boolean isConfigurator() {
269         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_CONFIGURATOR)
270             != 0;
271     }
isIncidentReportApprover()272     public boolean isIncidentReportApprover() {
273         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_INCIDENT_REPORT_APPROVER) != 0;
274     }
isAppPredictor()275     public boolean isAppPredictor() {
276         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_APP_PREDICTOR) != 0;
277     }
isCompanion()278     public boolean isCompanion() {
279         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_COMPANION) != 0;
280     }
281 
isRetailDemo()282     public boolean isRetailDemo() {
283         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_RETAIL_DEMO) != 0;
284     }
285 
transfer(@onNull String origPackageName, @NonNull String newPackageName)286     public void transfer(@NonNull String origPackageName, @NonNull String newPackageName) {
287         if (!origPackageName.equals(sourcePackageName)) {
288             return;
289         }
290         sourcePackageName = newPackageName;
291         perm = null;
292         if (pendingPermissionInfo != null) {
293             pendingPermissionInfo.packageName = newPackageName;
294         }
295         uid = 0;
296         setGids(null, false);
297     }
298 
addToTree(@rotectionLevel int protectionLevel, @NonNull PermissionInfo info, @NonNull BasePermission tree)299     public boolean addToTree(@ProtectionLevel int protectionLevel,
300             @NonNull PermissionInfo info, @NonNull BasePermission tree) {
301         final boolean changed =
302                 (this.protectionLevel != protectionLevel
303                     || perm == null
304                     || uid != tree.uid
305                     || !Objects.equals(perm.getPackageName(), tree.perm.getPackageName())
306                     || !comparePermissionInfos(perm, info));
307         this.protectionLevel = protectionLevel;
308         info = new PermissionInfo(info);
309         info.protectionLevel = protectionLevel;
310         perm = new ParsedPermission(tree.perm);
311         uid = tree.uid;
312         return changed;
313     }
314 
updateDynamicPermission(Collection<BasePermission> permissionTrees)315     public void updateDynamicPermission(Collection<BasePermission> permissionTrees) {
316         if (PackageManagerService.DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name="
317                 + getName() + " pkg=" + getSourcePackageName()
318                 + " info=" + pendingPermissionInfo);
319         if (pendingPermissionInfo != null) {
320             final BasePermission tree = findPermissionTree(permissionTrees, name);
321             if (tree != null && tree.perm != null) {
322                 perm = new ParsedPermission(tree.perm, pendingPermissionInfo,
323                         tree.perm.getPackageName(), name);
324                 uid = tree.uid;
325             }
326         }
327     }
328 
createOrUpdate(PackageManagerInternal packageManagerInternal, @Nullable BasePermission bp, @NonNull ParsedPermission p, @NonNull AndroidPackage pkg, Collection<BasePermission> permissionTrees, boolean chatty)329     static BasePermission createOrUpdate(PackageManagerInternal packageManagerInternal,
330             @Nullable BasePermission bp, @NonNull ParsedPermission p,
331             @NonNull AndroidPackage pkg, Collection<BasePermission> permissionTrees,
332             boolean chatty) {
333         final PackageSettingBase pkgSetting =
334                 (PackageSettingBase) packageManagerInternal.getPackageSetting(pkg.getPackageName());
335         // Allow system apps to redefine non-system permissions
336         boolean ownerChanged = false;
337         if (bp != null && !Objects.equals(bp.sourcePackageName, p.getPackageName())) {
338             final boolean currentOwnerIsSystem;
339             if (bp.perm == null) {
340                 currentOwnerIsSystem = false;
341             } else {
342                 AndroidPackage currentPackage = packageManagerInternal.getPackage(
343                         bp.perm.getPackageName());
344                 if (currentPackage == null) {
345                     currentOwnerIsSystem = false;
346                 } else {
347                     currentOwnerIsSystem = currentPackage.isSystem();
348                 }
349             }
350 
351             if (pkg.isSystem()) {
352                 if (bp.type == BasePermission.TYPE_BUILTIN && bp.perm == null) {
353                     // It's a built-in permission and no owner, take ownership now
354                     p.setFlags(p.getFlags() | PermissionInfo.FLAG_INSTALLED);
355                     bp.perm = p;
356                     bp.uid = pkg.getUid();
357                     bp.sourcePackageName = p.getPackageName();
358                 } else if (!currentOwnerIsSystem) {
359                     String msg = "New decl " + pkg + " of permission  "
360                             + p.getName() + " is system; overriding " + bp.sourcePackageName;
361                     PackageManagerService.reportSettingsProblem(Log.WARN, msg);
362                     ownerChanged = true;
363                     bp = null;
364                 }
365             }
366         }
367         if (bp == null) {
368             bp = new BasePermission(p.getName(), p.getPackageName(), TYPE_NORMAL);
369         }
370         boolean wasNonRuntime = !bp.isRuntime();
371         StringBuilder r = null;
372         if (bp.perm == null) {
373             if (bp.sourcePackageName == null
374                     || bp.sourcePackageName.equals(p.getPackageName())) {
375                 final BasePermission tree = findPermissionTree(permissionTrees, p.getName());
376                 if (tree == null
377                         || tree.sourcePackageName.equals(p.getPackageName())) {
378                     p.setFlags(p.getFlags() | PermissionInfo.FLAG_INSTALLED);
379                     bp.perm = p;
380                     bp.uid = pkg.getUid();
381                     bp.sourcePackageName = p.getPackageName();
382                     if (chatty) {
383                         if (r == null) {
384                             r = new StringBuilder(256);
385                         } else {
386                             r.append(' ');
387                         }
388                         r.append(p.getName());
389                     }
390                 } else {
391                     Slog.w(TAG, "Permission " + p.getName() + " from package "
392                             + p.getPackageName() + " ignored: base tree "
393                             + tree.name + " is from package "
394                             + tree.sourcePackageName);
395                 }
396             } else {
397                 Slog.w(TAG, "Permission " + p.getName() + " from package "
398                         + p.getPackageName() + " ignored: original from "
399                         + bp.sourcePackageName);
400             }
401         } else if (chatty) {
402             if (r == null) {
403                 r = new StringBuilder(256);
404             } else {
405                 r.append(' ');
406             }
407             r.append("DUP:");
408             r.append(p.getName());
409         }
410         if (bp.perm != null && Objects.equals(bp.perm.getPackageName(), p.getPackageName())
411                 && Objects.equals(bp.perm.getName(), p.getName())) {
412             bp.protectionLevel = p.getProtectionLevel();
413         }
414         if (bp.isRuntime() && (ownerChanged || wasNonRuntime)) {
415             // If this is a runtime permission and the owner has changed, or this was a normal
416             // permission, then permission state should be cleaned up
417             bp.mPermissionDefinitionChanged = true;
418         }
419         if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) {
420             Log.d(TAG, "  Permissions: " + r);
421         }
422         return bp;
423     }
424 
enforcePermissionTree( Collection<BasePermission> permissionTrees, String permName, int callingUid)425     static BasePermission enforcePermissionTree(
426             Collection<BasePermission> permissionTrees, String permName, int callingUid) {
427         if (permName != null) {
428             BasePermission bp = findPermissionTree(permissionTrees, permName);
429             if (bp != null) {
430                 if (bp.uid == UserHandle.getAppId(callingUid)) {
431                     return bp;
432                 }
433                 throw new SecurityException("Calling uid " + callingUid
434                         + " is not allowed to add to permission tree "
435                         + bp.name + " owned by uid " + bp.uid);
436             }
437         }
438         throw new SecurityException("No permission tree found for " + permName);
439     }
440 
enforceDeclaredUsedAndRuntimeOrDevelopment(AndroidPackage pkg, PackageSetting pkgSetting)441     public void enforceDeclaredUsedAndRuntimeOrDevelopment(AndroidPackage pkg,
442             PackageSetting pkgSetting) {
443         final PermissionsState permsState = pkgSetting.getPermissionsState();
444         int index = pkg.getRequestedPermissions().indexOf(name);
445         if (!permsState.hasRequestedPermission(name) && index == -1) {
446             throw new SecurityException("Package " + pkg.getPackageName()
447                     + " has not requested permission " + name);
448         }
449         if (!isRuntime() && !isDevelopment()) {
450             throw new SecurityException("Permission " + name + " requested by "
451                     + pkg.getPackageName() + " is not a changeable permission type");
452         }
453     }
454 
findPermissionTree( Collection<BasePermission> permissionTrees, String permName)455     private static BasePermission findPermissionTree(
456             Collection<BasePermission> permissionTrees, String permName) {
457         for (BasePermission bp : permissionTrees) {
458             if (permName.startsWith(bp.name) &&
459                     permName.length() > bp.name.length() &&
460                     permName.charAt(bp.name.length()) == '.') {
461                 return bp;
462             }
463         }
464         return null;
465     }
466 
generatePermissionInfo(@onNull String groupName, int flags)467     public @Nullable PermissionInfo generatePermissionInfo(@NonNull String groupName, int flags) {
468         if (groupName == null) {
469             if (perm == null || perm.getGroup() == null) {
470                 return generatePermissionInfo(protectionLevel, flags);
471             }
472         } else {
473             if (perm != null && groupName.equals(perm.getGroup())) {
474                 return PackageInfoUtils.generatePermissionInfo(perm, flags);
475             }
476         }
477         return null;
478     }
479 
generatePermissionInfo(int adjustedProtectionLevel, int flags)480     public @NonNull PermissionInfo generatePermissionInfo(int adjustedProtectionLevel, int flags) {
481         PermissionInfo permissionInfo;
482         if (perm != null) {
483             final boolean protectionLevelChanged = protectionLevel != adjustedProtectionLevel;
484             permissionInfo = PackageInfoUtils.generatePermissionInfo(perm, flags);
485             if (protectionLevelChanged) {
486                 // if we return different protection level, don't use the cached info
487                 permissionInfo = new PermissionInfo(permissionInfo);
488                 permissionInfo.protectionLevel = adjustedProtectionLevel;
489             }
490             return permissionInfo;
491         }
492         permissionInfo = new PermissionInfo();
493         permissionInfo.name = name;
494         permissionInfo.packageName = sourcePackageName;
495         permissionInfo.nonLocalizedLabel = name;
496         permissionInfo.protectionLevel = protectionLevel;
497         return permissionInfo;
498     }
499 
readLPw(@onNull Map<String, BasePermission> out, @NonNull XmlPullParser parser)500     public static boolean readLPw(@NonNull Map<String, BasePermission> out,
501             @NonNull XmlPullParser parser) {
502         final String tagName = parser.getName();
503         if (!tagName.equals(TAG_ITEM)) {
504             return false;
505         }
506         final String name = parser.getAttributeValue(null, ATTR_NAME);
507         final String sourcePackage = parser.getAttributeValue(null, ATTR_PACKAGE);
508         final String ptype = parser.getAttributeValue(null, "type");
509         if (name == null || sourcePackage == null) {
510             PackageManagerService.reportSettingsProblem(Log.WARN,
511                     "Error in package manager settings: permissions has" + " no name at "
512                             + parser.getPositionDescription());
513             return false;
514         }
515         final boolean dynamic = "dynamic".equals(ptype);
516         BasePermission bp = out.get(name);
517         // If the permission is builtin, do not clobber it.
518         if (bp == null || bp.type != TYPE_BUILTIN) {
519             bp = new BasePermission(name.intern(), sourcePackage,
520                     dynamic ? TYPE_DYNAMIC : TYPE_NORMAL);
521         }
522         bp.protectionLevel = readInt(parser, null, "protection",
523                 PermissionInfo.PROTECTION_NORMAL);
524         bp.protectionLevel = PermissionInfo.fixProtectionLevel(bp.protectionLevel);
525         if (dynamic) {
526             final PermissionInfo pi = new PermissionInfo();
527             pi.packageName = sourcePackage.intern();
528             pi.name = name.intern();
529             pi.icon = readInt(parser, null, "icon", 0);
530             pi.nonLocalizedLabel = parser.getAttributeValue(null, "label");
531             pi.protectionLevel = bp.protectionLevel;
532             bp.pendingPermissionInfo = pi;
533         }
534         out.put(bp.name, bp);
535         return true;
536     }
537 
readInt(XmlPullParser parser, String ns, String name, int defValue)538     private static int readInt(XmlPullParser parser, String ns, String name, int defValue) {
539         String v = parser.getAttributeValue(ns, name);
540         try {
541             if (v == null) {
542                 return defValue;
543             }
544             return Integer.parseInt(v);
545         } catch (NumberFormatException e) {
546             PackageManagerService.reportSettingsProblem(Log.WARN,
547                     "Error in package manager settings: attribute " + name
548                             + " has bad integer value " + v + " at "
549                             + parser.getPositionDescription());
550         }
551         return defValue;
552     }
553 
writeLPr(@onNull XmlSerializer serializer)554     public void writeLPr(@NonNull XmlSerializer serializer) throws IOException {
555         if (sourcePackageName == null) {
556             return;
557         }
558         serializer.startTag(null, TAG_ITEM);
559         serializer.attribute(null, ATTR_NAME, name);
560         serializer.attribute(null, ATTR_PACKAGE, sourcePackageName);
561         if (protectionLevel != PermissionInfo.PROTECTION_NORMAL) {
562             serializer.attribute(null, "protection", Integer.toString(protectionLevel));
563         }
564         if (type == BasePermission.TYPE_DYNAMIC) {
565             if (perm != null || pendingPermissionInfo != null) {
566                 serializer.attribute(null, "type", "dynamic");
567                 int icon = perm != null ? perm.getIcon() : pendingPermissionInfo.icon;
568                 CharSequence nonLocalizedLabel = perm != null
569                         ? perm.getNonLocalizedLabel()
570                         : pendingPermissionInfo.nonLocalizedLabel;
571 
572                 if (icon != 0) {
573                     serializer.attribute(null, "icon", Integer.toString(icon));
574                 }
575                 if (nonLocalizedLabel != null) {
576                     serializer.attribute(null, "label", nonLocalizedLabel.toString());
577                 }
578             }
579         }
580         serializer.endTag(null, TAG_ITEM);
581     }
582 
compareStrings(CharSequence s1, CharSequence s2)583     private static boolean compareStrings(CharSequence s1, CharSequence s2) {
584         if (s1 == null) {
585             return s2 == null;
586         }
587         if (s2 == null) {
588             return false;
589         }
590         if (s1.getClass() != s2.getClass()) {
591             return false;
592         }
593         return s1.equals(s2);
594     }
595 
comparePermissionInfos(ParsedPermission pi1, PermissionInfo pi2)596     private static boolean comparePermissionInfos(ParsedPermission pi1, PermissionInfo pi2) {
597         if (pi1.getIcon() != pi2.icon) return false;
598         if (pi1.getLogo() != pi2.logo) return false;
599         if (pi1.getProtectionLevel() != pi2.protectionLevel) return false;
600         if (!compareStrings(pi1.getName(), pi2.name)) return false;
601         if (!compareStrings(pi1.getNonLocalizedLabel(), pi2.nonLocalizedLabel)) return false;
602         // We'll take care of setting this one.
603         if (!compareStrings(pi1.getPackageName(), pi2.packageName)) return false;
604         // These are not currently stored in settings.
605         //if (!compareStrings(pi1.group, pi2.group)) return false;
606         //if (!compareStrings(pi1.nonLocalizedDescription, pi2.nonLocalizedDescription)) return false;
607         //if (pi1.labelRes != pi2.labelRes) return false;
608         //if (pi1.descriptionRes != pi2.descriptionRes) return false;
609         return true;
610     }
611 
dumpPermissionsLPr(@onNull PrintWriter pw, @NonNull String packageName, @NonNull Set<String> permissionNames, boolean readEnforced, boolean printedSomething, @NonNull DumpState dumpState)612     public boolean dumpPermissionsLPr(@NonNull PrintWriter pw, @NonNull String packageName,
613             @NonNull Set<String> permissionNames, boolean readEnforced,
614             boolean printedSomething, @NonNull DumpState dumpState) {
615         if (packageName != null && !packageName.equals(sourcePackageName)) {
616             return false;
617         }
618         if (permissionNames != null && !permissionNames.contains(name)) {
619             return false;
620         }
621         if (!printedSomething) {
622             if (dumpState.onTitlePrinted())
623                 pw.println();
624             pw.println("Permissions:");
625             printedSomething = true;
626         }
627         pw.print("  Permission ["); pw.print(name); pw.print("] (");
628                 pw.print(Integer.toHexString(System.identityHashCode(this)));
629                 pw.println("):");
630         pw.print("    sourcePackage="); pw.println(sourcePackageName);
631         pw.print("    uid="); pw.print(uid);
632                 pw.print(" gids="); pw.print(Arrays.toString(
633                         computeGids(UserHandle.USER_SYSTEM)));
634                 pw.print(" type="); pw.print(type);
635                 pw.print(" prot=");
636                 pw.println(PermissionInfo.protectionToString(protectionLevel));
637         if (perm != null) {
638             pw.print("    perm="); pw.println(perm);
639             if ((perm.getFlags() & PermissionInfo.FLAG_INSTALLED) == 0
640                     || (perm.getFlags() & PermissionInfo.FLAG_REMOVED) != 0) {
641                 pw.print("    flags=0x"); pw.println(Integer.toHexString(perm.getFlags()));
642             }
643         }
644         if (READ_EXTERNAL_STORAGE.equals(name)) {
645             pw.print("    enforced=");
646             pw.println(readEnforced);
647         }
648         return true;
649     }
650 }
651