summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/content/pm/PackageParser.java39
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java119
2 files changed, 154 insertions, 4 deletions
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 270aea851791..2b23e7a2a633 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -591,6 +591,8 @@ public class PackageParser {
*/
public interface Callback {
boolean hasFeature(String feature);
+ String[] getOverlayPaths(String targetPackageName, String targetPath);
+ String[] getOverlayApks(String targetPackageName);
}
/**
@@ -607,6 +609,14 @@ public class PackageParser {
@Override public boolean hasFeature(String feature) {
return mPm.hasSystemFeature(feature);
}
+
+ @Override public String[] getOverlayPaths(String targetPackageName, String targetPath) {
+ return null;
+ }
+
+ @Override public String[] getOverlayApks(String targetPackageName) {
+ return null;
+ }
}
/**
@@ -1158,7 +1168,19 @@ public class PackageParser {
}
final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath());
- return fromCacheEntry(bytes);
+ Package p = fromCacheEntry(bytes);
+ if (mCallback != null) {
+ String[] overlayApks = mCallback.getOverlayApks(p.packageName);
+ if (overlayApks != null && overlayApks.length > 0) {
+ for (String overlayApk : overlayApks) {
+ // If a static RRO is updated, return null.
+ if (!isCacheUpToDate(new File(overlayApk), cacheFile)) {
+ return null;
+ }
+ }
+ }
+ }
+ return p;
} catch (Throwable e) {
Slog.w(TAG, "Error reading package cache: ", e);
@@ -1332,7 +1354,7 @@ public class PackageParser {
final Resources res = new Resources(assets, mMetrics, null);
final String[] outError = new String[1];
- final Package pkg = parseBaseApk(res, parser, flags, outError);
+ final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
if (pkg == null) {
throw new PackageParserException(mParseError,
apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
@@ -1889,6 +1911,7 @@ public class PackageParser {
* need to consider whether they should be supported by split APKs and child
* packages.
*
+ * @param apkPath The package apk file path
* @param res The resources from which to resolve values
* @param parser The manifest parser
* @param flags Flags how to parse
@@ -1898,7 +1921,8 @@ public class PackageParser {
* @throws XmlPullParserException
* @throws IOException
*/
- private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+ private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags,
String[] outError) throws XmlPullParserException, IOException {
final String splitName;
final String pkgName;
@@ -1918,6 +1942,15 @@ public class PackageParser {
return null;
}
+ if (mCallback != null) {
+ String[] overlayPaths = mCallback.getOverlayPaths(pkgName, apkPath);
+ if (overlayPaths != null && overlayPaths.length > 0) {
+ for (String overlayPath : overlayPaths) {
+ res.getAssets().addOverlayPath(overlayPath);
+ }
+ }
+ }
+
final Package pkg = new Package(pkgName);
TypedArray sa = res.obtainAttributes(parser,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6c5abe49fe13..898437ddae41 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -757,9 +757,124 @@ public class PackageManagerService extends IPackageManager.Stub
@Override public final boolean hasFeature(String feature) {
return PackageManagerService.this.hasSystemFeature(feature, 0);
}
+
+ final List<PackageParser.Package> getStaticOverlayPackages(
+ Collection<PackageParser.Package> allPackages, String targetPackageName) {
+ if ("android".equals(targetPackageName)) {
+ // Static RROs targeting to "android", ie framework-res.apk, are already applied by
+ // native AssetManager.
+ return null;
+ }
+
+ List<PackageParser.Package> overlayPackages = null;
+ for (PackageParser.Package p : allPackages) {
+ if (targetPackageName.equals(p.mOverlayTarget) && p.mOverlayIsStatic) {
+ if (overlayPackages == null) {
+ overlayPackages = new ArrayList<>();
+ }
+ overlayPackages.add(p);
+ }
+ }
+ if (overlayPackages != null) {
+ Comparator<PackageParser.Package> cmp =
+ Comparator.comparingInt(p -> p.mOverlayPriority);
+ overlayPackages.sort(cmp);
+ }
+ return overlayPackages;
+ }
+
+ final String[] getStaticOverlayPaths(List<PackageParser.Package> overlayPackages,
+ String targetPath) {
+ if (overlayPackages == null || overlayPackages.isEmpty()) {
+ return null;
+ }
+ List<String> overlayPathList = null;
+ for (PackageParser.Package overlayPackage : overlayPackages) {
+ if (targetPath == null) {
+ if (overlayPathList == null) {
+ overlayPathList = new ArrayList<>();
+ }
+ overlayPathList.add(overlayPackage.baseCodePath);
+ continue;
+ }
+
+ try {
+ // Creates idmaps for system to parse correctly the Android manifest of the
+ // target package.
+ //
+ // OverlayManagerService will update each of them with a correct gid from its
+ // target package app id.
+ mInstaller.idmap(targetPath, overlayPackage.baseCodePath,
+ UserHandle.getSharedAppGid(
+ UserHandle.getUserGid(UserHandle.USER_SYSTEM)));
+ if (overlayPathList == null) {
+ overlayPathList = new ArrayList<>();
+ }
+ overlayPathList.add(overlayPackage.baseCodePath);
+ } catch (InstallerException e) {
+ Slog.e(TAG, "Failed to generate idmap for " + targetPath + " and " +
+ overlayPackage.baseCodePath);
+ }
+ }
+ return overlayPathList == null ? null : overlayPathList.toArray(new String[0]);
+ }
+
+ String[] getStaticOverlayPaths(String targetPackageName, String targetPath) {
+ List<PackageParser.Package> overlayPackages;
+ synchronized (mInstallLock) {
+ synchronized (mPackages) {
+ overlayPackages = getStaticOverlayPackages(
+ mPackages.values(), targetPackageName);
+ }
+ // It is safe to keep overlayPackages without holding mPackages because static overlay
+ // packages can't be uninstalled or disabled.
+ return getStaticOverlayPaths(overlayPackages, targetPath);
+ }
+ }
+
+ @Override public final String[] getOverlayApks(String targetPackageName) {
+ return getStaticOverlayPaths(targetPackageName, null);
+ }
+
+ @Override public final String[] getOverlayPaths(String targetPackageName,
+ String targetPath) {
+ return getStaticOverlayPaths(targetPackageName, targetPath);
+ }
+ }
+
+ class ParallelPackageParserCallback extends PackageParserCallback {
+ List<PackageParser.Package> mOverlayPackages = null;
+
+ void findStaticOverlayPackages() {
+ synchronized (mPackages) {
+ for (PackageParser.Package p : mPackages.values()) {
+ if (p.mOverlayIsStatic) {
+ if (mOverlayPackages == null) {
+ mOverlayPackages = new ArrayList<>();
+ }
+ mOverlayPackages.add(p);
+ }
+ }
+ }
+ }
+
+ @Override
+ synchronized String[] getStaticOverlayPaths(String targetPackageName, String targetPath) {
+ // We can trust mOverlayPackages without holding mPackages because package uninstall
+ // can't happen while running parallel parsing.
+ // And we can call mInstaller inside getStaticOverlayPaths without holding mInstallLock
+ // because mInstallLock is held before running parallel parsing.
+ // Moreover holding mPackages or mInstallLock on each parsing thread causes dead-lock.
+ return mOverlayPackages == null ? null :
+ getStaticOverlayPaths(
+ getStaticOverlayPackages(mOverlayPackages, targetPackageName),
+ targetPath);
+ }
}
final PackageParser.Callback mPackageParserCallback = new PackageParserCallback();
+ final ParallelPackageParserCallback mParallelPackageParserCallback =
+ new ParallelPackageParserCallback();
// Currently known shared libraries.
final ArrayMap<String, LongSparseArray<SharedLibraryInfo>> mSharedLibraries = new ArrayMap<>();
@@ -2443,6 +2558,8 @@ public class PackageManagerService extends IPackageManager.Stub
| SCAN_AS_ODM,
0);
+ mParallelPackageParserCallback.findStaticOverlayPackages();
+
// Find base frameworks (resource packages without code).
scanDirTracedLI(frameworkDir,
mDefParseFlags
@@ -8665,7 +8782,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
try (ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
- mPackageParserCallback)) {
+ mParallelPackageParserCallback)) {
// Submit files for parsing in parallel
int fileCount = 0;
for (File file : files) {