summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/LoadedApk.java3
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java13
-rw-r--r--core/java/android/content/pm/PackageParser.java5
-rw-r--r--core/java/android/content/pm/PermissionInfo.java18
-rw-r--r--core/java/com/android/server/SystemConfig.java40
-rw-r--r--core/res/res/values/attrs_manifest.xml3
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java84
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java26
-rw-r--r--services/core/java/com/android/server/pm/PackageSetting.java4
-rw-r--r--services/core/java/com/android/server/pm/SettingBase.java1
-rw-r--r--services/core/java/com/android/server/pm/Settings.java3
-rw-r--r--services/core/java/com/android/server/pm/permission/BasePermission.java3
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java24
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java115
-rw-r--r--tests/privapp-permissions/Android.mk31
-rw-r--r--tests/privapp-permissions/system/AndroidManifest.xml23
-rw-r--r--tests/privapp-permissions/system/privapp-permissions-test.xml6
-rw-r--r--tests/privapp-permissions/vendor/AndroidManifest.xml25
-rw-r--r--tests/privapp-permissions/vendor/privapp-permissions-test.xml7
19 files changed, 292 insertions, 142 deletions
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index f6d9710dae69..de6230cf825a 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -638,8 +638,7 @@ public final class LoadedApk {
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 edb27cd4ecf1..5298f57b4ef2 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -594,6 +594,13 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
*/
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 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
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 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
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 ebeaad78ea6a..98c824dbf8f6 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -6267,6 +6267,11 @@ public class PackageParser {
}
/** @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 75887624eef3..551d53b631cd 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -144,6 +144,15 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
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 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
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 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
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 b5031f23918f..b7a67192f01f 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -146,6 +146,9 @@ public class SystemConfig {
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 @@ public class SystemConfig {
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 @@ public class SystemConfig {
// 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 @@ public class SystemConfig {
}
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 @@ public class SystemConfig {
}
}
- 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 @@ public class SystemConfig {
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 @@ public class SystemConfig {
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 4d410e5447de..4d67494be21d 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 2d5f7c7124c4..b34de7140b6b 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 @@ public class PackageManagerService extends IPackageManager.Stub
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 @@ public class PackageManagerService extends IPackageManager.Stub
| 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 @@ public class PackageManagerService extends IPackageManager.Stub
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 @@ public class PackageManagerService extends IPackageManager.Stub
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 @@ public class PackageManagerService extends IPackageManager.Stub
} 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 @@ public class PackageManagerService extends IPackageManager.Stub
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 @@ public class PackageManagerService extends IPackageManager.Stub
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 @@ public class PackageManagerService extends IPackageManager.Stub
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 @@ public class PackageManagerService extends IPackageManager.Stub
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 @@ public class PackageManagerService extends IPackageManager.Stub
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 @@ public class PackageManagerService extends IPackageManager.Stub
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 @@ public class PackageManagerService extends IPackageManager.Stub
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 44f36d1734c8..45b94a468514 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 @@ class PackageManagerShellCommand extends ShellCommand {
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 @@ class PackageManagerShellCommand extends ShellCommand {
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 3b414e9a0dc5..258dd4d4dcb3 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 @@ public final class PackageSetting extends PackageSettingBase {
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 c97f5e5443a3..46ba0060d93e 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 @@ abstract class SettingBase {
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 ddad6774871d..af1a4d148856 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 @@ public final class Settings {
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 @@ public final class Settings {
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 8c86db64471d..75a61064c1c9 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 final class BasePermission {
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 7d8e20696aff..90ac4ab7dd42 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 @@ Slog.e(TAG, "TODD: Packages: " + Arrays.toString(packages));
* <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 @@ Slog.e(TAG, "TODD: Packages: " + Arrays.toString(packages));
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 @@ Slog.e(TAG, "TODD: Packages: " + Arrays.toString(packages));
// 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 @@ Slog.e(TAG, "TODD: Packages: " + Arrays.toString(packages));
|| (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 e6b4540f73c9..000000000000
--- 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 000000000000..b001c8c466a9
--- /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 000000000000..2099e31bd2c1
--- /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 000000000000..a0cb6bc74195
--- /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 000000000000..78dedc5f199b
--- /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 000000000000..51c588f0dea7
--- /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>