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