Add new OEM permission flavor

The new OEM permission flavor of signature protected perissions
can be granted only to apps on the OEM partition if they are:

 1. Signed as the one declaring the permission

 2. The requesting app is on OEM partition of the system image and
    declares the permission used and the OEM explicitly granted this
    permission by adding an entry in /oem/permission/*.xml
    with the following format:

    <permissions>
        <oem-permissions package="foo.bar.baz">
            <permission name="android.permission.ACCESS_FOO" granted="true"/>
        </oem-permissions>
    </permissions>

All OEM permissions requested by any app on the OEM partition
must be declared granted or not to force the OEM making a well
though out explicit choice. If that condidtion is not met the
system server restarts - this prevents shipping a device with
OEM permissions for which no opition was explicitly expressed.

Normal apps requesting an OEM permission has no effect, i.e the
permission is only granted on a signature match.

Change-Id: I345bb0b56368ee03e4bd768faab540ee4e0571ae
Bug: 65497745
Test: Manual
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 664bcbca..d73f852 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -586,24 +586,32 @@
      */
     public static final int PRIVATE_FLAG_VIRTUAL_PRELOAD = 1 << 16;
 
+    /**
+     * Value for {@linl #privateFlags}: whether this app is pre-installed on the
+     * OEM partition of the system image.
+     * @hide
+     */
+    public static final int PRIVATE_FLAG_OEM = 1 << 17;
+
     /** @hide */
     @IntDef(flag = true, prefix = { "PRIVATE_FLAG_" }, value = {
-            PRIVATE_FLAG_HIDDEN,
+            PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE,
+            PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION,
+            PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE,
+            PRIVATE_FLAG_BACKUP_IN_FOREGROUND,
             PRIVATE_FLAG_CANT_SAVE_STATE,
-            PRIVATE_FLAG_FORWARD_LOCK,
-            PRIVATE_FLAG_PRIVILEGED,
-            PRIVATE_FLAG_HAS_DOMAIN_URLS,
             PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE,
             PRIVATE_FLAG_DIRECT_BOOT_AWARE,
+            PRIVATE_FLAG_FORWARD_LOCK,
+            PRIVATE_FLAG_HAS_DOMAIN_URLS,
+            PRIVATE_FLAG_HIDDEN,
             PRIVATE_FLAG_INSTANT,
-            PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE,
-            PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER,
-            PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE,
-            PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE,
-            PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION,
-            PRIVATE_FLAG_BACKUP_IN_FOREGROUND,
-            PRIVATE_FLAG_STATIC_SHARED_LIBRARY,
             PRIVATE_FLAG_ISOLATED_SPLIT_LOADING,
+            PRIVATE_FLAG_OEM,
+            PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE,
+            PRIVATE_FLAG_PRIVILEGED,
+            PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER,
+            PRIVATE_FLAG_STATIC_SHARED_LIBRARY,
             PRIVATE_FLAG_VIRTUAL_PRELOAD,
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -1557,6 +1565,13 @@
     /**
      * @hide
      */
+    public boolean isOem() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
+    }
+
+    /**
+     * @hide
+     */
     @Override protected ApplicationInfo getApplicationInfo() {
         return this;
     }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 8b54b0d..6c7c8a07 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -96,8 +96,8 @@
 import com.android.internal.util.XmlUtils;
 
 import libcore.io.IoUtils;
-
 import libcore.util.EmptyArray;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -815,21 +815,22 @@
         }
     }
 
-    public final static int PARSE_IS_SYSTEM = 1<<0;
-    public final static int PARSE_CHATTY = 1<<1;
-    public final static int PARSE_MUST_BE_APK = 1<<2;
-    public final static int PARSE_IGNORE_PROCESSES = 1<<3;
-    public final static int PARSE_FORWARD_LOCK = 1<<4;
-    public final static int PARSE_EXTERNAL_STORAGE = 1<<5;
-    public final static int PARSE_IS_SYSTEM_DIR = 1<<6;
-    public final static int PARSE_IS_PRIVILEGED = 1<<7;
-    public final static int PARSE_COLLECT_CERTIFICATES = 1<<8;
-    public final static int PARSE_TRUSTED_OVERLAY = 1<<9;
-    public final static int PARSE_ENFORCE_CODE = 1<<10;
+    public static final int PARSE_IS_SYSTEM = 1 << 0;
+    public static final int PARSE_CHATTY = 1 << 1;
+    public static final int PARSE_MUST_BE_APK = 1 << 2;
+    public static final int PARSE_IGNORE_PROCESSES = 1 << 3;
+    public static final int PARSE_FORWARD_LOCK = 1 << 4;
+    public static final int PARSE_EXTERNAL_STORAGE = 1 << 5;
+    public static final int PARSE_IS_SYSTEM_DIR = 1 << 6;
+    public static final int PARSE_IS_PRIVILEGED = 1 << 7;
+    public static final int PARSE_COLLECT_CERTIFICATES = 1 << 8;
+    public static final int PARSE_TRUSTED_OVERLAY = 1 << 9;
+    public static final int PARSE_ENFORCE_CODE = 1 << 10;
     /** @deprecated remove when fixing b/34761192 */
     @Deprecated
-    public final static int PARSE_IS_EPHEMERAL = 1<<11;
-    public final static int PARSE_FORCE_SDK = 1<<12;
+    public static final int PARSE_IS_EPHEMERAL = 1 << 11;
+    public static final int PARSE_FORCE_SDK = 1 << 12;
+    public static final int PARSE_IS_OEM = 1 << 13;
 
     private static final Comparator<String> sSplitNameComparator = new SplitNameComparator();
 
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index b84c1b9..17b4f87 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -17,7 +17,6 @@
 package android.content.pm;
 
 import android.annotation.SystemApi;
-import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -135,6 +134,16 @@
     public static final int PROTECTION_FLAG_RUNTIME_ONLY = 0x2000;
 
     /**
+     * Additional flag for {@link #protectionLevel}, corresponding
+     * to the <code>oem</code> value of
+     * {@link android.R.attr#protectionLevel}.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int PROTECTION_FLAG_OEM = 0x4000;
+
+    /**
      * Mask for {@link #protectionLevel}: the basic protection type.
      */
     public static final int PROTECTION_MASK_BASE = 0xf;
@@ -222,7 +231,7 @@
     /** @hide */
     public static String protectionToString(int level) {
         String protLevel = "????";
-        switch (level&PROTECTION_MASK_BASE) {
+        switch (level & PROTECTION_MASK_BASE) {
             case PermissionInfo.PROTECTION_DANGEROUS:
                 protLevel = "dangerous";
                 break;
@@ -236,36 +245,39 @@
                 protLevel = "signatureOrSystem";
                 break;
         }
-        if ((level&PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0) {
+        if ((level & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0) {
             protLevel += "|privileged";
         }
-        if ((level&PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) {
+        if ((level & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) {
             protLevel += "|development";
         }
-        if ((level&PermissionInfo.PROTECTION_FLAG_APPOP) != 0) {
+        if ((level & PermissionInfo.PROTECTION_FLAG_APPOP) != 0) {
             protLevel += "|appop";
         }
-        if ((level&PermissionInfo.PROTECTION_FLAG_PRE23) != 0) {
+        if ((level & PermissionInfo.PROTECTION_FLAG_PRE23) != 0) {
             protLevel += "|pre23";
         }
-        if ((level&PermissionInfo.PROTECTION_FLAG_INSTALLER) != 0) {
+        if ((level & PermissionInfo.PROTECTION_FLAG_INSTALLER) != 0) {
             protLevel += "|installer";
         }
-        if ((level&PermissionInfo.PROTECTION_FLAG_VERIFIER) != 0) {
+        if ((level & PermissionInfo.PROTECTION_FLAG_VERIFIER) != 0) {
             protLevel += "|verifier";
         }
-        if ((level&PermissionInfo.PROTECTION_FLAG_PREINSTALLED) != 0) {
+        if ((level & PermissionInfo.PROTECTION_FLAG_PREINSTALLED) != 0) {
             protLevel += "|preinstalled";
         }
-        if ((level&PermissionInfo.PROTECTION_FLAG_SETUP) != 0) {
+        if ((level & PermissionInfo.PROTECTION_FLAG_SETUP) != 0) {
             protLevel += "|setup";
         }
-        if ((level&PermissionInfo.PROTECTION_FLAG_INSTANT) != 0) {
+        if ((level & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0) {
             protLevel += "|instant";
         }
-        if ((level&PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) != 0) {
+        if ((level & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) != 0) {
             protLevel += "|runtime";
         }
+        if ((level & PermissionInfo.PROTECTION_FLAG_OEM) != 0) {
+            protLevel += "|oem";
+        }
         return protLevel;
     }
 
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 7778892..b5031f2 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -44,7 +44,9 @@
 import java.io.FileReader;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Loads global system configuration info.
@@ -60,6 +62,7 @@
     private static final int ALLOW_PERMISSIONS = 0x04;
     private static final int ALLOW_APP_CONFIGS = 0x08;
     private static final int ALLOW_PRIVAPP_PERMISSIONS = 0x10;
+    private static final int ALLOW_OEM_PERMISSIONS = 0x20;
     private static final int ALLOW_ALL = ~0;
 
     // Group-ids that are given to all packages as read from etc/permissions/*.xml.
@@ -143,6 +146,8 @@
     final ArrayMap<String, ArraySet<String>> mPrivAppPermissions = new ArrayMap<>();
     final ArrayMap<String, ArraySet<String>> mPrivAppDenyPermissions = new ArrayMap<>();
 
+    final ArrayMap<String, ArrayMap<String, Boolean>> mOemPermissions = new ArrayMap<>();
+
     public static SystemConfig getInstance() {
         synchronized (SystemConfig.class) {
             if (sInstance == null) {
@@ -224,13 +229,23 @@
         return mPrivAppDenyPermissions.get(packageName);
     }
 
+    public Map<String, Boolean> getOemPermissions(String packageName) {
+        final Map<String, Boolean> oemPermissions = mOemPermissions.get(packageName);
+        if (oemPermissions != null) {
+            return oemPermissions;
+        }
+        return Collections.emptyMap();
+    }
+
     SystemConfig() {
         // Read configuration from system
         readPermissions(Environment.buildPath(
                 Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);
+
         // Read configuration from the old permissions dir
         readPermissions(Environment.buildPath(
                 Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);
+
         // Allow Vendor to customize system configs around libs, features, permissions and apps
         int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS |
                 ALLOW_APP_CONFIGS;
@@ -238,17 +253,20 @@
                 Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag);
         readPermissions(Environment.buildPath(
                 Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);
+
         // Allow ODM to customize system configs around libs, features and apps
         int odmPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_APP_CONFIGS;
         readPermissions(Environment.buildPath(
                 Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);
         readPermissions(Environment.buildPath(
                 Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag);
-        // Only allow OEM to customize features
+
+        // Allow OEM to customize features and OEM permissions
+        int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS;
         readPermissions(Environment.buildPath(
-                Environment.getOemDirectory(), "etc", "sysconfig"), ALLOW_FEATURES);
+                Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag);
         readPermissions(Environment.buildPath(
-                Environment.getOemDirectory(), "etc", "permissions"), ALLOW_FEATURES);
+                Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag);
     }
 
     void readPermissions(File libraryDir, int permissionFlag) {
@@ -327,6 +345,7 @@
             boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0;
             boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0;
             boolean allowPrivappPermissions = (permissionFlag & ALLOW_PRIVAPP_PERMISSIONS) != 0;
+            boolean allowOemPermissions = (permissionFlag & ALLOW_OEM_PERMISSIONS) != 0;
             while (true) {
                 XmlUtils.nextElement(parser);
                 if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
@@ -569,6 +588,8 @@
                     XmlUtils.skipCurrentTag(parser);
                 } else if ("privapp-permissions".equals(name) && allowPrivappPermissions) {
                     readPrivAppPermissions(parser);
+                } else if ("oem-permissions".equals(name) && allowOemPermissions) {
+                    readOemPermissions(parser);
                 } else {
                     XmlUtils.skipCurrentTag(parser);
                     continue;
@@ -695,4 +716,40 @@
             mPrivAppDenyPermissions.put(packageName, denyPermissions);
         }
     }
+
+    void readOemPermissions(XmlPullParser parser) throws IOException, XmlPullParserException {
+        final String packageName = parser.getAttributeValue(null, "package");
+        if (TextUtils.isEmpty(packageName)) {
+            Slog.w(TAG, "package is required for <oem-permissions> in "
+                    + parser.getPositionDescription());
+            return;
+        }
+
+        ArrayMap<String, Boolean> permissions = mOemPermissions.get(packageName);
+        if (permissions == null) {
+            permissions = new ArrayMap<>();
+        }
+        final int depth = parser.getDepth();
+        while (XmlUtils.nextElementWithin(parser, depth)) {
+            final String name = parser.getName();
+            if ("permission".equals(name)) {
+                final String permName = parser.getAttributeValue(null, "name");
+                if (TextUtils.isEmpty(permName)) {
+                    Slog.w(TAG, "name is required for <permission> in "
+                            + parser.getPositionDescription());
+                    continue;
+                }
+                permissions.put(permName, Boolean.TRUE);
+            } else if ("deny-permission".equals(name)) {
+                String permName = parser.getAttributeValue(null, "name");
+                if (TextUtils.isEmpty(permName)) {
+                    Slog.w(TAG, "name is required for <deny-permission> in "
+                            + parser.getPositionDescription());
+                    continue;
+                }
+                permissions.put(permName, Boolean.FALSE);
+            }
+        }
+        mOemPermissions.put(packageName, permissions);
+    }
 }
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 793b5b2..e6c829f 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -249,6 +249,11 @@
              that target runtime permissions ({@link android.os.Build.VERSION_CODES#M} and above)
              -->
         <flag name="runtime" value="0x2000" />
+        <!-- Additional flag from base permission type: this permission can be granted only
+             if its protection level is signature, the requesting app resides on the OEM partition,
+             and the OEM has white-listed the app to receive this permission by the OEM.
+         -->
+        <flag name="oem" value="0x4000" />
     </attr>
 
     <!-- Flags indicating more context for a permission group. -->