diff options
| -rw-r--r-- | core/java/android/content/pm/PackageParser.java | 39 | ||||
| -rw-r--r-- | services/core/java/com/android/server/pm/PackageManagerService.java | 119 |
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) { |