Merge changes from topic "product_partition"
* changes:
Read media files from /product/media/audio
Support /product partition
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 746a090..f6697e8 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -602,6 +602,13 @@
*/
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 @@
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 @@
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 3bb812b..d5c88aa 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -6393,6 +6393,11 @@
}
/** @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 158041d..03203d0 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -41,6 +41,7 @@
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 @@
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 @@
}
/**
+ * 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 c5af897..111934f 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -149,6 +149,9 @@
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 @@
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 @@
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 @@
}
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 403937b..7e17a49 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -174,6 +174,10 @@
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 956b724..3b7b14c 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -85,11 +85,15 @@
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 0485625..a5698af 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -73,6 +73,7 @@
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 ecc5dc1..08da731 100644
--- a/libs/androidfw/include/androidfw/AssetManager.h
+++ b/libs/androidfw/include/androidfw/AssetManager.h
@@ -60,6 +60,7 @@
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/media/java/android/media/MediaActionSound.java b/media/java/android/media/MediaActionSound.java
index 983ca75..dcd4dce 100644
--- a/media/java/android/media/MediaActionSound.java
+++ b/media/java/android/media/MediaActionSound.java
@@ -47,11 +47,16 @@
private SoundPool mSoundPool;
private SoundState[] mSounds;
+ private static final String[] SOUND_DIRS = {
+ "/product/media/audio/ui/",
+ "/system/media/audio/ui/",
+ };
+
private static final String[] SOUND_FILES = {
- "/system/media/audio/ui/camera_click.ogg",
- "/system/media/audio/ui/camera_focus.ogg",
- "/system/media/audio/ui/VideoRecord.ogg",
- "/system/media/audio/ui/VideoStop.ogg"
+ "camera_click.ogg",
+ "camera_focus.ogg",
+ "VideoRecord.ogg",
+ "VideoStop.ogg"
};
private static final String TAG = "MediaActionSound";
@@ -132,12 +137,16 @@
}
private int loadSound(SoundState sound) {
- int id = mSoundPool.load(SOUND_FILES[sound.name], 1);
- if (id > 0) {
- sound.state = STATE_LOADING;
- sound.id = id;
+ final String soundFileName = SOUND_FILES[sound.name];
+ for (String soundDir : SOUND_DIRS) {
+ int id = mSoundPool.load(soundDir + soundFileName, 1);
+ if (id > 0) {
+ sound.state = STATE_LOADING;
+ sound.id = id;
+ return id;
+ }
}
- return id;
+ return 0;
}
/**
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index cb4e46f..c309038 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -158,6 +158,7 @@
public static final String SCANNED_BUILD_PREFS_NAME = "MediaScanBuild";
public static final String LAST_INTERNAL_SCAN_FINGERPRINT = "lastScanFingerprint";
private static final String SYSTEM_SOUNDS_DIR = "/system/media/audio";
+ private static final String PRODUCT_SOUNDS_DIR = "/product/media/audio";
private static String sLastInternalScanFingerprint;
private static final String[] ID3_GENRES = {
@@ -1153,7 +1154,10 @@
private static boolean isSystemSoundWithMetadata(String path) {
if (path.startsWith(SYSTEM_SOUNDS_DIR + ALARMS_DIR)
|| path.startsWith(SYSTEM_SOUNDS_DIR + RINGTONES_DIR)
- || path.startsWith(SYSTEM_SOUNDS_DIR + NOTIFICATIONS_DIR)) {
+ || path.startsWith(SYSTEM_SOUNDS_DIR + NOTIFICATIONS_DIR)
+ || path.startsWith(PRODUCT_SOUNDS_DIR + ALARMS_DIR)
+ || path.startsWith(PRODUCT_SOUNDS_DIR + RINGTONES_DIR)
+ || path.startsWith(PRODUCT_SOUNDS_DIR + NOTIFICATIONS_DIR)) {
return true;
}
return false;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index bedf043..edeee3e 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -133,6 +133,7 @@
import org.xmlpull.v1.XmlPullParserException;
+import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
@@ -4767,6 +4768,16 @@
Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
}
+ private String getSoundEffectFilePath(int effectType) {
+ String filePath = Environment.getProductDirectory() + SOUND_EFFECTS_PATH
+ + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
+ if (!new File(filePath).isFile()) {
+ filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH
+ + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
+ }
+ return filePath;
+ }
+
private boolean onLoadSoundEffects() {
int status;
@@ -4836,9 +4847,7 @@
continue;
}
if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
- String filePath = Environment.getRootDirectory()
- + SOUND_EFFECTS_PATH
- + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
+ String filePath = getSoundEffectFilePath(effect);
int sampleId = mSoundPool.load(filePath, 0);
if (sampleId <= 0) {
Log.w(TAG, "Soundpool could not load file: "+filePath);
@@ -4944,8 +4953,7 @@
} else {
MediaPlayer mediaPlayer = new MediaPlayer();
try {
- String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
- SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
+ String filePath = getSoundEffectFilePath(effectType);
mediaPlayer.setDataSource(filePath);
mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
mediaPlayer.prepare();
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 5bf38dc..10e05cf 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -362,9 +362,10 @@
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 837a118..7767945 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -466,6 +466,7 @@
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,
@@ -570,6 +571,8 @@
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 */
@@ -2552,7 +2555,7 @@
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),
@@ -2562,6 +2565,13 @@
| 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();
@@ -2595,8 +2605,7 @@
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) {
@@ -2636,6 +2645,37 @@
| 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
@@ -2842,6 +2882,23 @@
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;
@@ -9862,6 +9919,7 @@
* <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>
@@ -9884,6 +9942,10 @@
& 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());
@@ -10662,6 +10724,10 @@
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;
@@ -11708,6 +11774,8 @@
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
@@ -16110,7 +16178,7 @@
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;
@@ -16120,12 +16188,16 @@
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);
@@ -17373,6 +17445,10 @@
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;
}
@@ -18112,8 +18188,10 @@
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);
}
@@ -18138,6 +18216,15 @@
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.
*/
@@ -18262,6 +18349,9 @@
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 47cd813..686c4a5 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 @@
}
}
+ 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 @@
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 @@
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 2a2430c..3e2bd4a 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 @@
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 46ba006..7c92045 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 @@
& (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 8ce412e..5e9019d 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 @@
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 @@
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 6e07eaa..e2123c2 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 @@
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 786b998..cb3b107 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 @@
* <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 @@
// 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 0000000..eb38623
--- /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 0000000..0a955e9
--- /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 0000000..f49b46e
--- /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 b001c8c..3c80ad8 100644
--- a/tests/privapp-permissions/Android.mk
+++ b/tests/privapp-permissions/Android.mk
@@ -29,3 +29,17 @@
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 0000000..3d9415c
--- /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 0000000..f298f9d
--- /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>