Structural changes to support atomic installs
This change makes the initial changes to installPackage that allow
verification of multiple packages for install and a single commit of all
of them atomically. Install will eventually be broken up into 3 stages:
* scan: only parse and verify the APK; isolated from system state
* reconcile: verify that the APK is compatible with the system given
current state and with the other apps being installed
along side it
* commit: modify system state to account for the reconciled apps
Test: manual install still works; non-functional change
Bug: 109941548
Change-Id: I84cc2185942879d7d0217d49973404bb061918af
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e2d7c83d2..965f7bd 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -173,7 +173,6 @@
import android.content.pm.PackageManagerInternal.PackageListObserver;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.ActivityIntentInfo;
-import android.content.pm.PackageParser.Package;
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.PackageParser.ParseFlags;
@@ -290,8 +289,6 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
-import com.android.internal.util.function.QuadFunction;
-import com.android.internal.util.function.TriFunction;
import com.android.server.AttributeCache;
import com.android.server.DeviceIdleController;
import com.android.server.EventLogTags;
@@ -366,7 +363,6 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.BiFunction;
import java.util.function.Predicate;
import dalvik.system.CloseGuard;
@@ -17051,17 +17047,91 @@
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
+ private static class InstallRequest {
+ final InstallArgs args;
+ final PackageInstalledInfo res;
+
+ private InstallRequest(InstallArgs args, PackageInstalledInfo res) {
+ this.args = args;
+ this.res = res;
+ }
+ }
private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo res) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackage");
- installPackageLI(args, res);
+ installPackagesLI(Collections.singletonList(new InstallRequest(args, res)));
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
- private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
+ private static class CommitRequest {
+ final Map<String, ReconciledPackage> reconciledPackages;
+
+ private CommitRequest(Map<String, ReconciledPackage> reconciledPackages) {
+ this.reconciledPackages = reconciledPackages;
+ }
+ }
+ private static class ReconcileRequest {
+ final Map<String, ScanResult> scannedPackages;
+
+ private ReconcileRequest(Map<String, ScanResult> scannedPackages) {
+ this.scannedPackages = scannedPackages;
+ }
+ }
+ private static class ReconcileFailure extends PackageManagerException {
+ public ReconcileFailure(String message) {
+ super("Invalid reconcile request: " + message);
+ }
+ };
+
+ /**
+ * A container of all data needed to commit a package to in-memory data structures and to disk.
+ * Ideally most of the data contained in this class will move into a PackageSetting it contains.
+ */
+ private static class ReconciledPackage {}
+
+ @GuardedBy("mPackages")
+ private static Map<String, ReconciledPackage> reconcilePackagesLocked(
+ final ReconcileRequest request) throws ReconcileFailure {
+ return Collections.emptyMap();
+ }
+
+ @GuardedBy("mPackages")
+ private boolean commitPackagesLocked(final CommitRequest request) {
+ return true;
+ }
+
+ @GuardedBy("mInstallLock")
+ private void installPackagesLI(List<InstallRequest> requests) {
+ Map<String, ScanResult> scans = new ArrayMap<>(requests.size());
+ for (InstallRequest request : requests) {
+ // TODO(b/109941548): remove this once we've pulled everything from it and into scan,
+ // reconcile or commit.
+ preparePackageLI(request.args, request.res);
+
+ // TODO(b/109941548): scan package and get result
+ }
+ ReconcileRequest reconcileRequest = new ReconcileRequest(scans);
+ Map<String, ReconciledPackage> reconciledPackages;
+ try {
+ reconciledPackages = reconcilePackagesLocked(reconcileRequest);
+ } catch (ReconcileFailure e) {
+ // TODO(b/109941548): set install args error
+ return;
+ }
+ CommitRequest request = new CommitRequest(reconciledPackages);
+ if (!commitPackagesLocked(request)) {
+ // TODO(b/109941548): set install args error
+ return;
+ }
+ // TODO(b/109941548) post-commit actions (dex-opt, etc.)
+ }
+
+ @Deprecated
+ @GuardedBy("mInstallLock")
+ private void preparePackageLI(InstallArgs args, PackageInstalledInfo res) {
final int installFlags = args.installFlags;
final String installerPackageName = args.installerPackageName;
final String volumeUuid = args.volumeUuid;
@@ -24127,7 +24197,7 @@
}
@Override
- public boolean isLegacySystemApp(Package pkg) {
+ public boolean isLegacySystemApp(PackageParser.Package pkg) {
synchronized (mPackages) {
final PackageSetting ps = (PackageSetting) pkg.mExtras;
return mPromoteSystemApps