Move BasePermission to own package

This is the first of many changes. Moving permissions to their own package.

Change-Id: I60e94e2da3c96788fc165e97e813ab5b9ee51586
Bug: 63539144
Test: Manual. Builds and runs
Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.PermissionsHostTest
Test: cts-tradefed run commandAndExit cts-dev -m CtsPermissionTestCases
Test: cts-tradefed run commandAndExit cts-dev -m CtsPermission2TestCases
diff --git a/services/core/java/com/android/server/pm/BasePermission.java b/services/core/java/com/android/server/pm/BasePermission.java
deleted file mode 100644
index 30fda1e..0000000
--- a/services/core/java/com/android/server/pm/BasePermission.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.pm;
-
-import android.content.pm.PackageParser;
-import android.content.pm.PermissionInfo;
-import android.os.UserHandle;
-
-final class BasePermission {
-    final static int TYPE_NORMAL = 0;
-
-    final static int TYPE_BUILTIN = 1;
-
-    final static int TYPE_DYNAMIC = 2;
-
-    final String name;
-
-    String sourcePackage;
-
-    PackageSettingBase packageSetting;
-
-    final int type;
-
-    int protectionLevel;
-
-    PackageParser.Permission perm;
-
-    PermissionInfo pendingInfo;
-
-    /** UID that owns the definition of this permission */
-    int uid;
-
-    /** Additional GIDs given to apps granted this permission */
-    private int[] gids;
-
-    /**
-     * Flag indicating that {@link #gids} should be adjusted based on the
-     * {@link UserHandle} the granted app is running as.
-     */
-    private boolean perUser;
-
-    BasePermission(String _name, String _sourcePackage, int _type) {
-        name = _name;
-        sourcePackage = _sourcePackage;
-        type = _type;
-        // Default to most conservative protection level.
-        protectionLevel = PermissionInfo.PROTECTION_SIGNATURE;
-    }
-
-    @Override
-    public String toString() {
-        return "BasePermission{" + Integer.toHexString(System.identityHashCode(this)) + " " + name
-                + "}";
-    }
-
-    public void setGids(int[] gids, boolean perUser) {
-        this.gids = gids;
-        this.perUser = perUser;
-    }
-
-    public int[] computeGids(int userId) {
-        if (perUser) {
-            final int[] userGids = new int[gids.length];
-            for (int i = 0; i < gids.length; i++) {
-                userGids[i] = UserHandle.getUid(userId, gids[i]);
-            }
-            return userGids;
-        } else {
-            return gids;
-        }
-    }
-
-    public boolean isRuntime() {
-        return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
-                == PermissionInfo.PROTECTION_DANGEROUS;
-    }
-
-    public boolean isDevelopment() {
-        return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
-                == PermissionInfo.PROTECTION_SIGNATURE
-                && (protectionLevel & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0;
-    }
-
-    public boolean isInstant() {
-        return (protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0;
-    }
-
-    public boolean isRuntimeOnly() {
-        return (protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) != 0;
-    }
-}
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index a3811ba..59e243a 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -52,6 +52,8 @@
 import android.util.Slog;
 import android.util.Xml;
 import com.android.internal.util.XmlUtils;
+import com.android.server.pm.permission.BasePermission;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
diff --git a/services/core/java/com/android/server/pm/DumpState.java b/services/core/java/com/android/server/pm/DumpState.java
new file mode 100644
index 0000000..7ebef83
--- /dev/null
+++ b/services/core/java/com/android/server/pm/DumpState.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.pm;
+
+public final class DumpState {
+    public static final int DUMP_LIBS = 1 << 0;
+    public static final int DUMP_FEATURES = 1 << 1;
+    public static final int DUMP_ACTIVITY_RESOLVERS = 1 << 2;
+    public static final int DUMP_SERVICE_RESOLVERS = 1 << 3;
+    public static final int DUMP_RECEIVER_RESOLVERS = 1 << 4;
+    public static final int DUMP_CONTENT_RESOLVERS = 1 << 5;
+    public static final int DUMP_PERMISSIONS = 1 << 6;
+    public static final int DUMP_PACKAGES = 1 << 7;
+    public static final int DUMP_SHARED_USERS = 1 << 8;
+    public static final int DUMP_MESSAGES = 1 << 9;
+    public static final int DUMP_PROVIDERS = 1 << 10;
+    public static final int DUMP_VERIFIERS = 1 << 11;
+    public static final int DUMP_PREFERRED = 1 << 12;
+    public static final int DUMP_PREFERRED_XML = 1 << 13;
+    public static final int DUMP_KEYSETS = 1 << 14;
+    public static final int DUMP_VERSION = 1 << 15;
+    public static final int DUMP_INSTALLS = 1 << 16;
+    public static final int DUMP_INTENT_FILTER_VERIFIERS = 1 << 17;
+    public static final int DUMP_DOMAIN_PREFERRED = 1 << 18;
+    public static final int DUMP_FROZEN = 1 << 19;
+    public static final int DUMP_DEXOPT = 1 << 20;
+    public static final int DUMP_COMPILER_STATS = 1 << 21;
+    public static final int DUMP_CHANGES = 1 << 22;
+    public static final int DUMP_VOLUMES = 1 << 23;
+
+    public static final int OPTION_SHOW_FILTERS = 1 << 0;
+
+    private int mTypes;
+
+    private int mOptions;
+
+    private boolean mTitlePrinted;
+
+    private SharedUserSetting mSharedUser;
+
+    public boolean isDumping(int type) {
+        if (mTypes == 0 && type != DUMP_PREFERRED_XML) {
+            return true;
+        }
+
+        return (mTypes & type) != 0;
+    }
+
+    public void setDump(int type) {
+        mTypes |= type;
+    }
+
+    public boolean isOptionEnabled(int option) {
+        return (mOptions & option) != 0;
+    }
+
+    public void setOptionEnabled(int option) {
+        mOptions |= option;
+    }
+
+    public boolean onTitlePrinted() {
+        final boolean printed = mTitlePrinted;
+        mTitlePrinted = true;
+        return printed;
+    }
+
+    public boolean getTitlePrinted() {
+        return mTitlePrinted;
+    }
+
+    public void setTitlePrinted(boolean enabled) {
+        mTitlePrinted = enabled;
+    }
+
+    public SharedUserSetting getSharedUser() {
+        return mSharedUser;
+    }
+
+    public void setSharedUser(SharedUserSetting user) {
+        mSharedUser = user;
+    }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index e1e5b35..37b8ebb 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -49,6 +49,8 @@
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.XmlUtils;
+import com.android.server.pm.permission.BasePermission;
+
 import libcore.io.IoUtils;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 49d3c8b..3574466 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -565,7 +565,7 @@
     }
 
     public void dumpLPr(PrintWriter pw, String packageName,
-                        PackageManagerService.DumpState dumpState) {
+                        DumpState dumpState) {
         boolean printedHeader = false;
         for (ArrayMap.Entry<String, PackageSetting> e : mPackages.entrySet()) {
             String keySetPackage = e.getKey();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ed8dd8b..815106e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -289,6 +289,7 @@
 import com.android.server.pm.dex.DexManager;
 import com.android.server.pm.dex.DexoptOptions;
 import com.android.server.pm.dex.PackageDexUsage;
+import com.android.server.pm.permission.BasePermission;
 import com.android.server.storage.DeviceStorageMonitorInternal;
 
 import dalvik.system.CloseGuard;
@@ -385,7 +386,7 @@
 public class PackageManagerService extends IPackageManager.Stub
         implements PackageSender {
     static final String TAG = "PackageManager";
-    static final boolean DEBUG_SETTINGS = false;
+    public static final boolean DEBUG_SETTINGS = false;
     static final boolean DEBUG_PREFERRED = false;
     static final boolean DEBUG_UPGRADE = false;
     static final boolean DEBUG_DOMAIN_VERIFICATION = false;
@@ -396,7 +397,7 @@
     private static final boolean DEBUG_SHOW_INFO = false;
     private static final boolean DEBUG_PACKAGE_INFO = false;
     private static final boolean DEBUG_INTENT_MATCHING = false;
-    private static final boolean DEBUG_PACKAGE_SCANNING = false;
+    public static final boolean DEBUG_PACKAGE_SCANNING = false;
     private static final boolean DEBUG_VERIFY = false;
     private static final boolean DEBUG_FILTERS = false;
     private static final boolean DEBUG_PERMISSIONS = false;
@@ -4272,18 +4273,6 @@
         return null;
     }
 
-    static PermissionInfo generatePermissionInfo(BasePermission bp, int flags) {
-        if (bp.perm != null) {
-            return PackageParser.generatePermissionInfo(bp.perm, flags);
-        }
-        PermissionInfo pi = new PermissionInfo();
-        pi.name = bp.name;
-        pi.packageName = bp.sourcePackage;
-        pi.nonLocalizedLabel = bp.name;
-        pi.protectionLevel = bp.protectionLevel;
-        return pi;
-    }
-
     @Override
     public PermissionInfo getPermissionInfo(String name, String packageName, int flags) {
         final int callingUid = Binder.getCallingUid();
@@ -4292,24 +4281,13 @@
         }
         // reader
         synchronized (mPackages) {
-            final BasePermission p = mSettings.mPermissions.get(name);
-            if (p == null) {
+            final BasePermission bp = mSettings.mPermissions.get(name);
+            if (bp == null) {
                 return null;
             }
-            // If the caller is an app that targets pre 26 SDK drop protection flags.
-            PermissionInfo permissionInfo = generatePermissionInfo(p, flags);
-            if (permissionInfo != null) {
-                final int protectionLevel = adjustPermissionProtectionFlagsLPr(
-                        permissionInfo.protectionLevel, packageName, callingUid);
-                if (permissionInfo.protectionLevel != protectionLevel) {
-                    // If we return different protection level, don't use the cached info
-                    if (p.perm != null && p.perm.info == permissionInfo) {
-                        permissionInfo = new PermissionInfo(permissionInfo);
-                    }
-                    permissionInfo.protectionLevel = protectionLevel;
-                }
-            }
-            return permissionInfo;
+            final int adjustedProtectionLevel = adjustPermissionProtectionFlagsLPr(
+                    bp.getProtectionLevel(), packageName, callingUid);
+            return bp.generatePermissionInfo(adjustedProtectionLevel, flags);
         }
     }
 
@@ -4356,28 +4334,23 @@
     }
 
     @Override
-    public @Nullable ParceledListSlice<PermissionInfo> queryPermissionsByGroup(String group,
+    public @Nullable ParceledListSlice<PermissionInfo> queryPermissionsByGroup(String groupName,
             int flags) {
         if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
             return null;
         }
         // reader
         synchronized (mPackages) {
-            if (group != null && !mPermissionGroups.containsKey(group)) {
+            if (groupName != null && !mPermissionGroups.containsKey(groupName)) {
                 // This is thrown as NameNotFoundException
                 return null;
             }
 
             ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10);
-            for (BasePermission p : mSettings.mPermissions.values()) {
-                if (group == null) {
-                    if (p.perm == null || p.perm.info.group == null) {
-                        out.add(generatePermissionInfo(p, flags));
-                    }
-                } else {
-                    if (p.perm != null && group.equals(p.perm.info.group)) {
-                        out.add(PackageParser.generatePermissionInfo(p.perm, flags));
-                    }
+            for (BasePermission bp : mSettings.mPermissions.values()) {
+                final PermissionInfo pi = bp.generatePermissionInfo(groupName, flags);
+                if (pi != null) {
+                    out.add(pi);
                 }
             }
             return new ParceledListSlice<>(out);
@@ -5454,75 +5427,10 @@
         }
     }
 
-    private BasePermission findPermissionTreeLP(String permName) {
-        for(BasePermission bp : mSettings.mPermissionTrees.values()) {
-            if (permName.startsWith(bp.name) &&
-                    permName.length() > bp.name.length() &&
-                    permName.charAt(bp.name.length()) == '.') {
-                return bp;
-            }
-        }
-        return null;
-    }
-
-    private BasePermission checkPermissionTreeLP(String permName) {
-        if (permName != null) {
-            BasePermission bp = findPermissionTreeLP(permName);
-            if (bp != null) {
-                if (bp.uid == UserHandle.getAppId(Binder.getCallingUid())) {
-                    return bp;
-                }
-                throw new SecurityException("Calling uid "
-                        + Binder.getCallingUid()
-                        + " is not allowed to add to permission tree "
-                        + bp.name + " owned by uid " + bp.uid);
-            }
-        }
-        throw new SecurityException("No permission tree found for " + permName);
-    }
-
-    static boolean compareStrings(CharSequence s1, CharSequence s2) {
-        if (s1 == null) {
-            return s2 == null;
-        }
-        if (s2 == null) {
-            return false;
-        }
-        if (s1.getClass() != s2.getClass()) {
-            return false;
-        }
-        return s1.equals(s2);
-    }
-
-    static boolean comparePermissionInfos(PermissionInfo pi1, PermissionInfo pi2) {
-        if (pi1.icon != pi2.icon) return false;
-        if (pi1.logo != pi2.logo) return false;
-        if (pi1.protectionLevel != pi2.protectionLevel) return false;
-        if (!compareStrings(pi1.name, pi2.name)) return false;
-        if (!compareStrings(pi1.nonLocalizedLabel, pi2.nonLocalizedLabel)) return false;
-        // We'll take care of setting this one.
-        if (!compareStrings(pi1.packageName, pi2.packageName)) return false;
-        // These are not currently stored in settings.
-        //if (!compareStrings(pi1.group, pi2.group)) return false;
-        //if (!compareStrings(pi1.nonLocalizedDescription, pi2.nonLocalizedDescription)) return false;
-        //if (pi1.labelRes != pi2.labelRes) return false;
-        //if (pi1.descriptionRes != pi2.descriptionRes) return false;
-        return true;
-    }
-
-    int permissionInfoFootprint(PermissionInfo info) {
-        int size = info.name.length();
-        if (info.nonLocalizedLabel != null) size += info.nonLocalizedLabel.length();
-        if (info.nonLocalizedDescription != null) size += info.nonLocalizedDescription.length();
-        return size;
-    }
-
     int calculateCurrentPermissionFootprintLocked(BasePermission tree) {
         int size = 0;
         for (BasePermission perm : mSettings.mPermissions.values()) {
-            if (perm.uid == tree.uid) {
-                size += perm.name.length() + permissionInfoFootprint(perm.perm.info);
-            }
+            size += tree.calculateFootprint(perm);
         }
         return size;
     }
@@ -5530,9 +5438,9 @@
     void enforcePermissionCapLocked(PermissionInfo info, BasePermission tree) {
         // We calculate the max size of permissions defined by this uid and throw
         // if that plus the size of 'info' would exceed our stated maximum.
-        if (tree.uid != Process.SYSTEM_UID) {
+        if (tree.getUid() != Process.SYSTEM_UID) {
             final int curTreeSize = calculateCurrentPermissionFootprintLocked(tree);
-            if (curTreeSize + permissionInfoFootprint(info) > MAX_PERMISSION_TREE_FOOTPRINT) {
+            if (curTreeSize + info.calculateFootprint() > MAX_PERMISSION_TREE_FOOTPRINT) {
                 throw new SecurityException("Permission tree size cap exceeded");
             }
         }
@@ -5545,33 +5453,21 @@
         if (info.labelRes == 0 && info.nonLocalizedLabel == null) {
             throw new SecurityException("Label must be specified in permission");
         }
-        BasePermission tree = checkPermissionTreeLP(info.name);
+        BasePermission tree = BasePermission.enforcePermissionTreeLP(
+                mSettings.mPermissionTrees, info.name, Binder.getCallingUid());
         BasePermission bp = mSettings.mPermissions.get(info.name);
         boolean added = bp == null;
-        boolean changed = true;
         int fixedLevel = PermissionInfo.fixProtectionLevel(info.protectionLevel);
         if (added) {
             enforcePermissionCapLocked(info, tree);
-            bp = new BasePermission(info.name, tree.sourcePackage,
+            bp = new BasePermission(info.name, tree.getSourcePackageName(),
                     BasePermission.TYPE_DYNAMIC);
-        } else if (bp.type != BasePermission.TYPE_DYNAMIC) {
+        } else if (bp.isDynamic()) {
             throw new SecurityException(
                     "Not allowed to modify non-dynamic permission "
                     + info.name);
-        } else {
-            if (bp.protectionLevel == fixedLevel
-                    && bp.perm.owner.equals(tree.perm.owner)
-                    && bp.uid == tree.uid
-                    && comparePermissionInfos(bp.perm.info, info)) {
-                changed = false;
-            }
         }
-        bp.protectionLevel = fixedLevel;
-        info = new PermissionInfo(info);
-        info.protectionLevel = fixedLevel;
-        bp.perm = new PackageParser.Permission(tree.perm.owner, info);
-        bp.perm.info.packageName = tree.perm.info.packageName;
-        bp.uid = tree.uid;
+        final boolean changed = bp.addToTree(fixedLevel, info, tree);
         if (added) {
             mSettings.mPermissions.put(info.name, bp);
         }
@@ -5605,10 +5501,11 @@
             throw new SecurityException("Instant applications don't have access to this method");
         }
         synchronized (mPackages) {
-            checkPermissionTreeLP(name);
+            BasePermission.enforcePermissionTreeLP(
+                    mSettings.mPermissionTrees, name, Binder.getCallingUid());
             BasePermission bp = mSettings.mPermissions.get(name);
             if (bp != null) {
-                if (bp.type != BasePermission.TYPE_DYNAMIC) {
+                if (bp.isDynamic()) {
                     throw new SecurityException(
                             "Not allowed to modify non-dynamic permission "
                             + name);
@@ -5619,19 +5516,6 @@
         }
     }
 
-    private static void enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(
-            PackageParser.Package pkg, BasePermission bp) {
-        int index = pkg.requestedPermissions.indexOf(bp.name);
-        if (index == -1) {
-            throw new SecurityException("Package " + pkg.packageName
-                    + " has not requested permission " + bp.name);
-        }
-        if (!bp.isRuntime() && !bp.isDevelopment()) {
-            throw new SecurityException("Permission " + bp.name
-                    + " is not a changeable permission type");
-        }
-    }
-
     @Override
     public void grantRuntimePermission(String packageName, String name, final int userId) {
         grantRuntimePermission(packageName, name, userId, false /* Only if not fixed by policy */);
@@ -5671,7 +5555,7 @@
                 throw new IllegalArgumentException("Unknown package: " + packageName);
             }
 
-            enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(pkg, bp);
+            bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg);
 
             // If a permission review is required for legacy apps we represent
             // their permissions as always granted runtime ones since we need
@@ -5800,7 +5684,7 @@
                 throw new IllegalArgumentException("Unknown permission: " + name);
             }
 
-            enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(pkg, bp);
+            bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg);
 
             // If a permission review is required for legacy apps we represent
             // their permissions as always granted runtime ones since we need
@@ -9106,7 +8990,7 @@
         return fname;
     }
 
-    static void reportSettingsProblem(int priority, String msg) {
+    public static void reportSettingsProblem(int priority, String msg) {
         logCriticalInfo(priority, msg);
     }
 
@@ -11860,84 +11744,12 @@
                     }
                 }
 
-                ArrayMap<String, BasePermission> permissionMap =
+                final ArrayMap<String, BasePermission> permissionMap =
                         p.tree ? mSettings.mPermissionTrees
                                 : mSettings.mPermissions;
-                BasePermission bp = permissionMap.get(p.info.name);
-
-                // Allow system apps to redefine non-system permissions
-                if (bp != null && !Objects.equals(bp.sourcePackage, p.info.packageName)) {
-                    final boolean currentOwnerIsSystem = (bp.perm != null
-                            && isSystemApp(bp.perm.owner));
-                    if (isSystemApp(p.owner)) {
-                        if (bp.type == BasePermission.TYPE_BUILTIN && bp.perm == null) {
-                            // It's a built-in permission and no owner, take ownership now
-                            bp.packageSetting = pkgSetting;
-                            bp.perm = p;
-                            bp.uid = pkg.applicationInfo.uid;
-                            bp.sourcePackage = p.info.packageName;
-                            p.info.flags |= PermissionInfo.FLAG_INSTALLED;
-                        } else if (!currentOwnerIsSystem) {
-                            String msg = "New decl " + p.owner + " of permission  "
-                                    + p.info.name + " is system; overriding " + bp.sourcePackage;
-                            reportSettingsProblem(Log.WARN, msg);
-                            bp = null;
-                        }
-                    }
-                }
-
-                if (bp == null) {
-                    bp = new BasePermission(p.info.name, p.info.packageName,
-                            BasePermission.TYPE_NORMAL);
-                    permissionMap.put(p.info.name, bp);
-                }
-
-                if (bp.perm == null) {
-                    if (bp.sourcePackage == null
-                            || bp.sourcePackage.equals(p.info.packageName)) {
-                        BasePermission tree = findPermissionTreeLP(p.info.name);
-                        if (tree == null
-                                || tree.sourcePackage.equals(p.info.packageName)) {
-                            bp.packageSetting = pkgSetting;
-                            bp.perm = p;
-                            bp.uid = pkg.applicationInfo.uid;
-                            bp.sourcePackage = p.info.packageName;
-                            p.info.flags |= PermissionInfo.FLAG_INSTALLED;
-                            if (chatty) {
-                                if (r == null) {
-                                    r = new StringBuilder(256);
-                                } else {
-                                    r.append(' ');
-                                }
-                                r.append(p.info.name);
-                            }
-                        } else {
-                            Slog.w(TAG, "Permission " + p.info.name + " from package "
-                                    + p.info.packageName + " ignored: base tree "
-                                    + tree.name + " is from package "
-                                    + tree.sourcePackage);
-                        }
-                    } else {
-                        Slog.w(TAG, "Permission " + p.info.name + " from package "
-                                + p.info.packageName + " ignored: original from "
-                                + bp.sourcePackage);
-                    }
-                } else if (chatty) {
-                    if (r == null) {
-                        r = new StringBuilder(256);
-                    } else {
-                        r.append(' ');
-                    }
-                    r.append("DUP:");
-                    r.append(p.info.name);
-                }
-                if (bp.perm == p) {
-                    bp.protectionLevel = p.info.protectionLevel;
-                }
-            }
-
-            if (r != null) {
-                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Permissions: " + r);
+                final BasePermission bp = BasePermission.createOrUpdate(
+                        permissionMap.get(p.info.name), p, pkg, mSettings.mPermissionTrees, chatty);
+                permissionMap.put(p.info.name, bp);
             }
 
             N = pkg.instrumentation.size();
@@ -12671,8 +12483,8 @@
             if (bp == null) {
                 bp = mSettings.mPermissionTrees.get(p.info.name);
             }
-            if (bp != null && bp.perm == p) {
-                bp.perm = null;
+            if (bp != null && bp.isPermission(p)) {
+                bp.setPermission(null);
                 if (DEBUG_REMOVE && chatty) {
                     if (r == null) {
                         r = new StringBuilder(256);
@@ -12698,7 +12510,7 @@
         for (i=0; i<N; i++) {
             String perm = pkg.requestedPermissions.get(i);
             BasePermission bp = mSettings.mPermissions.get(perm);
-            if (bp != null && (bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) != 0) {
+            if (bp != null && bp.isAppOp()) {
                 ArraySet<String> appOpPkgs = mAppOpPermissionPackages.get(perm);
                 if (appOpPkgs != null) {
                     appOpPkgs.remove(pkg.packageName);
@@ -12803,23 +12615,32 @@
 
     private void updatePermissionsLPw(String changingPkg,
             PackageParser.Package pkgInfo, String replaceVolumeUuid, int flags) {
+        // TODO: Most of the methods exposing BasePermission internals [source package name,
+        // etc..] shouldn't be needed. Instead, when we've parsed a permission that doesn't
+        // have package settings, we should make note of it elsewhere [map between
+        // source package name and BasePermission] and cycle through that here. Then we
+        // define a single method on BasePermission that takes a PackageSetting, changing
+        // package name and a package.
+        // NOTE: With this approach, we also don't need to tree trees differently than
+        // normal permissions. Today, we need two separate loops because these BasePermission
+        // objects are stored separately.
         // Make sure there are no dangling permission trees.
         Iterator<BasePermission> it = mSettings.mPermissionTrees.values().iterator();
         while (it.hasNext()) {
             final BasePermission bp = it.next();
-            if (bp.packageSetting == null) {
+            if (bp.getSourcePackageSetting() == null) {
                 // We may not yet have parsed the package, so just see if
                 // we still know about its settings.
-                bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage);
+                bp.setSourcePackageSetting(mSettings.mPackages.get(bp.getSourcePackageName()));
             }
-            if (bp.packageSetting == null) {
-                Slog.w(TAG, "Removing dangling permission tree: " + bp.name
-                        + " from package " + bp.sourcePackage);
+            if (bp.getSourcePackageSetting() == null) {
+                Slog.w(TAG, "Removing dangling permission tree: " + bp.getName()
+                        + " from package " + bp.getSourcePackageName());
                 it.remove();
-            } else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) {
-                if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {
-                    Slog.i(TAG, "Removing old permission tree: " + bp.name
-                            + " from package " + bp.sourcePackage);
+            } else if (changingPkg != null && changingPkg.equals(bp.getSourcePackageName())) {
+                if (pkgInfo == null || !hasPermission(pkgInfo, bp.getName())) {
+                    Slog.i(TAG, "Removing old permission tree: " + bp.getName()
+                            + " from package " + bp.getSourcePackageName());
                     flags |= UPDATE_PERMISSIONS_ALL;
                     it.remove();
                 }
@@ -12831,35 +12652,22 @@
         it = mSettings.mPermissions.values().iterator();
         while (it.hasNext()) {
             final BasePermission bp = it.next();
-            if (bp.type == BasePermission.TYPE_DYNAMIC) {
-                if (DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name="
-                        + bp.name + " pkg=" + bp.sourcePackage
-                        + " info=" + bp.pendingInfo);
-                if (bp.packageSetting == null && bp.pendingInfo != null) {
-                    final BasePermission tree = findPermissionTreeLP(bp.name);
-                    if (tree != null && tree.perm != null) {
-                        bp.packageSetting = tree.packageSetting;
-                        bp.perm = new PackageParser.Permission(tree.perm.owner,
-                                new PermissionInfo(bp.pendingInfo));
-                        bp.perm.info.packageName = tree.perm.info.packageName;
-                        bp.perm.info.name = bp.name;
-                        bp.uid = tree.uid;
-                    }
-                }
+            if (bp.isDynamic()) {
+                bp.updateDynamicPermission(mSettings.mPermissionTrees);
             }
-            if (bp.packageSetting == null) {
+            if (bp.getSourcePackageSetting() == null) {
                 // We may not yet have parsed the package, so just see if
                 // we still know about its settings.
-                bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage);
+                bp.setSourcePackageSetting(mSettings.mPackages.get(bp.getSourcePackageName()));
             }
-            if (bp.packageSetting == null) {
-                Slog.w(TAG, "Removing dangling permission: " + bp.name
-                        + " from package " + bp.sourcePackage);
+            if (bp.getSourcePackageSetting() == null) {
+                Slog.w(TAG, "Removing dangling permission: " + bp.getName()
+                        + " from package " + bp.getSourcePackageName());
                 it.remove();
-            } else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) {
-                if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {
-                    Slog.i(TAG, "Removing old permission: " + bp.name
-                            + " from package " + bp.sourcePackage);
+            } else if (changingPkg != null && changingPkg.equals(bp.getSourcePackageName())) {
+                if (pkgInfo == null || !hasPermission(pkgInfo, bp.getName())) {
+                    Slog.i(TAG, "Removing old permission: " + bp.getName()
+                            + " from package " + bp.getSourcePackageName());
                     flags |= UPDATE_PERMISSIONS_ALL;
                     it.remove();
                 }
@@ -12951,7 +12759,7 @@
                 Log.i(TAG, "Package " + pkg.packageName + " checking " + name + ": " + bp);
             }
 
-            if (bp == null || bp.packageSetting == null) {
+            if (bp == null || bp.getSourcePackageSetting() == null) {
                 if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {
                     if (DEBUG_PERMISSIONS) {
                         Slog.i(TAG, "Unknown permission " + name
@@ -12965,7 +12773,7 @@
             // Limit ephemeral apps to ephemeral allowed permissions.
             if (pkg.applicationInfo.isInstantApp() && !bp.isInstant()) {
                 if (DEBUG_PERMISSIONS) {
-                    Log.i(TAG, "Denying non-ephemeral permission " + bp.name + " for package "
+                    Log.i(TAG, "Denying non-ephemeral permission " + bp.getName() + " for package "
                             + pkg.packageName);
                 }
                 continue;
@@ -12973,64 +12781,57 @@
 
             if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) {
                 if (DEBUG_PERMISSIONS) {
-                    Log.i(TAG, "Denying runtime-only permission " + bp.name + " for package "
+                    Log.i(TAG, "Denying runtime-only permission " + bp.getName() + " for package "
                             + pkg.packageName);
                 }
                 continue;
             }
 
-            final String perm = bp.name;
+            final String perm = bp.getName();
             boolean allowedSig = false;
             int grant = GRANT_DENIED;
 
             // Keep track of app op permissions.
-            if ((bp.protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0) {
-                ArraySet<String> pkgs = mAppOpPermissionPackages.get(bp.name);
+            if (bp.isAppOp()) {
+                ArraySet<String> pkgs = mAppOpPermissionPackages.get(perm);
                 if (pkgs == null) {
                     pkgs = new ArraySet<>();
-                    mAppOpPermissionPackages.put(bp.name, pkgs);
+                    mAppOpPermissionPackages.put(perm, pkgs);
                 }
                 pkgs.add(pkg.packageName);
             }
 
-            final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
-            switch (level) {
-                case PermissionInfo.PROTECTION_NORMAL: {
-                    // For all apps normal permissions are install time ones.
+            if (bp.isNormal()) {
+                // For all apps normal permissions are install time ones.
+                grant = GRANT_INSTALL;
+            } else if (bp.isRuntime()) {
+                // If a permission review is required for legacy apps we represent
+                // their permissions as always granted runtime ones since we need
+                // to keep the review required permission flag per user while an
+                // install permission's state is shared across all users.
+                if (!appSupportsRuntimePermissions && !mPermissionReviewRequired) {
+                    // For legacy apps dangerous permissions are install time ones.
                     grant = GRANT_INSTALL;
-                } break;
-
-                case PermissionInfo.PROTECTION_DANGEROUS: {
-                    // If a permission review is required for legacy apps we represent
-                    // their permissions as always granted runtime ones since we need
-                    // to keep the review required permission flag per user while an
-                    // install permission's state is shared across all users.
-                    if (!appSupportsRuntimePermissions && !mPermissionReviewRequired) {
-                        // For legacy apps dangerous permissions are install time ones.
-                        grant = GRANT_INSTALL;
-                    } else if (origPermissions.hasInstallPermission(bp.name)) {
-                        // For legacy apps that became modern, install becomes runtime.
-                        grant = GRANT_UPGRADE;
-                    } else if (mPromoteSystemApps
-                            && isSystemApp(ps)
-                            && mExistingSystemPackages.contains(ps.name)) {
-                        // For legacy system apps, install becomes runtime.
-                        // We cannot check hasInstallPermission() for system apps since those
-                        // permissions were granted implicitly and not persisted pre-M.
-                        grant = GRANT_UPGRADE;
-                    } else {
-                        // For modern apps keep runtime permissions unchanged.
-                        grant = GRANT_RUNTIME;
-                    }
-                } break;
-
-                case PermissionInfo.PROTECTION_SIGNATURE: {
-                    // For all apps signature permissions are install time ones.
-                    allowedSig = grantSignaturePermission(perm, pkg, bp, origPermissions);
-                    if (allowedSig) {
-                        grant = GRANT_INSTALL;
-                    }
-                } break;
+                } else if (origPermissions.hasInstallPermission(bp.getName())) {
+                    // For legacy apps that became modern, install becomes runtime.
+                    grant = GRANT_UPGRADE;
+                } else if (mPromoteSystemApps
+                        && isSystemApp(ps)
+                        && mExistingSystemPackages.contains(ps.name)) {
+                    // For legacy system apps, install becomes runtime.
+                    // We cannot check hasInstallPermission() for system apps since those
+                    // permissions were granted implicitly and not persisted pre-M.
+                    grant = GRANT_UPGRADE;
+                } else {
+                    // For modern apps keep runtime permissions unchanged.
+                    grant = GRANT_RUNTIME;
+                }
+            } else if (bp.isSignature()) {
+                // For all apps signature permissions are install time ones.
+                allowedSig = grantSignaturePermission(perm, pkg, bp, origPermissions);
+                if (allowedSig) {
+                    grant = GRANT_INSTALL;
+                }
             }
 
             if (DEBUG_PERMISSIONS) {
@@ -13059,7 +12860,7 @@
                         // for legacy apps
                         for (int userId : UserManagerService.getInstance().getUserIds()) {
                             if (origPermissions.getRuntimePermissionState(
-                                    bp.name, userId) != null) {
+                                    perm, userId) != null) {
                                 // Revoke the runtime permission and clear the flags.
                                 origPermissions.revokeRuntimePermission(bp, userId);
                                 origPermissions.updatePermissionFlags(bp, userId,
@@ -13080,10 +12881,10 @@
                         // Grant previously granted runtime permissions.
                         for (int userId : UserManagerService.getInstance().getUserIds()) {
                             PermissionState permissionState = origPermissions
-                                    .getRuntimePermissionState(bp.name, userId);
+                                    .getRuntimePermissionState(perm, userId);
                             int flags = permissionState != null
                                     ? permissionState.getFlags() : 0;
-                            if (origPermissions.hasRuntimePermission(bp.name, userId)) {
+                            if (origPermissions.hasRuntimePermission(perm, userId)) {
                                 // Don't propagate the permission in a permission review mode if
                                 // the former was revoked, i.e. marked to not propagate on upgrade.
                                 // Note that in a permission review mode install permissions are
@@ -13126,7 +12927,7 @@
                                 // permissions as these are the only ones the platform knows
                                 // how to disable the API to simulate revocation as legacy
                                 // apps don't expect to run with revoked permissions.
-                                if (PLATFORM_PACKAGE_NAME.equals(bp.sourcePackage)) {
+                                if (PLATFORM_PACKAGE_NAME.equals(bp.getSourcePackageName())) {
                                     if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
                                         flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
                                         // We changed the flags, hence have to write.
@@ -13149,7 +12950,7 @@
                     case GRANT_UPGRADE: {
                         // Grant runtime permissions for a previously held install permission.
                         PermissionState permissionState = origPermissions
-                                .getInstallPermissionState(bp.name);
+                                .getInstallPermissionState(perm);
                         final int flags = permissionState != null ? permissionState.getFlags() : 0;
 
                         if (origPermissions.revokeInstallPermission(bp)
@@ -13197,10 +12998,10 @@
                     changedInstallPermission = true;
                     Slog.i(TAG, "Un-granting permission " + perm
                             + " from package " + pkg.packageName
-                            + " (protectionLevel=" + bp.protectionLevel
+                            + " (protectionLevel=" + bp.getProtectionLevel()
                             + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
                             + ")");
-                } else if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) == 0) {
+                } else if (bp.isAppOp()) {
                     // Don't print warning for app op permissions, since it is fine for them
                     // not to be granted, there is a UI for the user to decide.
                     if (DEBUG_PERMISSIONS
@@ -13208,7 +13009,7 @@
                                     || packageOfInterest.equals(pkg.packageName))) {
                         Slog.i(TAG, "Not granting permission " + perm
                                 + " to package " + pkg.packageName
-                                + " (protectionLevel=" + bp.protectionLevel
+                                + " (protectionLevel=" + bp.getProtectionLevel()
                                 + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
                                 + ")");
                     }
@@ -13268,13 +13069,11 @@
 
     private boolean grantSignaturePermission(String perm, PackageParser.Package pkg,
             BasePermission bp, PermissionsState origPermissions) {
-        boolean oemPermission = (bp.protectionLevel
-                & PermissionInfo.PROTECTION_FLAG_OEM) != 0;
-        boolean privilegedPermission = (bp.protectionLevel
-                & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0;
+        boolean oemPermission = bp.isOEM();
+        boolean privilegedPermission = bp.isPrivileged();
         boolean privappPermissionsDisable =
                 RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE;
-        boolean platformPermission = PLATFORM_PACKAGE_NAME.equals(bp.sourcePackage);
+        boolean platformPermission = PLATFORM_PACKAGE_NAME.equals(bp.getSourcePackageName());
         boolean platformPackage = PLATFORM_PACKAGE_NAME.equals(pkg.packageName);
         if (!privappPermissionsDisable && privilegedPermission && pkg.isPrivilegedApp()
                 && !platformPackage && platformPermission) {
@@ -13303,7 +13102,7 @@
             }
         }
         boolean allowed = (compareSignatures(
-                bp.packageSetting.signatures.mSignatures, pkg.mSignatures)
+                bp.getSourcePackageSetting().signatures.mSignatures, pkg.mSignatures)
                         == PackageManager.SIGNATURE_MATCH)
                 || (compareSignatures(mPlatformPackage.mSignatures, pkg.mSignatures)
                         == PackageManager.SIGNATURE_MATCH);
@@ -13380,39 +13179,37 @@
             }
         }
         if (!allowed) {
-            if (!allowed && (bp.protectionLevel
-                    & PermissionInfo.PROTECTION_FLAG_PRE23) != 0
+            if (!allowed
+                    && bp.isPre23()
                     && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
                 // If this was a previously normal/dangerous permission that got moved
                 // to a system permission as part of the runtime permission redesign, then
                 // we still want to blindly grant it to old apps.
                 allowed = true;
             }
-            if (!allowed && (bp.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTALLER) != 0
+            if (!allowed && bp.isInstaller()
                     && pkg.packageName.equals(mRequiredInstallerPackage)) {
                 // If this permission is to be granted to the system installer and
                 // this app is an installer, then it gets the permission.
                 allowed = true;
             }
-            if (!allowed && (bp.protectionLevel & PermissionInfo.PROTECTION_FLAG_VERIFIER) != 0
+            if (!allowed && bp.isVerifier()
                     && pkg.packageName.equals(mRequiredVerifierPackage)) {
                 // If this permission is to be granted to the system verifier and
                 // this app is a verifier, then it gets the permission.
                 allowed = true;
             }
-            if (!allowed && (bp.protectionLevel
-                    & PermissionInfo.PROTECTION_FLAG_PREINSTALLED) != 0
+            if (!allowed && bp.isPreInstalled()
                     && isSystemApp(pkg)) {
                 // Any pre-installed system app is allowed to get this permission.
                 allowed = true;
             }
-            if (!allowed && (bp.protectionLevel
-                    & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) {
+            if (!allowed && bp.isDevelopment()) {
                 // For development permissions, a development permission
                 // is granted only if it was already granted.
                 allowed = origPermissions.hasInstallPermission(perm);
             }
-            if (!allowed && (bp.protectionLevel & PermissionInfo.PROTECTION_FLAG_SETUP) != 0
+            if (!allowed && bp.isSetup()
                     && pkg.packageName.equals(mSetupWizardPackage)) {
                 // If this permission is to be granted to the system setup wizard and
                 // this app is a setup wizard, then it gets the permission.
@@ -17621,9 +17418,9 @@
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
     }
 
-    private boolean shouldCheckUpgradeKeySetLP(PackageSetting oldPs, int scanFlags) {
+    private boolean shouldCheckUpgradeKeySetLP(PackageSettingBase oldPs, int scanFlags) {
         // Can't rotate keys during boot or if sharedUser.
-        if (oldPs == null || (scanFlags&SCAN_INITIAL) != 0 || oldPs.sharedUser != null
+        if (oldPs == null || (scanFlags&SCAN_INITIAL) != 0 || oldPs.isSharedUser()
                 || !oldPs.keySetData.isUsingUpgradeKeySets()) {
             return false;
         }
@@ -17643,7 +17440,7 @@
         return true;
     }
 
-    private boolean checkUpgradeKeySetLP(PackageSetting oldPS, PackageParser.Package newPkg) {
+    private boolean checkUpgradeKeySetLP(PackageSettingBase oldPS, PackageParser.Package newPkg) {
         // Upgrade keysets are being used.  Determine if new package has a superset of the
         // required keys.
         long[] upgradeKeySets = oldPS.keySetData.getUpgradeKeySets();
@@ -18697,25 +18494,26 @@
                     // also includes the "updating the same package" case, of course.
                     // "updating same package" could also involve key-rotation.
                     final boolean sigsOk;
-                    if (bp.sourcePackage.equals(pkg.packageName)
-                            && (bp.packageSetting instanceof PackageSetting)
-                            && (shouldCheckUpgradeKeySetLP((PackageSetting) bp.packageSetting,
+                    final String sourcePackageName = bp.getSourcePackageName();
+                    final PackageSettingBase sourcePackageSetting = bp.getSourcePackageSetting();
+                    if (sourcePackageName.equals(pkg.packageName)
+                            && (shouldCheckUpgradeKeySetLP(sourcePackageSetting,
                                     scanFlags))) {
-                        sigsOk = checkUpgradeKeySetLP((PackageSetting) bp.packageSetting, pkg);
+                        sigsOk = checkUpgradeKeySetLP(sourcePackageSetting, pkg);
                     } else {
-                        sigsOk = compareSignatures(bp.packageSetting.signatures.mSignatures,
+                        sigsOk = compareSignatures(sourcePackageSetting.signatures.mSignatures,
                                 pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
                     }
                     if (!sigsOk) {
                         // If the owning package is the system itself, we log but allow
                         // install to proceed; we fail the install on all other permission
                         // redefinitions.
-                        if (!bp.sourcePackage.equals("android")) {
+                        if (!sourcePackageName.equals("android")) {
                             res.setError(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
                                     + pkg.packageName + " attempting to redeclare permission "
-                                    + perm.info.name + " already owned by " + bp.sourcePackage);
+                                    + perm.info.name + " already owned by " + sourcePackageName);
                             res.origPermission = perm.info.name;
-                            res.origPackage = bp.sourcePackage;
+                            res.origPackage = sourcePackageName;
                             return;
                         } else {
                             Slog.w(TAG, "Package " + pkg.packageName
@@ -18734,7 +18532,7 @@
                                 Slog.w(TAG, "Package " + pkg.packageName + " trying to change a "
                                         + "non-runtime permission " + perm.info.name
                                         + " to runtime; keeping old protection level");
-                                perm.info.protectionLevel = bp.protectionLevel;
+                                perm.info.protectionLevel = bp.getProtectionLevel();
                             }
                         }
                     }
@@ -20573,9 +20371,8 @@
 
         final int permissionCount = ps.pkg.requestedPermissions.size();
         for (int i = 0; i < permissionCount; i++) {
-            String permission = ps.pkg.requestedPermissions.get(i);
-
-            BasePermission bp = mSettings.mPermissions.get(permission);
+            final String permissionName = ps.pkg.requestedPermissions.get(i);
+            final BasePermission bp = mSettings.mPermissions.get(permissionName);
             if (bp == null) {
                 continue;
             }
@@ -20587,7 +20384,7 @@
                 for (int j = 0; j < packageCount; j++) {
                     PackageSetting pkg = ps.sharedUser.packages.valueAt(j);
                     if (pkg.pkg != null && !pkg.pkg.packageName.equals(ps.pkg.packageName)
-                            && pkg.pkg.requestedPermissions.contains(permission)) {
+                            && pkg.pkg.requestedPermissions.contains(permissionName)) {
                         used = true;
                         break;
                     }
@@ -20597,13 +20394,13 @@
                 }
             }
 
-            PermissionsState permissionsState = ps.getPermissionsState();
+            final PermissionsState permissionsState = ps.getPermissionsState();
 
-            final int oldFlags = permissionsState.getPermissionFlags(bp.name, userId);
+            final int oldFlags = permissionsState.getPermissionFlags(permissionName, userId);
 
             // Always clear the user settable flags.
-            final boolean hasInstallState = permissionsState.getInstallPermissionState(
-                    bp.name) != null;
+            final boolean hasInstallState =
+                    permissionsState.getInstallPermissionState(permissionName) != null;
             // If permission review is enabled and this is a legacy app, mark the
             // permission as requiring a review as this is the initial state.
             int flags = 0;
@@ -22459,85 +22256,6 @@
         return buf.toString();
     }
 
-    static class DumpState {
-        public static final int DUMP_LIBS = 1 << 0;
-        public static final int DUMP_FEATURES = 1 << 1;
-        public static final int DUMP_ACTIVITY_RESOLVERS = 1 << 2;
-        public static final int DUMP_SERVICE_RESOLVERS = 1 << 3;
-        public static final int DUMP_RECEIVER_RESOLVERS = 1 << 4;
-        public static final int DUMP_CONTENT_RESOLVERS = 1 << 5;
-        public static final int DUMP_PERMISSIONS = 1 << 6;
-        public static final int DUMP_PACKAGES = 1 << 7;
-        public static final int DUMP_SHARED_USERS = 1 << 8;
-        public static final int DUMP_MESSAGES = 1 << 9;
-        public static final int DUMP_PROVIDERS = 1 << 10;
-        public static final int DUMP_VERIFIERS = 1 << 11;
-        public static final int DUMP_PREFERRED = 1 << 12;
-        public static final int DUMP_PREFERRED_XML = 1 << 13;
-        public static final int DUMP_KEYSETS = 1 << 14;
-        public static final int DUMP_VERSION = 1 << 15;
-        public static final int DUMP_INSTALLS = 1 << 16;
-        public static final int DUMP_INTENT_FILTER_VERIFIERS = 1 << 17;
-        public static final int DUMP_DOMAIN_PREFERRED = 1 << 18;
-        public static final int DUMP_FROZEN = 1 << 19;
-        public static final int DUMP_DEXOPT = 1 << 20;
-        public static final int DUMP_COMPILER_STATS = 1 << 21;
-        public static final int DUMP_CHANGES = 1 << 22;
-        public static final int DUMP_VOLUMES = 1 << 23;
-
-        public static final int OPTION_SHOW_FILTERS = 1 << 0;
-
-        private int mTypes;
-
-        private int mOptions;
-
-        private boolean mTitlePrinted;
-
-        private SharedUserSetting mSharedUser;
-
-        public boolean isDumping(int type) {
-            if (mTypes == 0 && type != DUMP_PREFERRED_XML) {
-                return true;
-            }
-
-            return (mTypes & type) != 0;
-        }
-
-        public void setDump(int type) {
-            mTypes |= type;
-        }
-
-        public boolean isOptionEnabled(int option) {
-            return (mOptions & option) != 0;
-        }
-
-        public void setOptionEnabled(int option) {
-            mOptions |= option;
-        }
-
-        public boolean onTitlePrinted() {
-            final boolean printed = mTitlePrinted;
-            mTitlePrinted = true;
-            return printed;
-        }
-
-        public boolean getTitlePrinted() {
-            return mTitlePrinted;
-        }
-
-        public void setTitlePrinted(boolean enabled) {
-            mTitlePrinted = enabled;
-        }
-
-        public SharedUserSetting getSharedUser() {
-            return mSharedUser;
-        }
-
-        public void setSharedUser(SharedUserSetting user) {
-            mSharedUser = user;
-        }
-    }
-
     @Override
     public void onShellCommand(FileDescriptor in, FileDescriptor out,
             FileDescriptor err, String[] args, ShellCallback callback,
@@ -24867,7 +24585,8 @@
             synchronized (mPackages) {
                 if (mSettings.mReadExternalStorageEnforced == null
                         || mSettings.mReadExternalStorageEnforced != enforced) {
-                    mSettings.mReadExternalStorageEnforced = enforced;
+                    mSettings.mReadExternalStorageEnforced =
+                            enforced ? Boolean.TRUE : Boolean.FALSE;
                     mSettings.writeLPr();
                 }
             }
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 52bf641..88fe3c1 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -103,6 +103,7 @@
         sharedUserId = orig.sharedUserId;
     }
 
+    @Override
     public PermissionsState getPermissionsState() {
         return (sharedUser != null)
                 ? sharedUser.getPermissionsState()
@@ -125,6 +126,7 @@
         return (pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0;
     }
 
+    @Override
     public boolean isSharedUser() {
         return sharedUser != null;
     }
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index d3ca1fd..0d4878f 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -24,14 +24,12 @@
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageUserState;
-import android.os.storage.VolumeInfo;
 import android.service.pm.PackageProto;
 import android.util.ArraySet;
 import android.util.SparseArray;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.google.android.collect.Lists;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -42,7 +40,7 @@
 /**
  * Settings base class for pending and resolved classes.
  */
-abstract class PackageSettingBase extends SettingBase {
+public abstract class PackageSettingBase extends SettingBase {
 
     private static final int[] EMPTY_INT_ARRAY = new int[0];
 
@@ -230,6 +228,9 @@
         return updateAvailable;
     }
 
+    public boolean isSharedUser() {
+        return false;
+    }
     /**
      * Makes a shallow copy of the given package settings.
      *
diff --git a/services/core/java/com/android/server/pm/PermissionsState.java b/services/core/java/com/android/server/pm/PermissionsState.java
index f4d2ad2..8b42a99 100644
--- a/services/core/java/com/android/server/pm/PermissionsState.java
+++ b/services/core/java/com/android/server/pm/PermissionsState.java
@@ -24,6 +24,7 @@
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import com.android.internal.util.ArrayUtils;
+import com.android.server.pm.permission.BasePermission;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -406,7 +407,7 @@
             ensurePermissionData(permission);
         }
 
-        PermissionData permissionData = mPermissions.get(permission.name);
+        PermissionData permissionData = mPermissions.get(permission.getName());
         if (permissionData == null) {
             if (!mayChangeFlags) {
                 return false;
@@ -557,7 +558,7 @@
     }
 
     private int grantPermission(BasePermission permission, int userId) {
-        if (hasPermission(permission.name, userId)) {
+        if (hasPermission(permission.getName(), userId)) {
             return PERMISSION_OPERATION_FAILURE;
         }
 
@@ -581,21 +582,22 @@
     }
 
     private int revokePermission(BasePermission permission, int userId) {
-        if (!hasPermission(permission.name, userId)) {
+        final String permName = permission.getName();
+        if (!hasPermission(permName, userId)) {
             return PERMISSION_OPERATION_FAILURE;
         }
 
         final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
         final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
 
-        PermissionData permissionData = mPermissions.get(permission.name);
+        PermissionData permissionData = mPermissions.get(permName);
 
         if (!permissionData.revoke(userId)) {
             return PERMISSION_OPERATION_FAILURE;
         }
 
         if (permissionData.isDefault()) {
-            ensureNoPermissionData(permission.name);
+            ensureNoPermissionData(permName);
         }
 
         if (hasGids) {
@@ -625,13 +627,14 @@
     }
 
     private PermissionData ensurePermissionData(BasePermission permission) {
+        final String permName = permission.getName();
         if (mPermissions == null) {
             mPermissions = new ArrayMap<>();
         }
-        PermissionData permissionData = mPermissions.get(permission.name);
+        PermissionData permissionData = mPermissions.get(permName);
         if (permissionData == null) {
             permissionData = new PermissionData(permission);
-            mPermissions.put(permission.name, permissionData);
+            mPermissions.put(permName, permissionData);
         }
         return permissionData;
     }
@@ -692,7 +695,7 @@
 
             PermissionState userState = mUserStates.get(userId);
             if (userState == null) {
-                userState = new PermissionState(mPerm.name);
+                userState = new PermissionState(mPerm.getName());
                 mUserStates.put(userId, userState);
             }
 
@@ -760,7 +763,7 @@
                 }
                 return userState.mFlags != oldFlags;
             } else if (newFlags != 0) {
-                userState = new PermissionState(mPerm.name);
+                userState = new PermissionState(mPerm.getName());
                 userState.mFlags = newFlags;
                 mUserStates.put(userId, userState);
                 return true;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 51d3e10..06cf79a 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -16,7 +16,6 @@
 
 package com.android.server.pm;
 
-import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
@@ -64,7 +63,6 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.storage.StorageManager;
-import android.os.storage.VolumeInfo;
 import android.service.pm.PackageServiceDumpProto;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -87,10 +85,9 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.JournaledFile;
 import com.android.internal.util.XmlUtils;
-import com.android.server.backup.PreferredActivityBackupHelper;
 import com.android.server.pm.Installer.InstallerException;
-import com.android.server.pm.PackageManagerService.DumpState;
 import com.android.server.pm.PermissionsState.PermissionState;
+import com.android.server.pm.permission.BasePermission;
 
 import libcore.io.IoUtils;
 
@@ -127,7 +124,7 @@
 /**
  * Holds information about dynamic settings.
  */
-final class Settings {
+public final class Settings {
     private static final String TAG = "PackageSettings";
 
     /**
@@ -176,7 +173,7 @@
     private static final String TAG_READ_EXTERNAL_STORAGE = "read-external-storage";
     private static final String ATTR_ENFORCEMENT = "enforcement";
 
-    private static final String TAG_ITEM = "item";
+    public static final String TAG_ITEM = "item";
     private static final String TAG_DISABLED_COMPONENTS = "disabled-components";
     private static final String TAG_ENABLED_COMPONENTS = "enabled-components";
     private static final String TAG_PACKAGE_RESTRICTIONS = "package-restrictions";
@@ -201,7 +198,8 @@
     private static final String TAG_DEFAULT_DIALER = "default-dialer";
     private static final String TAG_VERSION = "version";
 
-    private static final String ATTR_NAME = "name";
+    public static final String ATTR_NAME = "name";
+    public static final String ATTR_PACKAGE = "package";
     private static final String ATTR_USER = "user";
     private static final String ATTR_CODE = "code";
     private static final String ATTR_GRANTED = "granted";
@@ -233,7 +231,6 @@
     private static final String ATTR_VOLUME_UUID = "volumeUuid";
     private static final String ATTR_SDK_VERSION = "sdkVersion";
     private static final String ATTR_DATABASE_VERSION = "databaseVersion";
-    private static final String ATTR_DONE = "done";
 
     // Bookkeeping for restored permission grants
     private static final String TAG_RESTORED_RUNTIME_PERMISSIONS = "restored-perms";
@@ -665,26 +662,13 @@
     }
 
     // Transfer ownership of permissions from one package to another.
-    void transferPermissionsLPw(String origPkg, String newPkg) {
+    void transferPermissionsLPw(String origPackageName, String newPackageName) {
         // Transfer ownership of permissions to the new package.
         for (int i=0; i<2; i++) {
             ArrayMap<String, BasePermission> permissions =
                     i == 0 ? mPermissionTrees : mPermissions;
             for (BasePermission bp : permissions.values()) {
-                if (origPkg.equals(bp.sourcePackage)) {
-                    if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG,
-                            "Moving permission " + bp.name
-                            + " from pkg " + bp.sourcePackage
-                            + " to " + newPkg);
-                    bp.sourcePackage = newPkg;
-                    bp.packageSetting = null;
-                    bp.perm = null;
-                    if (bp.pendingInfo != null) {
-                        bp.pendingInfo.packageName = newPkg;
-                    }
-                    bp.uid = 0;
-                    bp.setGids(null, false);
-                }
+                bp.transfer(origPackageName, newPackageName);
             }
         }
     }
@@ -2022,8 +2006,7 @@
 
     // Specifically for backup/restore
     public void processRestoredPermissionGrantLPr(String pkgName, String permission,
-            boolean isGranted, int restoredFlagSet, int userId)
-            throws IOException, XmlPullParserException {
+            boolean isGranted, int restoredFlagSet, int userId) {
         mRuntimePermissionsPersistence.rememberRestoredUserGrantLPr(
                 pkgName, permission, isGranted, restoredFlagSet, userId);
     }
@@ -2605,9 +2588,6 @@
             writeAllRuntimePermissionsLPr();
             return;
 
-        } catch(XmlPullParserException e) {
-            Slog.wtf(PackageManagerService.TAG, "Unable to write package manager settings, "
-                    + "current changes will be lost at reboot", e);
         } catch(java.io.IOException e) {
             Slog.wtf(PackageManagerService.TAG, "Unable to write package manager settings, "
                     + "current changes will be lost at reboot", e);
@@ -2951,7 +2931,6 @@
 
     void writeUpgradeKeySetsLPr(XmlSerializer serializer,
             PackageKeySetData data) throws IOException {
-        long properSigning = data.getProperSigningKeySet();
         if (data.isUsingUpgradeKeySets()) {
             for (long id : data.getUpgradeKeySets()) {
                 serializer.startTag(null, "upgrade-keyset");
@@ -2971,32 +2950,8 @@
         }
     }
 
-    void writePermissionLPr(XmlSerializer serializer, BasePermission bp)
-            throws XmlPullParserException, java.io.IOException {
-        if (bp.sourcePackage != null) {
-            serializer.startTag(null, TAG_ITEM);
-            serializer.attribute(null, ATTR_NAME, bp.name);
-            serializer.attribute(null, "package", bp.sourcePackage);
-            if (bp.protectionLevel != PermissionInfo.PROTECTION_NORMAL) {
-                serializer.attribute(null, "protection", Integer.toString(bp.protectionLevel));
-            }
-            if (PackageManagerService.DEBUG_SETTINGS)
-                Log.v(PackageManagerService.TAG, "Writing perm: name=" + bp.name + " type="
-                        + bp.type);
-            if (bp.type == BasePermission.TYPE_DYNAMIC) {
-                final PermissionInfo pi = bp.perm != null ? bp.perm.info : bp.pendingInfo;
-                if (pi != null) {
-                    serializer.attribute(null, "type", "dynamic");
-                    if (pi.icon != 0) {
-                        serializer.attribute(null, "icon", Integer.toString(pi.icon));
-                    }
-                    if (pi.nonLocalizedLabel != null) {
-                        serializer.attribute(null, "label", pi.nonLocalizedLabel.toString());
-                    }
-                }
-            }
-            serializer.endTag(null, TAG_ITEM);
-        }
+    void writePermissionLPr(XmlSerializer serializer, BasePermission bp) throws IOException {
+        bp.writeLPr(serializer);
     }
 
     ArrayList<PackageSetting> getListOfIncompleteInstallPackagesLPr() {
@@ -3169,7 +3124,8 @@
                     }
                 } else if (TAG_READ_EXTERNAL_STORAGE.equals(tagName)) {
                     final String enforcement = parser.getAttributeValue(null, ATTR_ENFORCEMENT);
-                    mReadExternalStorageEnforced = "1".equals(enforcement);
+                    mReadExternalStorageEnforced =
+                            "1".equals(enforcement) ? Boolean.TRUE : Boolean.FALSE;
                 } else if (tagName.equals("keyset-settings")) {
                     mKeySetManagerService.readKeySetsLPw(parser, mKeySetRefs);
                 } else if (TAG_VERSION.equals(tagName)) {
@@ -3593,22 +3549,6 @@
         }
     }
 
-    private int readInt(XmlPullParser parser, String ns, String name, int defValue) {
-        String v = parser.getAttributeValue(ns, name);
-        try {
-            if (v == null) {
-                return defValue;
-            }
-            return Integer.parseInt(v);
-        } catch (NumberFormatException e) {
-            PackageManagerService.reportSettingsProblem(Log.WARN,
-                    "Error in package manager settings: attribute " + name
-                            + " has bad integer value " + v + " at "
-                            + parser.getPositionDescription());
-        }
-        return defValue;
-    }
-
     private void readPermissionsLPw(ArrayMap<String, BasePermission> out, XmlPullParser parser)
             throws IOException, XmlPullParserException {
         int outerDepth = parser.getDepth();
@@ -3619,38 +3559,7 @@
                 continue;
             }
 
-            final String tagName = parser.getName();
-            if (tagName.equals(TAG_ITEM)) {
-                final String name = parser.getAttributeValue(null, ATTR_NAME);
-                final String sourcePackage = parser.getAttributeValue(null, "package");
-                final String ptype = parser.getAttributeValue(null, "type");
-                if (name != null && sourcePackage != null) {
-                    final boolean dynamic = "dynamic".equals(ptype);
-                    BasePermission bp = out.get(name);
-                    // If the permission is builtin, do not clobber it.
-                    if (bp == null || bp.type != BasePermission.TYPE_BUILTIN) {
-                        bp = new BasePermission(name.intern(), sourcePackage,
-                                dynamic ? BasePermission.TYPE_DYNAMIC : BasePermission.TYPE_NORMAL);
-                    }
-                    bp.protectionLevel = readInt(parser, null, "protection",
-                            PermissionInfo.PROTECTION_NORMAL);
-                    bp.protectionLevel = PermissionInfo.fixProtectionLevel(bp.protectionLevel);
-                    if (dynamic) {
-                        PermissionInfo pi = new PermissionInfo();
-                        pi.packageName = sourcePackage.intern();
-                        pi.name = name.intern();
-                        pi.icon = readInt(parser, null, "icon", 0);
-                        pi.nonLocalizedLabel = parser.getAttributeValue(null, "label");
-                        pi.protectionLevel = bp.protectionLevel;
-                        bp.pendingInfo = pi;
-                    }
-                    out.put(bp.name, bp);
-                } else {
-                    PackageManagerService.reportSettingsProblem(Log.WARN,
-                            "Error in package manager settings: permissions has" + " no name at "
-                                    + parser.getPositionDescription());
-                }
-            } else {
+            if (!BasePermission.readLPw(out, parser)) {
                 PackageManagerService.reportSettingsProblem(Log.WARN,
                         "Unknown element reading permissions: " + parser.getName() + " at "
                                 + parser.getPositionDescription());
@@ -4385,10 +4294,6 @@
         return ps;
     }
 
-    private String compToString(ArraySet<String> cmp) {
-        return cmp != null ? Arrays.toString(cmp.toArray()) : "[]";
-    }
-
     boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, int flags, int userId) {
         final PackageSetting ps = mPackages.get(componentInfo.packageName);
         if (ps == null) return false;
@@ -5002,43 +4907,9 @@
     void dumpPermissionsLPr(PrintWriter pw, String packageName, ArraySet<String> permissionNames,
             DumpState dumpState) {
         boolean printedSomething = false;
-        for (BasePermission p : mPermissions.values()) {
-            if (packageName != null && !packageName.equals(p.sourcePackage)) {
-                continue;
-            }
-            if (permissionNames != null && !permissionNames.contains(p.name)) {
-                continue;
-            }
-            if (!printedSomething) {
-                if (dumpState.onTitlePrinted())
-                    pw.println();
-                pw.println("Permissions:");
-                printedSomething = true;
-            }
-            pw.print("  Permission ["); pw.print(p.name); pw.print("] (");
-                    pw.print(Integer.toHexString(System.identityHashCode(p)));
-                    pw.println("):");
-            pw.print("    sourcePackage="); pw.println(p.sourcePackage);
-            pw.print("    uid="); pw.print(p.uid);
-                    pw.print(" gids="); pw.print(Arrays.toString(
-                            p.computeGids(UserHandle.USER_SYSTEM)));
-                    pw.print(" type="); pw.print(p.type);
-                    pw.print(" prot=");
-                    pw.println(PermissionInfo.protectionToString(p.protectionLevel));
-            if (p.perm != null) {
-                pw.print("    perm="); pw.println(p.perm);
-                if ((p.perm.info.flags & PermissionInfo.FLAG_INSTALLED) == 0
-                        || (p.perm.info.flags & PermissionInfo.FLAG_REMOVED) != 0) {
-                    pw.print("    flags=0x"); pw.println(Integer.toHexString(p.perm.info.flags));
-                }
-            }
-            if (p.packageSetting != null) {
-                pw.print("    packageSetting="); pw.println(p.packageSetting);
-            }
-            if (READ_EXTERNAL_STORAGE.equals(p.name)) {
-                pw.print("    enforced=");
-                pw.println(mReadExternalStorageEnforced);
-            }
+        for (BasePermission bp : mPermissions.values()) {
+            printedSomething = bp.dumpPermissionsLPr(pw, packageName, permissionNames,
+                    mReadExternalStorageEnforced == Boolean.TRUE, printedSomething, dumpState);
         }
     }
 
@@ -5248,7 +5119,7 @@
 
         private final Handler mHandler = new MyHandler();
 
-        private final Object mLock;
+        private final Object mPersistenceLock;
 
         @GuardedBy("mLock")
         private final SparseBooleanArray mWriteScheduled = new SparseBooleanArray();
@@ -5265,8 +5136,8 @@
         // The mapping keys are user ids.
         private final SparseBooleanArray mDefaultPermissionsGranted = new SparseBooleanArray();
 
-        public RuntimePermissionPersistence(Object lock) {
-            mLock = lock;
+        public RuntimePermissionPersistence(Object persistenceLock) {
+            mPersistenceLock = persistenceLock;
         }
 
         public boolean areDefaultRuntimPermissionsGrantedLPr(int userId) {
@@ -5321,7 +5192,7 @@
             ArrayMap<String, List<PermissionState>> permissionsForPackage = new ArrayMap<>();
             ArrayMap<String, List<PermissionState>> permissionsForSharedUser = new ArrayMap<>();
 
-            synchronized (mLock) {
+            synchronized (mPersistenceLock) {
                 mWriteScheduled.delete(userId);
 
                 final int packageCount = mPackages.size();
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
new file mode 100644
index 0000000..09a6e9c
--- /dev/null
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -0,0 +1,564 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.permission;
+
+import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
+import static android.content.pm.PermissionInfo.PROTECTION_NORMAL;
+import static android.content.pm.PermissionInfo.PROTECTION_SIGNATURE;
+import static android.content.pm.PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM;
+
+import static com.android.server.pm.Settings.ATTR_NAME;
+import static com.android.server.pm.Settings.ATTR_PACKAGE;
+import static com.android.server.pm.Settings.TAG_ITEM;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.Permission;
+import android.content.pm.PermissionInfo;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.server.pm.DumpState;
+import com.android.server.pm.PackageManagerService;
+import com.android.server.pm.PackageSettingBase;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+public final class BasePermission {
+    static final String TAG = "PackageManager";
+
+    public static final int TYPE_NORMAL = 0;
+    public static final int TYPE_BUILTIN = 1;
+    public static final int TYPE_DYNAMIC = 2;
+    @IntDef(value = {
+        TYPE_NORMAL,
+        TYPE_BUILTIN,
+        TYPE_DYNAMIC,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PermissionType {}
+
+    @IntDef(value = {
+        PROTECTION_DANGEROUS,
+        PROTECTION_NORMAL,
+        PROTECTION_SIGNATURE,
+        PROTECTION_SIGNATURE_OR_SYSTEM,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ProtectionLevel {}
+
+    final String name;
+
+    @PermissionType final int type;
+
+    String sourcePackageName;
+
+    // TODO: Can we get rid of this? Seems we only use some signature info from the setting
+    PackageSettingBase sourcePackageSetting;
+
+    int protectionLevel;
+
+    PackageParser.Permission perm;
+
+    PermissionInfo pendingPermissionInfo;
+
+    /** UID that owns the definition of this permission */
+    int uid;
+
+    /** Additional GIDs given to apps granted this permission */
+    private int[] gids;
+
+    /**
+     * Flag indicating that {@link #gids} should be adjusted based on the
+     * {@link UserHandle} the granted app is running as.
+     */
+    private boolean perUser;
+
+    public BasePermission(String _name, String _sourcePackageName, @PermissionType int _type) {
+        name = _name;
+        sourcePackageName = _sourcePackageName;
+        type = _type;
+        // Default to most conservative protection level.
+        protectionLevel = PermissionInfo.PROTECTION_SIGNATURE;
+    }
+
+    @Override
+    public String toString() {
+        return "BasePermission{" + Integer.toHexString(System.identityHashCode(this)) + " " + name
+                + "}";
+    }
+
+    public String getName() {
+        return name;
+    }
+    public int getProtectionLevel() {
+        return protectionLevel;
+    }
+    public String getSourcePackageName() {
+        return sourcePackageName;
+    }
+    public PackageSettingBase getSourcePackageSetting() {
+        return sourcePackageSetting;
+    }
+    public int getType() {
+        return type;
+    }
+    public int getUid() {
+        return uid;
+    }
+    public void setGids(int[] gids, boolean perUser) {
+        this.gids = gids;
+        this.perUser = perUser;
+    }
+    public void setPermission(@Nullable Permission perm) {
+        this.perm = perm;
+    }
+    public void setSourcePackageSetting(PackageSettingBase sourcePackageSetting) {
+        this.sourcePackageSetting = sourcePackageSetting;
+    }
+
+    public int[] computeGids(int userId) {
+        if (perUser) {
+            final int[] userGids = new int[gids.length];
+            for (int i = 0; i < gids.length; i++) {
+                userGids[i] = UserHandle.getUid(userId, gids[i]);
+            }
+            return userGids;
+        } else {
+            return gids;
+        }
+    }
+
+    public int calculateFootprint(BasePermission perm) {
+        if (uid == perm.uid) {
+            return perm.name.length() + perm.perm.info.calculateFootprint();
+        }
+        return 0;
+    }
+
+    public boolean isPermission(Permission perm) {
+        return this.perm == perm;
+    }
+
+    public boolean isDynamic() {
+        return type == TYPE_DYNAMIC;
+    }
+
+
+    public boolean isNormal() {
+        return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
+                == PermissionInfo.PROTECTION_NORMAL;
+    }
+    public boolean isRuntime() {
+        return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
+                == PermissionInfo.PROTECTION_DANGEROUS;
+    }
+    public boolean isSignature() {
+        return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) ==
+                PermissionInfo.PROTECTION_SIGNATURE;
+    }
+
+    public boolean isAppOp() {
+        return (protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0;
+    }
+    public boolean isDevelopment() {
+        return isSignature()
+                && (protectionLevel & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0;
+    }
+    public boolean isInstaller() {
+        return (protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTALLER) != 0;
+    }
+    public boolean isInstant() {
+        return (protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0;
+    }
+    public boolean isOEM() {
+        return (protectionLevel & PermissionInfo.PROTECTION_FLAG_OEM) != 0;
+    }
+    public boolean isPre23() {
+        return (protectionLevel & PermissionInfo.PROTECTION_FLAG_PRE23) != 0;
+    }
+    public boolean isPreInstalled() {
+        return (protectionLevel & PermissionInfo.PROTECTION_FLAG_PREINSTALLED) != 0;
+    }
+    public boolean isPrivileged() {
+        return (protectionLevel & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0;
+    }
+    public boolean isRuntimeOnly() {
+        return (protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) != 0;
+    }
+    public boolean isSetup() {
+        return (protectionLevel & PermissionInfo.PROTECTION_FLAG_SETUP) != 0;
+    }
+    public boolean isVerifier() {
+        return (protectionLevel & PermissionInfo.PROTECTION_FLAG_VERIFIER) != 0;
+    }
+
+    public void transfer(@NonNull String origPackageName, @NonNull String newPackageName) {
+        if (!origPackageName.equals(sourcePackageName)) {
+            return;
+        }
+        sourcePackageName = newPackageName;
+        sourcePackageSetting = null;
+        perm = null;
+        if (pendingPermissionInfo != null) {
+            pendingPermissionInfo.packageName = newPackageName;
+        }
+        uid = 0;
+        setGids(null, false);
+    }
+
+    public boolean addToTree(@ProtectionLevel int protectionLevel,
+            @NonNull PermissionInfo info, @NonNull BasePermission tree) {
+        final boolean changed =
+                (this.protectionLevel != protectionLevel
+                    || perm == null
+                    || uid != tree.uid
+                    || !perm.owner.equals(tree.perm.owner)
+                    || !comparePermissionInfos(perm.info, info));
+        this.protectionLevel = protectionLevel;
+        info = new PermissionInfo(info);
+        info.protectionLevel = protectionLevel;
+        perm = new PackageParser.Permission(tree.perm.owner, info);
+        perm.info.packageName = tree.perm.info.packageName;
+        uid = tree.uid;
+        return changed;
+    }
+
+    public void updateDynamicPermission(Map<String, BasePermission> permissionTrees) {
+        if (PackageManagerService.DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name="
+                + getName() + " pkg=" + getSourcePackageName()
+                + " info=" + pendingPermissionInfo);
+        if (sourcePackageSetting == null && pendingPermissionInfo != null) {
+            final BasePermission tree = findPermissionTreeLP(permissionTrees, name);
+            if (tree != null && tree.perm != null) {
+                sourcePackageSetting = tree.sourcePackageSetting;
+                perm = new PackageParser.Permission(tree.perm.owner,
+                        new PermissionInfo(pendingPermissionInfo));
+                perm.info.packageName = tree.perm.info.packageName;
+                perm.info.name = name;
+                uid = tree.uid;
+            }
+        }
+    }
+
+    public static BasePermission createOrUpdate(@Nullable BasePermission bp, @NonNull Permission p,
+            @NonNull PackageParser.Package pkg, Map<String, BasePermission> permissionTrees,
+            boolean chatty) {
+        final PackageSettingBase pkgSetting = (PackageSettingBase) pkg.mExtras;
+        // Allow system apps to redefine non-system permissions
+        if (bp != null && !Objects.equals(bp.sourcePackageName, p.info.packageName)) {
+            final boolean currentOwnerIsSystem = (bp.perm != null
+                    && bp.perm.owner.isSystemApp());
+            if (p.owner.isSystemApp()) {
+                if (bp.type == BasePermission.TYPE_BUILTIN && bp.perm == null) {
+                    // It's a built-in permission and no owner, take ownership now
+                    bp.sourcePackageSetting = pkgSetting;
+                    bp.perm = p;
+                    bp.uid = pkg.applicationInfo.uid;
+                    bp.sourcePackageName = p.info.packageName;
+                    p.info.flags |= PermissionInfo.FLAG_INSTALLED;
+                } else if (!currentOwnerIsSystem) {
+                    String msg = "New decl " + p.owner + " of permission  "
+                            + p.info.name + " is system; overriding " + bp.sourcePackageName;
+                    PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+                    bp = null;
+                }
+            }
+        }
+        if (bp == null) {
+            bp = new BasePermission(p.info.name, p.info.packageName, TYPE_NORMAL);
+        }
+        StringBuilder r = null;
+        if (bp.perm == null) {
+            if (bp.sourcePackageName == null
+                    || bp.sourcePackageName.equals(p.info.packageName)) {
+                final BasePermission tree = findPermissionTreeLP(permissionTrees, p.info.name);
+                if (tree == null
+                        || tree.sourcePackageName.equals(p.info.packageName)) {
+                    bp.sourcePackageSetting = pkgSetting;
+                    bp.perm = p;
+                    bp.uid = pkg.applicationInfo.uid;
+                    bp.sourcePackageName = p.info.packageName;
+                    p.info.flags |= PermissionInfo.FLAG_INSTALLED;
+                    if (chatty) {
+                        if (r == null) {
+                            r = new StringBuilder(256);
+                        } else {
+                            r.append(' ');
+                        }
+                        r.append(p.info.name);
+                    }
+                } else {
+                    Slog.w(TAG, "Permission " + p.info.name + " from package "
+                            + p.info.packageName + " ignored: base tree "
+                            + tree.name + " is from package "
+                            + tree.sourcePackageName);
+                }
+            } else {
+                Slog.w(TAG, "Permission " + p.info.name + " from package "
+                        + p.info.packageName + " ignored: original from "
+                        + bp.sourcePackageName);
+            }
+        } else if (chatty) {
+            if (r == null) {
+                r = new StringBuilder(256);
+            } else {
+                r.append(' ');
+            }
+            r.append("DUP:");
+            r.append(p.info.name);
+        }
+        if (bp.perm == p) {
+            bp.protectionLevel = p.info.protectionLevel;
+        }
+        if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) {
+            Log.d(TAG, "  Permissions: " + r);
+        }
+        return bp;
+    }
+
+    public static BasePermission enforcePermissionTreeLP(
+            Map<String, BasePermission> permissionTrees, String permName, int callingUid) {
+        if (permName != null) {
+            BasePermission bp = findPermissionTreeLP(permissionTrees, permName);
+            if (bp != null) {
+                if (bp.uid == UserHandle.getAppId(callingUid)) {//UserHandle.getAppId(Binder.getCallingUid())) {
+                    return bp;
+                }
+                throw new SecurityException("Calling uid " + callingUid
+                        + " is not allowed to add to permission tree "
+                        + bp.name + " owned by uid " + bp.uid);
+            }
+        }
+        throw new SecurityException("No permission tree found for " + permName);
+    }
+
+    public void enforceDeclaredUsedAndRuntimeOrDevelopment(PackageParser.Package pkg) {
+        int index = pkg.requestedPermissions.indexOf(name);
+        if (index == -1) {
+            throw new SecurityException("Package " + pkg.packageName
+                    + " has not requested permission " + name);
+        }
+        if (!isRuntime() && !isDevelopment()) {
+            throw new SecurityException("Permission " + name
+                    + " is not a changeable permission type");
+        }
+    }
+
+    private static BasePermission findPermissionTreeLP(
+            Map<String, BasePermission> permissionTrees, String permName) {
+        for (BasePermission bp : permissionTrees.values()) {
+            if (permName.startsWith(bp.name) &&
+                    permName.length() > bp.name.length() &&
+                    permName.charAt(bp.name.length()) == '.') {
+                return bp;
+            }
+        }
+        return null;
+    }
+
+    public @Nullable PermissionInfo generatePermissionInfo(@NonNull String groupName, int flags) {
+        if (groupName == null) {
+            if (perm == null || perm.info.group == null) {
+                return generatePermissionInfo(protectionLevel, flags);
+            }
+        } else {
+            if (perm != null && groupName.equals(perm.info.group)) {
+                return PackageParser.generatePermissionInfo(perm, flags);
+            }
+        }
+        return null;
+    }
+
+    public @NonNull PermissionInfo generatePermissionInfo(int adjustedProtectionLevel, int flags) {
+        final boolean protectionLevelChanged = protectionLevel != adjustedProtectionLevel;
+        // if we return different protection level, don't use the cached info
+        if (perm != null && !protectionLevelChanged) {
+            return PackageParser.generatePermissionInfo(perm, flags);
+        }
+        final PermissionInfo pi = new PermissionInfo();
+        pi.name = name;
+        pi.packageName = sourcePackageName;
+        pi.nonLocalizedLabel = name;
+        pi.protectionLevel = protectionLevelChanged ? adjustedProtectionLevel : protectionLevel;
+        return pi;
+    }
+
+    public static boolean readLPw(@NonNull Map<String, BasePermission> out,
+            @NonNull XmlPullParser parser) {
+        final String tagName = parser.getName();
+        if (!tagName.equals(TAG_ITEM)) {
+            return false;
+        }
+        final String name = parser.getAttributeValue(null, ATTR_NAME);
+        final String sourcePackage = parser.getAttributeValue(null, ATTR_PACKAGE);
+        final String ptype = parser.getAttributeValue(null, "type");
+        if (name == null || sourcePackage == null) {
+            PackageManagerService.reportSettingsProblem(Log.WARN,
+                    "Error in package manager settings: permissions has" + " no name at "
+                            + parser.getPositionDescription());
+            return false;
+        }
+        final boolean dynamic = "dynamic".equals(ptype);
+        BasePermission bp = out.get(name);
+        // If the permission is builtin, do not clobber it.
+        if (bp == null || bp.type != TYPE_BUILTIN) {
+            bp = new BasePermission(name.intern(), sourcePackage,
+                    dynamic ? TYPE_DYNAMIC : TYPE_NORMAL);
+        }
+        bp.protectionLevel = readInt(parser, null, "protection",
+                PermissionInfo.PROTECTION_NORMAL);
+        bp.protectionLevel = PermissionInfo.fixProtectionLevel(bp.protectionLevel);
+        if (dynamic) {
+            final PermissionInfo pi = new PermissionInfo();
+            pi.packageName = sourcePackage.intern();
+            pi.name = name.intern();
+            pi.icon = readInt(parser, null, "icon", 0);
+            pi.nonLocalizedLabel = parser.getAttributeValue(null, "label");
+            pi.protectionLevel = bp.protectionLevel;
+            bp.pendingPermissionInfo = pi;
+        }
+        out.put(bp.name, bp);
+        return true;
+    }
+
+    private static int readInt(XmlPullParser parser, String ns, String name, int defValue) {
+        String v = parser.getAttributeValue(ns, name);
+        try {
+            if (v == null) {
+                return defValue;
+            }
+            return Integer.parseInt(v);
+        } catch (NumberFormatException e) {
+            PackageManagerService.reportSettingsProblem(Log.WARN,
+                    "Error in package manager settings: attribute " + name
+                            + " has bad integer value " + v + " at "
+                            + parser.getPositionDescription());
+        }
+        return defValue;
+    }
+
+    public void writeLPr(@NonNull XmlSerializer serializer) throws IOException {
+        if (sourcePackageName == null) {
+            return;
+        }
+        serializer.startTag(null, TAG_ITEM);
+        serializer.attribute(null, ATTR_NAME, name);
+        serializer.attribute(null, ATTR_PACKAGE, sourcePackageName);
+        if (protectionLevel != PermissionInfo.PROTECTION_NORMAL) {
+            serializer.attribute(null, "protection", Integer.toString(protectionLevel));
+        }
+        if (type == BasePermission.TYPE_DYNAMIC) {
+            final PermissionInfo pi = perm != null ? perm.info : pendingPermissionInfo;
+            if (pi != null) {
+                serializer.attribute(null, "type", "dynamic");
+                if (pi.icon != 0) {
+                    serializer.attribute(null, "icon", Integer.toString(pi.icon));
+                }
+                if (pi.nonLocalizedLabel != null) {
+                    serializer.attribute(null, "label", pi.nonLocalizedLabel.toString());
+                }
+            }
+        }
+        serializer.endTag(null, TAG_ITEM);
+    }
+
+    private static boolean compareStrings(CharSequence s1, CharSequence s2) {
+        if (s1 == null) {
+            return s2 == null;
+        }
+        if (s2 == null) {
+            return false;
+        }
+        if (s1.getClass() != s2.getClass()) {
+            return false;
+        }
+        return s1.equals(s2);
+    }
+
+    private static boolean comparePermissionInfos(PermissionInfo pi1, PermissionInfo pi2) {
+        if (pi1.icon != pi2.icon) return false;
+        if (pi1.logo != pi2.logo) return false;
+        if (pi1.protectionLevel != pi2.protectionLevel) return false;
+        if (!compareStrings(pi1.name, pi2.name)) return false;
+        if (!compareStrings(pi1.nonLocalizedLabel, pi2.nonLocalizedLabel)) return false;
+        // We'll take care of setting this one.
+        if (!compareStrings(pi1.packageName, pi2.packageName)) return false;
+        // These are not currently stored in settings.
+        //if (!compareStrings(pi1.group, pi2.group)) return false;
+        //if (!compareStrings(pi1.nonLocalizedDescription, pi2.nonLocalizedDescription)) return false;
+        //if (pi1.labelRes != pi2.labelRes) return false;
+        //if (pi1.descriptionRes != pi2.descriptionRes) return false;
+        return true;
+    }
+
+    public boolean dumpPermissionsLPr(@NonNull PrintWriter pw, @NonNull String packageName,
+            @NonNull Set<String> permissionNames, boolean readEnforced,
+            boolean printedSomething, @NonNull DumpState dumpState) {
+        if (packageName != null && !packageName.equals(sourcePackageName)) {
+            return false;
+        }
+        if (permissionNames != null && !permissionNames.contains(name)) {
+            return false;
+        }
+        if (!printedSomething) {
+            if (dumpState.onTitlePrinted())
+                pw.println();
+            pw.println("Permissions:");
+            printedSomething = true;
+        }
+        pw.print("  Permission ["); pw.print(name); pw.print("] (");
+                pw.print(Integer.toHexString(System.identityHashCode(this)));
+                pw.println("):");
+        pw.print("    sourcePackage="); pw.println(sourcePackageName);
+        pw.print("    uid="); pw.print(uid);
+                pw.print(" gids="); pw.print(Arrays.toString(
+                        computeGids(UserHandle.USER_SYSTEM)));
+                pw.print(" type="); pw.print(type);
+                pw.print(" prot=");
+                pw.println(PermissionInfo.protectionToString(protectionLevel));
+        if (perm != null) {
+            pw.print("    perm="); pw.println(perm);
+            if ((perm.info.flags & PermissionInfo.FLAG_INSTALLED) == 0
+                    || (perm.info.flags & PermissionInfo.FLAG_REMOVED) != 0) {
+                pw.print("    flags=0x"); pw.println(Integer.toHexString(perm.info.flags));
+            }
+        }
+        if (sourcePackageSetting != null) {
+            pw.print("    packageSetting="); pw.println(sourcePackageSetting);
+        }
+        if (READ_EXTERNAL_STORAGE.equals(name)) {
+            pw.print("    enforced=");
+            pw.println(readEnforced);
+        }
+        return true;
+    }
+}