Merge changes from topic "priv_vendor_app"

* changes:
  BIND_IMS_SERVICE is exposed to vendors
  Support privileged vendor apps
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index f6d9710..de6230c 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -638,8 +638,7 @@
         final String defaultSearchPaths = System.getProperty("java.library.path");
         final boolean treatVendorApkAsUnbundled = !defaultSearchPaths.contains("/vendor/lib");
         if (mApplicationInfo.getCodePath() != null
-                && mApplicationInfo.getCodePath().startsWith("/vendor/")
-                && treatVendorApkAsUnbundled) {
+                && mApplicationInfo.isVendor() && treatVendorApkAsUnbundled) {
             isBundledApp = false;
         }
 
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index edb27cd..5298f57 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -594,6 +594,13 @@
      */
     public static final int PRIVATE_FLAG_OEM = 1 << 17;
 
+    /**
+     * Value for {@linl #privateFlags}: whether this app is pre-installed on the
+     * vendor partition of the system image.
+     * @hide
+     */
+    public static final int PRIVATE_FLAG_VENDOR = 1 << 18;
+
     /** @hide */
     @IntDef(flag = true, prefix = { "PRIVATE_FLAG_" }, value = {
             PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE,
@@ -613,6 +620,7 @@
             PRIVATE_FLAG_PRIVILEGED,
             PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER,
             PRIVATE_FLAG_STATIC_SHARED_LIBRARY,
+            PRIVATE_FLAG_VENDOR,
             PRIVATE_FLAG_VIRTUAL_PRELOAD,
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -1569,6 +1577,11 @@
         return (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
     }
 
+    /** @hide */
+    public boolean isVendor() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
+    }
+
     /**
      * Returns whether or not this application was installed as a virtual preload.
      */
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index ebeaad7..98c824d 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -6267,6 +6267,11 @@
         }
 
         /** @hide */
+        public boolean isVendor() {
+            return applicationInfo.isVendor();
+        }
+
+        /** @hide */
         public boolean isPrivileged() {
             return applicationInfo.isPrivilegedApp();
         }
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 7588762..551d53b 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -144,6 +144,15 @@
     public static final int PROTECTION_FLAG_OEM = 0x4000;
 
     /**
+     * Additional flag for {${link #protectionLevel}, corresponding
+     * to the <code>vendorPrivileged</code> value of
+     * {@link android.R.attr#protectionLevel}.
+     *
+     * @hide
+     */
+    public static final int PROTECTION_FLAG_VENDOR_PRIVILEGED = 0x8000;
+
+    /**
      * Mask for {@link #protectionLevel}: the basic protection type.
      */
     public static final int PROTECTION_MASK_BASE = 0xf;
@@ -231,6 +240,12 @@
         if (level == PROTECTION_SIGNATURE_OR_SYSTEM) {
             level = PROTECTION_SIGNATURE | PROTECTION_FLAG_PRIVILEGED;
         }
+        if ((level & PROTECTION_FLAG_VENDOR_PRIVILEGED) != 0
+                && (level & PROTECTION_FLAG_PRIVILEGED) == 0) {
+            // 'vendorPrivileged' must be 'privileged'. If not,
+            // drop the vendorPrivileged.
+            level = level & ~PROTECTION_FLAG_VENDOR_PRIVILEGED;
+        }
         return level;
     }
 
@@ -284,6 +299,9 @@
         if ((level & PermissionInfo.PROTECTION_FLAG_OEM) != 0) {
             protLevel += "|oem";
         }
+        if ((level & PermissionInfo.PROTECTION_FLAG_VENDOR_PRIVILEGED) != 0) {
+            protLevel += "|vendorPrivileged";
+        }
         return protLevel;
     }
 
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index b5031f2..b7a6719 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -146,6 +146,9 @@
     final ArrayMap<String, ArraySet<String>> mPrivAppPermissions = new ArrayMap<>();
     final ArrayMap<String, ArraySet<String>> mPrivAppDenyPermissions = new ArrayMap<>();
 
+    final ArrayMap<String, ArraySet<String>> mVendorPrivAppPermissions = new ArrayMap<>();
+    final ArrayMap<String, ArraySet<String>> mVendorPrivAppDenyPermissions = new ArrayMap<>();
+
     final ArrayMap<String, ArrayMap<String, Boolean>> mOemPermissions = new ArrayMap<>();
 
     public static SystemConfig getInstance() {
@@ -229,6 +232,14 @@
         return mPrivAppDenyPermissions.get(packageName);
     }
 
+    public ArraySet<String> getVendorPrivAppPermissions(String packageName) {
+        return mVendorPrivAppPermissions.get(packageName);
+    }
+
+    public ArraySet<String> getVendorPrivAppDenyPermissions(String packageName) {
+        return mVendorPrivAppDenyPermissions.get(packageName);
+    }
+
     public Map<String, Boolean> getOemPermissions(String packageName) {
         final Map<String, Boolean> oemPermissions = mOemPermissions.get(packageName);
         if (oemPermissions != null) {
@@ -248,7 +259,7 @@
 
         // Allow Vendor to customize system configs around libs, features, permissions and apps
         int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS |
-                ALLOW_APP_CONFIGS;
+                ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS;
         readPermissions(Environment.buildPath(
                 Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag);
         readPermissions(Environment.buildPath(
@@ -587,7 +598,19 @@
                     }
                     XmlUtils.skipCurrentTag(parser);
                 } else if ("privapp-permissions".equals(name) && allowPrivappPermissions) {
-                    readPrivAppPermissions(parser);
+                    // privapp permissions from system and vendor partitions are stored
+                    // separately. This is to prevent xml files in the vendor partition from
+                    // granting permissions to priv apps in the system partition and vice
+                    // versa.
+                    boolean vendor = permFile.toPath().startsWith(
+                            Environment.getVendorDirectory().toPath());
+                    if (vendor) {
+                        readPrivAppPermissions(parser, mVendorPrivAppPermissions,
+                                mVendorPrivAppDenyPermissions);
+                    } else {
+                        readPrivAppPermissions(parser, mPrivAppPermissions,
+                                mPrivAppDenyPermissions);
+                    }
                 } else if ("oem-permissions".equals(name) && allowOemPermissions) {
                     readOemPermissions(parser);
                 } else {
@@ -674,7 +697,10 @@
         }
     }
 
-    void readPrivAppPermissions(XmlPullParser parser) throws IOException, XmlPullParserException {
+    private void readPrivAppPermissions(XmlPullParser parser,
+            ArrayMap<String, ArraySet<String>> grantMap,
+            ArrayMap<String, ArraySet<String>> denyMap)
+            throws IOException, XmlPullParserException {
         String packageName = parser.getAttributeValue(null, "package");
         if (TextUtils.isEmpty(packageName)) {
             Slog.w(TAG, "package is required for <privapp-permissions> in "
@@ -682,11 +708,11 @@
             return;
         }
 
-        ArraySet<String> permissions = mPrivAppPermissions.get(packageName);
+        ArraySet<String> permissions = grantMap.get(packageName);
         if (permissions == null) {
             permissions = new ArraySet<>();
         }
-        ArraySet<String> denyPermissions = mPrivAppDenyPermissions.get(packageName);
+        ArraySet<String> denyPermissions = denyMap.get(packageName);
         int depth = parser.getDepth();
         while (XmlUtils.nextElementWithin(parser, depth)) {
             String name = parser.getName();
@@ -711,9 +737,9 @@
                 denyPermissions.add(permName);
             }
         }
-        mPrivAppPermissions.put(packageName, permissions);
+        grantMap.put(packageName, permissions);
         if (denyPermissions != null) {
-            mPrivAppDenyPermissions.put(packageName, denyPermissions);
+            denyMap.put(packageName, denyPermissions);
         }
     }
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5906b27..d9fb230 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1740,7 +1740,7 @@
          @hide
     -->
     <permission android:name="android.permission.BIND_IMS_SERVICE"
-        android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged|vendorPrivileged" />
 
     <!-- Allows an application to manage embedded subscriptions (those on a eUICC) through
          EuiccManager APIs.
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 4d410e5..4d67494 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -262,6 +262,9 @@
              and the OEM has white-listed the app to receive this permission by the OEM.
          -->
         <flag name="oem" value="0x4000" />
+        <!-- Additional flag from base permission type: this permission can be granted to
+             privileged apps in vendor partition. -->
+        <flag name="vendorPrivileged" value="0x8000" />
     </attr>
 
     <!-- Flags indicating more context for a permission group. -->
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0c6be32..4b6589c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -467,6 +467,7 @@
     static final int SCAN_AS_SYSTEM = 1<<17;
     static final int SCAN_AS_PRIVILEGED = 1<<18;
     static final int SCAN_AS_OEM = 1<<19;
+    static final int SCAN_AS_VENDOR = 1<<20;
 
     @IntDef(flag = true, prefix = { "SCAN_" }, value = {
             SCAN_NO_DEX,
@@ -2574,8 +2575,25 @@
                     | SCAN_AS_SYSTEM,
                     0);
 
-            // Collect all vendor packages.
-            File vendorAppDir = new File("/vendor/app");
+            // Collected privileged vendor packages.
+                File privilegedVendorAppDir = new File(Environment.getVendorDirectory(),
+                        "priv-app");
+            try {
+                privilegedVendorAppDir = privilegedVendorAppDir.getCanonicalFile();
+            } catch (IOException e) {
+                // failed to look up canonical path, continue with original one
+            }
+            scanDirTracedLI(privilegedVendorAppDir,
+                    mDefParseFlags
+                    | PackageParser.PARSE_IS_SYSTEM_DIR,
+                    scanFlags
+                    | SCAN_AS_SYSTEM
+                    | SCAN_AS_VENDOR
+                    | SCAN_AS_PRIVILEGED,
+                    0);
+
+            // Collect ordinary vendor packages.
+            File vendorAppDir = new File(Environment.getVendorDirectory(), "app");
             try {
                 vendorAppDir = vendorAppDir.getCanonicalFile();
             } catch (IOException e) {
@@ -2585,7 +2603,8 @@
                     mDefParseFlags
                     | PackageParser.PARSE_IS_SYSTEM_DIR,
                     scanFlags
-                    | SCAN_AS_SYSTEM,
+                    | SCAN_AS_SYSTEM
+                    | SCAN_AS_VENDOR,
                     0);
 
             // Collect all OEM packages.
@@ -2770,13 +2789,23 @@
                             rescanFlags =
                                     scanFlags
                                     | SCAN_AS_SYSTEM;
+                        } else if (FileUtils.contains(privilegedVendorAppDir, scanFile)) {
+                            reparseFlags =
+                                    mDefParseFlags |
+                                    PackageParser.PARSE_IS_SYSTEM_DIR;
+                            rescanFlags =
+                                    scanFlags
+                                    | SCAN_AS_SYSTEM
+                                    | SCAN_AS_VENDOR
+                                    | SCAN_AS_PRIVILEGED;
                         } else if (FileUtils.contains(vendorAppDir, scanFile)) {
                             reparseFlags =
                                     mDefParseFlags |
                                     PackageParser.PARSE_IS_SYSTEM_DIR;
                             rescanFlags =
                                     scanFlags
-                                    | SCAN_AS_SYSTEM;
+                                    | SCAN_AS_SYSTEM
+                                    | SCAN_AS_VENDOR;
                         } else if (FileUtils.contains(oemAppDir, scanFile)) {
                             reparseFlags =
                                     mDefParseFlags |
@@ -8335,6 +8364,13 @@
             } else {
                 updatedPs.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_OEM;
             }
+            // If new package is not located in "/vendor" (e.g. due to an OTA),
+            // it needs to drop FLAG_VENDOR.
+            if (locationIsVendor(pkg.codePath)) {
+                updatedPs.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_VENDOR;
+            } else {
+                updatedPs.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_VENDOR;
+            }
 
             if (ps != null && !ps.codePathString.equals(pkg.codePath)) {
                 // The path has changed from what was last scanned...  check the
@@ -8455,11 +8491,17 @@
                 scanFlags |= SCAN_AS_PRIVILEGED;
             }
 
-            // An updated OEM app will not have the PARSE_IS_OEM
+            // An updated OEM app will not have the SCAN_AS_OEM
             // flag set initially
             if ((updatedPs.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0) {
                 scanFlags |= SCAN_AS_OEM;
             }
+
+            // An updated vendor app will not have the SCAN_AS_VENDOR
+            // flag set initially
+            if ((updatedPs.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0) {
+                scanFlags |= SCAN_AS_VENDOR;
+            }
         }
 
         // Verify certificates against what was last scanned
@@ -10208,6 +10250,10 @@
             pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_OEM;
         }
 
+        if ((scanFlags & SCAN_AS_VENDOR) != 0) {
+            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VENDOR;
+        }
+
         if (!isSystemApp(pkg)) {
             // Only system apps can use these features.
             pkg.mOriginalPackages = null;
@@ -15583,18 +15629,22 @@
 
         boolean sysPkg = (isSystemApp(oldPackage));
         if (sysPkg) {
-            // Set the system/privileged/oem flags as needed
+            // Set the system/privileged/oem/vendor flags as needed
             final boolean privileged =
                     (oldPackage.applicationInfo.privateFlags
                             & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
             final boolean oem =
                     (oldPackage.applicationInfo.privateFlags
                             & ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
+            final boolean vendor =
+                    (oldPackage.applicationInfo.privateFlags
+                            & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
             final @ParseFlags int systemParseFlags = parseFlags;
             final @ScanFlags int systemScanFlags = scanFlags
                     | SCAN_AS_SYSTEM
                     | (privileged ? SCAN_AS_PRIVILEGED : 0)
-                    | (oem ? SCAN_AS_OEM : 0);
+                    | (oem ? SCAN_AS_OEM : 0)
+                    | (vendor ? SCAN_AS_VENDOR : 0);
 
             replaceSystemPackageLIF(oldPackage, pkg, systemParseFlags, systemScanFlags,
                     user, allUsers, installerPackageName, res, installReason);
@@ -16773,6 +16823,10 @@
         return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
     }
 
+    private static boolean isVendorApp(PackageParser.Package pkg) {
+        return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
+    }
+
     private static boolean hasDomainURLs(PackageParser.Package pkg) {
         return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0;
     }
@@ -17507,7 +17561,9 @@
     static boolean locationIsPrivileged(String path) {
         try {
             final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
-            return path.startsWith(privilegedAppDir.getCanonicalPath());
+            final File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app");
+            return path.startsWith(privilegedAppDir.getCanonicalPath())
+                    || path.startsWith(privilegedVendorAppDir.getCanonicalPath());
         } catch (IOException e) {
             Slog.e(TAG, "Unable to access code path " + path);
         }
@@ -17523,6 +17579,15 @@
         return false;
     }
 
+    static boolean locationIsVendor(String path) {
+        try {
+            return path.startsWith(Environment.getVendorDirectory().getCanonicalPath());
+        } catch (IOException e) {
+            Slog.e(TAG, "Unable to access code path " + path);
+        }
+        return false;
+    }
+
     /*
      * Tries to delete system package.
      */
@@ -17644,6 +17709,9 @@
         if (locationIsOem(codePathString)) {
             scanFlags |= SCAN_AS_OEM;
         }
+        if (locationIsVendor(codePathString)) {
+            scanFlags |= SCAN_AS_VENDOR;
+        }
 
         final File codePath = new File(codePathString);
         final PackageParser.Package pkg =
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 44f36d1..45b94a4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -1538,13 +1538,26 @@
         return 0;
     }
 
+    private boolean isVendorApp(String pkg) {
+        try {
+            final PackageInfo info = mInterface.getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM);
+            return info != null && info.applicationInfo.isVendor();
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
     private int runGetPrivappPermissions() {
         final String pkg = getNextArg();
         if (pkg == null) {
             getErrPrintWriter().println("Error: no package specified.");
             return 1;
         }
-        ArraySet<String> privAppPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg);
+
+        ArraySet<String> privAppPermissions = isVendorApp(pkg) ?
+                SystemConfig.getInstance().getVendorPrivAppPermissions(pkg)
+                    : SystemConfig.getInstance().getPrivAppPermissions(pkg);
+
         getOutPrintWriter().println(privAppPermissions == null
                 ? "{}" : privAppPermissions.toString());
         return 0;
@@ -1556,10 +1569,13 @@
             getErrPrintWriter().println("Error: no package specified.");
             return 1;
         }
-        ArraySet<String> privAppDenyPermissions =
-                SystemConfig.getInstance().getPrivAppDenyPermissions(pkg);
-        getOutPrintWriter().println(privAppDenyPermissions == null
-                ? "{}" : privAppDenyPermissions.toString());
+
+        ArraySet<String> privAppPermissions = isVendorApp(pkg) ?
+                SystemConfig.getInstance().getVendorPrivAppDenyPermissions(pkg)
+                    : SystemConfig.getInstance().getPrivAppDenyPermissions(pkg);
+
+        getOutPrintWriter().println(privAppPermissions == null
+                ? "{}" : privAppPermissions.toString());
         return 0;
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 3b414e9..258dd4d4 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -140,6 +140,10 @@
         return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
     }
 
+    public boolean isVendor() {
+        return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
+    }
+
     public boolean isForwardLocked() {
         return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
     }
diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java
index c97f5e5..46ba006 100644
--- a/services/core/java/com/android/server/pm/SettingBase.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -61,6 +61,7 @@
         this.pkgPrivateFlags = pkgPrivateFlags
                 & (ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
                 | ApplicationInfo.PRIVATE_FLAG_OEM
+                | ApplicationInfo.PRIVATE_FLAG_VENDOR
                 | ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK
                 | ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER);
     }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index ddad677..af1a4d1 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -847,6 +847,8 @@
                 pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
         pkgSetting.pkgPrivateFlags |=
                 pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_OEM;
+        pkgSetting.pkgPrivateFlags |=
+                pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR;
         pkgSetting.primaryCpuAbiString = primaryCpuAbi;
         pkgSetting.secondaryCpuAbiString = secondaryCpuAbi;
         if (childPkgNames != null) {
@@ -4421,6 +4423,7 @@
             ApplicationInfo.PRIVATE_FLAG_PRIVILEGED, "PRIVILEGED",
             ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER, "REQUIRED_FOR_SYSTEM_USER",
             ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY, "STATIC_SHARED_LIBRARY",
+            ApplicationInfo.PRIVATE_FLAG_VENDOR, "VENDOR",
             ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD, "VIRTUAL_PRELOAD",
     };
 
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index 8c86db6..75a6106 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -225,6 +225,9 @@
     public boolean isVerifier() {
         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_VERIFIER) != 0;
     }
+    public boolean isVendorPrivileged() {
+        return (protectionLevel & PermissionInfo.PROTECTION_FLAG_VENDOR_PRIVILEGED) != 0;
+    }
 
     public void transfer(@NonNull String origPackageName, @NonNull String newPackageName) {
         if (!origPackageName.equals(sourcePackageName)) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 7d8e206..90ac4ab 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -959,8 +959,9 @@
      * <p>This handles parent/child apps.
      */
     private boolean hasPrivappWhitelistEntry(String perm, PackageParser.Package pkg) {
-        ArraySet<String> wlPermissions = SystemConfig.getInstance()
-                .getPrivAppPermissions(pkg.packageName);
+        ArraySet<String> wlPermissions = pkg.isVendor() ?
+                SystemConfig.getInstance().getVendorPrivAppPermissions(pkg.packageName)
+                    : SystemConfig.getInstance().getPrivAppPermissions(pkg.packageName);
         // Let's check if this package is whitelisted...
         boolean whitelisted = wlPermissions != null && wlPermissions.contains(perm);
         // If it's not, we'll also tail-recurse to the parent.
@@ -971,7 +972,8 @@
     private boolean grantSignaturePermission(String perm, PackageParser.Package pkg,
             BasePermission bp, PermissionsState origPermissions) {
         boolean oemPermission = bp.isOEM();
-        boolean privilegedPermission = bp.isPrivileged();
+        boolean vendorPrivilegedPermission = bp.isVendorPrivileged();
+        boolean privilegedPermission = bp.isPrivileged() || bp.isVendorPrivileged();
         boolean privappPermissionsDisable =
                 RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE;
         boolean platformPermission = PLATFORM_PACKAGE_NAME.equals(bp.getSourcePackageName());
@@ -982,8 +984,11 @@
                 // Only report violations for apps on system image
                 if (!mSystemReady && !pkg.isUpdatedSystemApp()) {
                     // it's only a reportable violation if the permission isn't explicitly denied
-                    final ArraySet<String> deniedPermissions = SystemConfig.getInstance()
-                            .getPrivAppDenyPermissions(pkg.packageName);
+                    final ArraySet<String> deniedPermissions = pkg.isVendor() ?
+                            SystemConfig.getInstance()
+                                    .getVendorPrivAppDenyPermissions(pkg.packageName)
+                            : SystemConfig.getInstance()
+                                    .getPrivAppDenyPermissions(pkg.packageName);
                     final boolean permissionViolation =
                             deniedPermissions == null || !deniedPermissions.contains(perm);
                     if (permissionViolation) {
@@ -1086,6 +1091,15 @@
                             || (oemPermission && pkg.isOem()
                                     && canGrantOemPermission(ps, perm));
                 }
+                // In any case, don't grant a privileged permission to privileged vendor apps, if
+                // the permission's protectionLevel does not have the extra 'vendorPrivileged'
+                // flag.
+                if (allowed && privilegedPermission &&
+                        !vendorPrivilegedPermission && pkg.isVendor()) {
+                   Slog.w(TAG, "Permission " + perm + " cannot be granted to privileged vendor apk "
+                           + pkg.packageName + " because it isn't a 'vendorPrivileged' permission.");
+                   allowed = false;
+                }
             }
         }
         if (!allowed) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java
deleted file mode 100644
index e6b4540f..0000000
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2016 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.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PermissionInfo;
-import android.platform.test.annotations.GlobalPresubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.util.ArraySet;
-
-import com.android.internal.os.RoSystemProperties;
-import com.android.internal.util.ArrayUtils;
-import com.android.server.SystemConfig;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-import static android.content.pm.PackageManager.GET_PERMISSIONS;
-import static junit.framework.Assert.assertTrue;
-
-
-/**
- * Presubmit tests for {@link PackageManager}.
- */
-@RunWith(AndroidJUnit4.class)
-public class PackageManagerPresubmitTest {
-
-    private Context mContext;
-
-    private PackageManager mPackageManager;
-
-    @Before
-    public void setUp() {
-        mContext = InstrumentationRegistry.getContext();
-        mPackageManager = mContext.getPackageManager();
-    }
-
-    /**
-     * <p>This test ensures that all signature|privileged permissions are granted to priv-apps.
-     * If CONTROL_PRIVAPP_PERMISSIONS_ENFORCE is set, the test also verifies that
-     * granted permissions are whitelisted in {@link SystemConfig}
-     */
-    @Test
-    @SmallTest
-    @GlobalPresubmit
-    public void testPrivAppPermissions() throws PackageManager.NameNotFoundException {
-        List<PackageInfo> installedPackages = mPackageManager
-                .getInstalledPackages(PackageManager.MATCH_UNINSTALLED_PACKAGES | GET_PERMISSIONS);
-        for (PackageInfo packageInfo : installedPackages) {
-            if (!packageInfo.applicationInfo.isPrivilegedApp()
-                    || PackageManagerService.PLATFORM_PACKAGE_NAME.equals(packageInfo.packageName)) {
-                continue;
-            }
-            testPackagePrivAppPermission(packageInfo);
-        }
-
-    }
-
-    private void testPackagePrivAppPermission(PackageInfo packageInfo)
-            throws PackageManager.NameNotFoundException {
-        String packageName = packageInfo.packageName;
-        ArraySet<String> privAppPermissions = SystemConfig.getInstance()
-                .getPrivAppPermissions(packageName);
-        if (ArrayUtils.isEmpty(packageInfo.requestedPermissions)) {
-            return;
-        }
-        for (int i = 0; i < packageInfo.requestedPermissions.length; i++) {
-            String pName = packageInfo.requestedPermissions[i];
-            int protectionLevel;
-            boolean platformPermission;
-            try {
-                PermissionInfo permissionInfo = mPackageManager.getPermissionInfo(pName, 0);
-                platformPermission = PackageManagerService.PLATFORM_PACKAGE_NAME.equals(
-                        permissionInfo.packageName);
-                protectionLevel = permissionInfo.protectionLevel;
-            } catch (PackageManager.NameNotFoundException e) {
-                continue;
-            }
-            if ((protectionLevel & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0) {
-                boolean granted = (packageInfo.requestedPermissionsFlags[i]
-                        & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0;
-                // if privapp permissions are enforced, platform permissions must be whitelisted
-                // in SystemConfig
-                if (platformPermission && RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) {
-                    assertTrue("Permission " + pName + " should be declared in "
-                                    + "privapp-permissions-<category>.xml file for package "
-                                    + packageName,
-                            privAppPermissions != null && privAppPermissions.contains(pName));
-                }
-                assertTrue("Permission " + pName + " should be granted to " + packageName, granted);
-            }
-        }
-    }
-}
diff --git a/tests/privapp-permissions/Android.mk b/tests/privapp-permissions/Android.mk
new file mode 100644
index 0000000..b001c8c
--- /dev/null
+++ b/tests/privapp-permissions/Android.mk
@@ -0,0 +1,31 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := PrivAppPermissionTest
+LOCAL_PRIVILEGED_MODULE := true
+LOCAL_MANIFEST_FILE := system/AndroidManifest.xml
+LOCAL_REQUIRED_MODULES := privapp-permissions-test.xml
+include $(BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := privapp-permissions-test.xml
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
+LOCAL_SRC_FILES:= system/privapp-permissions-test.xml
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := VendorPrivAppPermissionTest
+LOCAL_PRIVILEGED_MODULE := true
+LOCAL_MANIFEST_FILE := vendor/AndroidManifest.xml
+LOCAL_VENDOR_MODULE := true
+LOCAL_REQUIRED_MODULES := vendorprivapp-permissions-test.xml
+include $(BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := vendorprivapp-permissions-test.xml
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_ETC)/permissions
+LOCAL_SRC_FILES:= vendor/privapp-permissions-test.xml
+include $(BUILD_PREBUILT)
+
diff --git a/tests/privapp-permissions/system/AndroidManifest.xml b/tests/privapp-permissions/system/AndroidManifest.xml
new file mode 100644
index 0000000..2099e31
--- /dev/null
+++ b/tests/privapp-permissions/system/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2017 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.framework.permission.privapp.tests.system">
+
+    <!-- MANAGE_USB is signature|privileged -->
+    <uses-permission android:name="android.permission.MANAGE_USB"/>
+</manifest>
diff --git a/tests/privapp-permissions/system/privapp-permissions-test.xml b/tests/privapp-permissions/system/privapp-permissions-test.xml
new file mode 100644
index 0000000..a0cb6bc
--- /dev/null
+++ b/tests/privapp-permissions/system/privapp-permissions-test.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<permissions>
+    <privapp-permissions package="com.android.framework.permission.privapp.tests.system">
+        <permission name="android.permission.MANAGE_USB"/>
+    </privapp-permissions>
+</permissions>
diff --git a/tests/privapp-permissions/vendor/AndroidManifest.xml b/tests/privapp-permissions/vendor/AndroidManifest.xml
new file mode 100644
index 0000000..78dedc5
--- /dev/null
+++ b/tests/privapp-permissions/vendor/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2017 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.framework.permission.privapp.tests.vendor">
+
+    <!-- BIND_IMS_SERVICE is signature|privileged|vendorPrivileged -->
+    <uses-permission android:name="android.permission.BIND_IMS_SERVICE"/>
+    <!-- MANAGE_USB is signature|privileged and thus cannot be granted to this app -->
+    <uses-permission android:name="android.permission.MANAGE_USB"/>
+</manifest>
diff --git a/tests/privapp-permissions/vendor/privapp-permissions-test.xml b/tests/privapp-permissions/vendor/privapp-permissions-test.xml
new file mode 100644
index 0000000..51c588f
--- /dev/null
+++ b/tests/privapp-permissions/vendor/privapp-permissions-test.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<permissions>
+    <privapp-permissions package="com.android.framework.permission.privapp.tests.vendor">
+        <permission name="android.permission.BIND_IMS_SERVICE"/>
+        <permission name="android.permission.MANAGE_USB"/>
+    </privapp-permissions>
+</permissions>