Support privileged vendor apps
Privileged apps can now be located in the vendor partition. This is
mainly to move SoC-dependent apks to the vendor partition so that the
system partition becomes more generic.
Like existing privileged apps in the system partition, the list of
privileged apps in the vendor partition and the permissions they are
using must be white-listed. The whitelist can be specified via
<privapp-permissions> tags in one of /vendor/etc/permissions/*.xml
files. Note: vendors can only white-list the apps in vendor partition,
but not the apps in system partition.
This change also introduces a new flag 'vendor-privileged' to the
permission protection level. It is used to expose platform-defined
permissions to the privileged vendor apps. If a platform permission does
not have this flag, it is not granted to vendor apps even when the app
is privileged and white-listed.
Bug: 35301609
Test: `mm` under frameworks/base/tests/privapp-permissions
adb sync && adb reboot
adb shell cmd package \
com.android.framework.permission.privapp.tests.vendor
shows that the app is installed.
android.permission.BIND_IMS_SERVICE is in the installed permissions list
android.permission.MANAGE_USE is not in the installed permissions list,
but is in the requested permissions list.
Change-Id: I196375aaaa9ea3a2ba15686ef08cf3f70ade7046
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/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 2d5f7c7..b34de71 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;
@@ -15574,18 +15620,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);
@@ -16759,6 +16809,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;
}
@@ -17493,7 +17547,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);
}
@@ -17509,6 +17565,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.
*/
@@ -17630,6 +17695,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>