diff options
22 files changed, 331 insertions, 25 deletions
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 746a090264c2..f6697e8148a0 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -602,6 +602,13 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { */ public static final int PRIVATE_FLAG_VENDOR = 1 << 18; + /** + * Value for {@linl #privateFlags}: whether this app is pre-installed on the + * product partition of the system image. + * @hide + */ + public static final int PRIVATE_FLAG_PRODUCT = 1 << 19; + /** @hide */ @IntDef(flag = true, prefix = { "PRIVATE_FLAG_" }, value = { PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE, @@ -619,6 +626,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { PRIVATE_FLAG_OEM, PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE, PRIVATE_FLAG_PRIVILEGED, + PRIVATE_FLAG_PRODUCT, PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER, PRIVATE_FLAG_STATIC_SHARED_LIBRARY, PRIVATE_FLAG_VENDOR, @@ -1699,6 +1707,11 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { return (privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0; } + /** @hide */ + public boolean isProduct() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 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 c705ef52f6b5..d1ce72ed1011 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -6379,6 +6379,11 @@ public class PackageParser { } /** @hide */ + public boolean isProduct() { + return applicationInfo.isProduct(); + } + + /** @hide */ public boolean isPrivileged() { return applicationInfo.isPrivilegedApp(); } diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 62731e84a401..d543a0222d46 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -41,6 +41,7 @@ public class Environment { private static final String ENV_OEM_ROOT = "OEM_ROOT"; private static final String ENV_ODM_ROOT = "ODM_ROOT"; private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT"; + private static final String ENV_PRODUCT_ROOT = "PRODUCT_ROOT"; /** {@hide} */ public static final String DIR_ANDROID = "Android"; @@ -62,6 +63,7 @@ public class Environment { private static final File DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem"); private static final File DIR_ODM_ROOT = getDirectory(ENV_ODM_ROOT, "/odm"); private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor"); + private static final File DIR_PRODUCT_ROOT = getDirectory(ENV_PRODUCT_ROOT, "/product"); private static UserEnvironment sCurrentUser; private static boolean sUserRequired; @@ -180,6 +182,16 @@ public class Environment { } /** + * Return root directory of the "product" partition holding product-specific + * customizations if any. If present, the partition is mounted read-only. + * + * @hide + */ + public static File getProductDirectory() { + return DIR_PRODUCT_ROOT; + } + + /** * Return the system directory for a user. This is for use by system * services to store files relating to the user. This directory will be * automatically deleted when the user is removed. diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index c5af89727575..111934f9d005 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -149,6 +149,9 @@ public class SystemConfig { final ArrayMap<String, ArraySet<String>> mVendorPrivAppPermissions = new ArrayMap<>(); final ArrayMap<String, ArraySet<String>> mVendorPrivAppDenyPermissions = new ArrayMap<>(); + final ArrayMap<String, ArraySet<String>> mProductPrivAppPermissions = new ArrayMap<>(); + final ArrayMap<String, ArraySet<String>> mProductPrivAppDenyPermissions = new ArrayMap<>(); + final ArrayMap<String, ArrayMap<String, Boolean>> mOemPermissions = new ArrayMap<>(); public static SystemConfig getInstance() { @@ -240,6 +243,14 @@ public class SystemConfig { return mVendorPrivAppDenyPermissions.get(packageName); } + public ArraySet<String> getProductPrivAppPermissions(String packageName) { + return mProductPrivAppPermissions.get(packageName); + } + + public ArraySet<String> getProductPrivAppDenyPermissions(String packageName) { + return mProductPrivAppDenyPermissions.get(packageName); + } + public Map<String, Boolean> getOemPermissions(String packageName) { final Map<String, Boolean> oemPermissions = mOemPermissions.get(packageName); if (oemPermissions != null) { @@ -278,6 +289,14 @@ public class SystemConfig { Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag); readPermissions(Environment.buildPath( Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag); + + // Allow Product to customize system configs around libs, features, permissions and apps + int productPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS | + ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS; + readPermissions(Environment.buildPath( + Environment.getProductDirectory(), "etc", "sysconfig"), productPermissionFlag); + readPermissions(Environment.buildPath( + Environment.getProductDirectory(), "etc", "permissions"), productPermissionFlag); } void readPermissions(File libraryDir, int permissionFlag) { @@ -598,15 +617,20 @@ public class SystemConfig { } XmlUtils.skipCurrentTag(parser); } else if ("privapp-permissions".equals(name) && allowPrivappPermissions) { - // privapp permissions from system and vendor partitions are stored + // privapp permissions from system, vendor and product 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()); + boolean product = permFile.toPath().startsWith( + Environment.getProductDirectory().toPath()); if (vendor) { readPrivAppPermissions(parser, mVendorPrivAppPermissions, mVendorPrivAppDenyPermissions); + } else if (product) { + readPrivAppPermissions(parser, mProductPrivAppPermissions, + mProductPrivAppDenyPermissions); } else { readPrivAppPermissions(parser, mPrivAppPermissions, mPrivAppDenyPermissions); diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index 403937be7088..7e17a4909cee 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -174,6 +174,10 @@ static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) { argv[argc++] = AssetManager::OVERLAY_DIR; } + if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) { + argv[argc++] = AssetManager::PRODUCT_OVERLAY_DIR; + } + // Finally, invoke idmap (if any overlay directory exists) if (argc > 5) { execv(AssetManager::IDMAP_BIN, (char* const*)argv); diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index 956b7249660f..3b7b14c58d0a 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -85,11 +85,15 @@ bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const { static const char* kOverlayDir = "/system/vendor/overlay/"; static const char* kVendorOverlayDir = "/vendor/overlay"; static const char* kOverlaySubdir = "/system/vendor/overlay-subdir/"; + static const char* kSystemProductOverlayDir = "/system/product/overlay/"; + static const char* kProductOverlayDir = "/product/overlay"; static const char* kApkSuffix = ".apk"; if ((android::base::StartsWith(path, kOverlayDir) || android::base::StartsWith(path, kOverlaySubdir) - || android::base::StartsWith(path, kVendorOverlayDir)) + || android::base::StartsWith(path, kVendorOverlayDir) + || android::base::StartsWith(path, kSystemProductOverlayDir) + || android::base::StartsWith(path, kProductOverlayDir)) && android::base::EndsWith(path, kApkSuffix) && path.find("/../") == std::string::npos) { return true; diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 0485625e81e8..a5698af18f6b 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -73,6 +73,7 @@ static volatile int32_t gCount = 0; const char* AssetManager::RESOURCES_FILENAME = "resources.arsc"; const char* AssetManager::IDMAP_BIN = "/system/bin/idmap"; const char* AssetManager::OVERLAY_DIR = "/vendor/overlay"; +const char* AssetManager::PRODUCT_OVERLAY_DIR = "/product/overlay"; const char* AssetManager::OVERLAY_THEME_DIR_PROPERTY = "ro.boot.vendor.overlay.theme"; const char* AssetManager::TARGET_PACKAGE_NAME = "android"; const char* AssetManager::TARGET_APK_PATH = "/system/framework/framework-res.apk"; diff --git a/libs/androidfw/include/androidfw/AssetManager.h b/libs/androidfw/include/androidfw/AssetManager.h index ecc5dc1ad331..08da7319de85 100644 --- a/libs/androidfw/include/androidfw/AssetManager.h +++ b/libs/androidfw/include/androidfw/AssetManager.h @@ -60,6 +60,7 @@ public: static const char* RESOURCES_FILENAME; static const char* IDMAP_BIN; static const char* OVERLAY_DIR; + static const char* PRODUCT_OVERLAY_DIR; /* * If OVERLAY_THEME_DIR_PROPERTY is set, search for runtime resource overlay * APKs in OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java index 03950119ea13..4fddec9c133e 100644 --- a/services/core/java/com/android/server/pm/OtaDexoptService.java +++ b/services/core/java/com/android/server/pm/OtaDexoptService.java @@ -361,9 +361,10 @@ public class OtaDexoptService extends IOtaDexopt.Stub { continue; } - // If the path is in /system or /vendor, ignore. It will have been ota-dexopted into - // /data/ota and moved into the dalvik-cache already. - if (pkg.codePath.startsWith("/system") || pkg.codePath.startsWith("/vendor")) { + // If the path is in /system, /vendor or /product, ignore. It will have been + // ota-dexopted into /data/ota and moved into the dalvik-cache already. + if (pkg.codePath.startsWith("/system") || pkg.codePath.startsWith("/vendor") + || pkg.codePath.startsWith("/product")) { continue; } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 5dfd3ae4b8e8..704646571f06 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -464,6 +464,7 @@ public class PackageManagerService extends IPackageManager.Stub static final int SCAN_AS_PRIVILEGED = 1<<18; static final int SCAN_AS_OEM = 1<<19; static final int SCAN_AS_VENDOR = 1<<20; + static final int SCAN_AS_PRODUCT = 1<<21; @IntDef(flag = true, prefix = { "SCAN_" }, value = { SCAN_NO_DEX, @@ -568,6 +569,8 @@ public class PackageManagerService extends IPackageManager.Stub private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay"; + private static final String PRODUCT_OVERLAY_DIR = "/product/overlay"; + private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB = "pm.dexopt.priv-apps-oob"; /** Canonical intent used to identify what counts as a "web browser" app */ @@ -2550,7 +2553,7 @@ public class PackageManagerService extends IPackageManager.Stub scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE; } - // Collect vendor overlay packages. (Do this before scanning any apps.) + // Collect vendor/product overlay packages. (Do this before scanning any apps.) // For security and version matching reason, only consider // overlay packages if they reside in the right directory. scanDirTracedLI(new File(VENDOR_OVERLAY_DIR), @@ -2560,6 +2563,13 @@ public class PackageManagerService extends IPackageManager.Stub | SCAN_AS_SYSTEM | SCAN_AS_VENDOR, 0); + scanDirTracedLI(new File(PRODUCT_OVERLAY_DIR), + mDefParseFlags + | PackageParser.PARSE_IS_SYSTEM_DIR, + scanFlags + | SCAN_AS_SYSTEM + | SCAN_AS_PRODUCT, + 0); mParallelPackageParserCallback.findStaticOverlayPackages(); @@ -2593,8 +2603,7 @@ public class PackageManagerService extends IPackageManager.Stub 0); // Collected privileged vendor packages. - File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), - "priv-app"); + File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app"); try { privilegedVendorAppDir = privilegedVendorAppDir.getCanonicalFile(); } catch (IOException e) { @@ -2634,6 +2643,37 @@ public class PackageManagerService extends IPackageManager.Stub | SCAN_AS_OEM, 0); + // Collected privileged product packages. + File privilegedProductAppDir = new File(Environment.getProductDirectory(), "priv-app"); + try { + privilegedProductAppDir = privilegedProductAppDir.getCanonicalFile(); + } catch (IOException e) { + // failed to look up canonical path, continue with original one + } + scanDirTracedLI(privilegedProductAppDir, + mDefParseFlags + | PackageParser.PARSE_IS_SYSTEM_DIR, + scanFlags + | SCAN_AS_SYSTEM + | SCAN_AS_PRODUCT + | SCAN_AS_PRIVILEGED, + 0); + + // Collect ordinary product packages. + File productAppDir = new File(Environment.getProductDirectory(), "app"); + try { + productAppDir = productAppDir.getCanonicalFile(); + } catch (IOException e) { + // failed to look up canonical path, continue with original one + } + scanDirTracedLI(productAppDir, + mDefParseFlags + | PackageParser.PARSE_IS_SYSTEM_DIR, + scanFlags + | SCAN_AS_SYSTEM + | SCAN_AS_PRODUCT, + 0); + // Prune any system packages that no longer exist. final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>(); // Stub packages must either be replaced with full versions in the /data @@ -2840,6 +2880,23 @@ Slog.e("TODD", scanFlags | SCAN_AS_SYSTEM | SCAN_AS_OEM; + } else if (FileUtils.contains(privilegedProductAppDir, scanFile)) { + reparseFlags = + mDefParseFlags | + PackageParser.PARSE_IS_SYSTEM_DIR; + rescanFlags = + scanFlags + | SCAN_AS_SYSTEM + | SCAN_AS_PRODUCT + | SCAN_AS_PRIVILEGED; + } else if (FileUtils.contains(productAppDir, scanFile)) { + reparseFlags = + mDefParseFlags | + PackageParser.PARSE_IS_SYSTEM_DIR; + rescanFlags = + scanFlags + | SCAN_AS_SYSTEM + | SCAN_AS_PRODUCT; } else { Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile); continue; @@ -9826,6 +9883,7 @@ Slog.e("TODD", * <li>{@link #SCAN_AS_PRIVILEGED}</li> * <li>{@link #SCAN_AS_OEM}</li> * <li>{@link #SCAN_AS_VENDOR}</li> + * <li>{@link #SCAN_AS_PRODUCT}</li> * <li>{@link #SCAN_AS_INSTANT_APP}</li> * <li>{@link #SCAN_AS_VIRTUAL_PRELOAD}</li> * </ul> @@ -9848,6 +9906,10 @@ Slog.e("TODD", & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0) { scanFlags |= SCAN_AS_VENDOR; } + if ((disabledPkgSetting.pkgPrivateFlags + & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0) { + scanFlags |= SCAN_AS_PRODUCT; + } } if (pkgSetting != null) { final int userId = ((user == null) ? 0 : user.getIdentifier()); @@ -10626,6 +10688,10 @@ Slog.e("TODD", pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VENDOR; } + if ((scanFlags & SCAN_AS_PRODUCT) != 0) { + pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRODUCT; + } + if (!isSystemApp(pkg)) { // Only system apps can use these features. pkg.mOriginalPackages = null; @@ -11672,6 +11738,8 @@ Slog.e("TODD", codeRoot = Environment.getOemDirectory(); } else if (FileUtils.contains(Environment.getVendorDirectory(), codePath)) { codeRoot = Environment.getVendorDirectory(); + } else if (FileUtils.contains(Environment.getProductDirectory(), codePath)) { + codeRoot = Environment.getProductDirectory(); } else { // Unrecognized code path; take its top real segment as the apk root: // e.g. /something/app/blah.apk => /something @@ -16074,7 +16142,7 @@ Slog.e("TODD", boolean sysPkg = (isSystemApp(oldPackage)); if (sysPkg) { - // Set the system/privileged/oem/vendor flags as needed + // Set the system/privileged/oem/vendor/product flags as needed final boolean privileged = (oldPackage.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; @@ -16084,12 +16152,16 @@ Slog.e("TODD", final boolean vendor = (oldPackage.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0; + final boolean product = + (oldPackage.applicationInfo.privateFlags + & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0; final @ParseFlags int systemParseFlags = parseFlags; final @ScanFlags int systemScanFlags = scanFlags | SCAN_AS_SYSTEM | (privileged ? SCAN_AS_PRIVILEGED : 0) | (oem ? SCAN_AS_OEM : 0) - | (vendor ? SCAN_AS_VENDOR : 0); + | (vendor ? SCAN_AS_VENDOR : 0) + | (product ? SCAN_AS_PRODUCT : 0); replaceSystemPackageLIF(oldPackage, pkg, systemParseFlags, systemScanFlags, user, allUsers, installerPackageName, res, installReason); @@ -17339,6 +17411,10 @@ Slog.e("TODD", return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0; } + private static boolean isProductApp(PackageParser.Package pkg) { + return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0; + } + private static boolean hasDomainURLs(PackageParser.Package pkg) { return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0; } @@ -18078,8 +18154,10 @@ Slog.e("TODD", try { final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app"); final File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app"); + final File privilegedProductAppDir = new File(Environment.getProductDirectory(), "priv-app"); return path.startsWith(privilegedAppDir.getCanonicalPath()) - || path.startsWith(privilegedVendorAppDir.getCanonicalPath()); + || path.startsWith(privilegedVendorAppDir.getCanonicalPath()) + || path.startsWith(privilegedProductAppDir.getCanonicalPath()); } catch (IOException e) { Slog.e(TAG, "Unable to access code path " + path); } @@ -18104,6 +18182,15 @@ Slog.e("TODD", return false; } + static boolean locationIsProduct(String path) { + try { + return path.startsWith(Environment.getProductDirectory().getCanonicalPath()); + } catch (IOException e) { + Slog.e(TAG, "Unable to access code path " + path); + } + return false; + } + /* * Tries to delete system package. */ @@ -18228,6 +18315,9 @@ Slog.e("TODD", if (locationIsVendor(codePathString)) { scanFlags |= SCAN_AS_VENDOR; } + if (locationIsProduct(codePathString)) { + scanFlags |= SCAN_AS_PRODUCT; + } 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 47cd81326932..686c4a5eb321 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -1555,6 +1555,15 @@ class PackageManagerShellCommand extends ShellCommand { } } + private boolean isProductApp(String pkg) { + try { + final PackageInfo info = mInterface.getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM); + return info != null && info.applicationInfo.isProduct(); + } catch (RemoteException e) { + return false; + } + } + private int runGetPrivappPermissions() { final String pkg = getNextArg(); if (pkg == null) { @@ -1562,9 +1571,14 @@ class PackageManagerShellCommand extends ShellCommand { return 1; } - ArraySet<String> privAppPermissions = isVendorApp(pkg) ? - SystemConfig.getInstance().getVendorPrivAppPermissions(pkg) - : SystemConfig.getInstance().getPrivAppPermissions(pkg); + ArraySet<String> privAppPermissions = null; + if (isVendorApp(pkg)) { + privAppPermissions = SystemConfig.getInstance().getVendorPrivAppPermissions(pkg); + } else if (isProductApp(pkg)) { + privAppPermissions = SystemConfig.getInstance().getProductPrivAppPermissions(pkg); + } else { + privAppPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg); + } getOutPrintWriter().println(privAppPermissions == null ? "{}" : privAppPermissions.toString()); @@ -1578,9 +1592,14 @@ class PackageManagerShellCommand extends ShellCommand { return 1; } - ArraySet<String> privAppPermissions = isVendorApp(pkg) ? - SystemConfig.getInstance().getVendorPrivAppDenyPermissions(pkg) - : SystemConfig.getInstance().getPrivAppDenyPermissions(pkg); + ArraySet<String> privAppPermissions = null; + if (isVendorApp(pkg)) { + privAppPermissions = SystemConfig.getInstance().getVendorPrivAppDenyPermissions(pkg); + } else if (isProductApp(pkg)) { + privAppPermissions = SystemConfig.getInstance().getProductPrivAppDenyPermissions(pkg); + } else { + privAppPermissions = SystemConfig.getInstance().getPrivAppDenyPermissions(pkg); + } getOutPrintWriter().println(privAppPermissions == null ? "{}" : privAppPermissions.toString()); diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index 2a2430c07980..3e2bd4a1b3ba 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -173,6 +173,10 @@ public final class PackageSetting extends PackageSettingBase { return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0; } + public boolean isProduct() { + return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 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 46ba0060d93e..7c92045c7c5e 100644 --- a/services/core/java/com/android/server/pm/SettingBase.java +++ b/services/core/java/com/android/server/pm/SettingBase.java @@ -62,6 +62,7 @@ abstract class SettingBase { & (ApplicationInfo.PRIVATE_FLAG_PRIVILEGED | ApplicationInfo.PRIVATE_FLAG_OEM | ApplicationInfo.PRIVATE_FLAG_VENDOR + | ApplicationInfo.PRIVATE_FLAG_PRODUCT | 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 8ce412e5783a..5e9019dfea04 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -851,6 +851,8 @@ public final class Settings { pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_OEM; pkgSetting.pkgPrivateFlags |= pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR; + pkgSetting.pkgPrivateFlags |= + pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT; pkgSetting.primaryCpuAbiString = primaryCpuAbi; pkgSetting.secondaryCpuAbiString = secondaryCpuAbi; if (childPkgNames != null) { @@ -4397,6 +4399,7 @@ public final class Settings { 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_PRODUCT, "PRODUCT", ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD, "VIRTUAL_PRELOAD", }; diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index 6e07eaac9c44..e2123c25dd81 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -1215,6 +1215,10 @@ public final class DefaultPermissionGrantPolicy { if (dir.isDirectory() && dir.canRead()) { Collections.addAll(ret, dir.listFiles()); } + dir = new File(Environment.getProductDirectory(), "etc/default-permissions"); + if (dir.isDirectory() && dir.canRead()) { + Collections.addAll(ret, dir.listFiles()); + } return ret.isEmpty() ? null : ret.toArray(new File[0]); } 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 786b998862de..cb3b1073a593 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -954,9 +954,16 @@ 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 = pkg.isVendor() ? - SystemConfig.getInstance().getVendorPrivAppPermissions(pkg.packageName) - : SystemConfig.getInstance().getPrivAppPermissions(pkg.packageName); + ArraySet<String> wlPermissions = null; + if (pkg.isVendor()) { + wlPermissions = + SystemConfig.getInstance().getVendorPrivAppPermissions(pkg.packageName); + } else if (pkg.isProduct()) { + wlPermissions = + SystemConfig.getInstance().getProductPrivAppPermissions(pkg.packageName); + } else { + wlPermissions = 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. @@ -979,11 +986,17 @@ 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 = pkg.isVendor() ? - SystemConfig.getInstance() - .getVendorPrivAppDenyPermissions(pkg.packageName) - : SystemConfig.getInstance() - .getPrivAppDenyPermissions(pkg.packageName); + ArraySet<String> deniedPermissions = null; + if (pkg.isVendor()) { + deniedPermissions = SystemConfig.getInstance() + .getVendorPrivAppDenyPermissions(pkg.packageName); + } else if (pkg.isProduct()) { + deniedPermissions = SystemConfig.getInstance() + .getProductPrivAppDenyPermissions(pkg.packageName); + } else { + deniedPermissions = SystemConfig.getInstance() + .getPrivAppDenyPermissions(pkg.packageName); + } final boolean permissionViolation = deniedPermissions == null || !deniedPermissions.contains(perm); if (permissionViolation) { diff --git a/tests/libs-permissions/Android.mk b/tests/libs-permissions/Android.mk new file mode 100644 index 000000000000..eb3862390338 --- /dev/null +++ b/tests/libs-permissions/Android.mk @@ -0,0 +1,15 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := com.android.test.libs.product +LOCAL_PRODUCT_MODULE := true +LOCAL_SRC_FILES := $(call all-java-files-under, product/java) +LOCAL_REQUIRED_MODULES := com.android.test.libs.product.xml +include $(BUILD_JAVA_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := com.android.test.libs.product.xml +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_ETC)/permissions +LOCAL_SRC_FILES:= product/com.android.test.libs.product.xml +include $(BUILD_PREBUILT) diff --git a/tests/libs-permissions/product/com.android.test.libs.product.xml b/tests/libs-permissions/product/com.android.test.libs.product.xml new file mode 100644 index 000000000000..0a955e9df7fd --- /dev/null +++ b/tests/libs-permissions/product/com.android.test.libs.product.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2018 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. +--> + +<permissions> + <library name="com.android.test.libs.product" + file="/product/framework/com.android.test.libs.product.jar" /> +</permissions> diff --git a/tests/libs-permissions/product/java/com/android/test/libs/product/LibsProductTest.java b/tests/libs-permissions/product/java/com/android/test/libs/product/LibsProductTest.java new file mode 100644 index 000000000000..f49b46e72c25 --- /dev/null +++ b/tests/libs-permissions/product/java/com/android/test/libs/product/LibsProductTest.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2018 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.test.libs.product; + +/** + * Test class for product libs. + */ +public class LibsProductTest { + + /** + * Dummpy method for testing. + */ + public static void test() { + } +} diff --git a/tests/privapp-permissions/Android.mk b/tests/privapp-permissions/Android.mk index b001c8c466a9..3c80ad8587af 100644 --- a/tests/privapp-permissions/Android.mk +++ b/tests/privapp-permissions/Android.mk @@ -29,3 +29,17 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_ETC)/permissions LOCAL_SRC_FILES:= vendor/privapp-permissions-test.xml include $(BUILD_PREBUILT) +include $(CLEAR_VARS) +LOCAL_PACKAGE_NAME := ProductPrivAppPermissionTest +LOCAL_PRIVILEGED_MODULE := true +LOCAL_MANIFEST_FILE := product/AndroidManifest.xml +LOCAL_PRODUCT_MODULE := true +LOCAL_REQUIRED_MODULES := productprivapp-permissions-test.xml +include $(BUILD_PACKAGE) + +include $(CLEAR_VARS) +LOCAL_MODULE := productprivapp-permissions-test.xml +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_ETC)/permissions +LOCAL_SRC_FILES:= product/privapp-permissions-test.xml +include $(BUILD_PREBUILT) diff --git a/tests/privapp-permissions/product/AndroidManifest.xml b/tests/privapp-permissions/product/AndroidManifest.xml new file mode 100644 index 000000000000..3d9415c3df41 --- /dev/null +++ b/tests/privapp-permissions/product/AndroidManifest.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2018 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.product"> + + <!-- MANAGE_USB is signature|privileged --> + <uses-permission android:name="android.permission.MANAGE_USB"/> +</manifest> diff --git a/tests/privapp-permissions/product/privapp-permissions-test.xml b/tests/privapp-permissions/product/privapp-permissions-test.xml new file mode 100644 index 000000000000..f298f9da41b7 --- /dev/null +++ b/tests/privapp-permissions/product/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.product"> + <permission name="android.permission.MANAGE_USB"/> + </privapp-permissions> +</permissions> |