diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index 1476e6ea8904b..93dcc72c0ae84 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -203,6 +203,11 @@ public final class Installer extends SystemService { mInstaller.execute("linkfile", relativePath, fromBase, toBase); } + public void moveAb(String apkPath, String instructionSet, String outputPath) + throws InstallerException { + mInstaller.execute("move_ab", apkPath, instructionSet, outputPath); + } + private static void assertValidInstructionSet(String instructionSet) throws InstallerException { for (String abi : Build.SUPPORTED_ABIS) { diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java index 3d2a3555ecd93..67aeed116df50 100644 --- a/services/core/java/com/android/server/pm/OtaDexoptService.java +++ b/services/core/java/com/android/server/pm/OtaDexoptService.java @@ -16,36 +16,28 @@ package com.android.server.pm; -import android.app.AppGlobals; +import static com.android.server.pm.Installer.DEXOPT_OTA; +import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; +import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; + import android.content.Context; -import android.content.Intent; import android.content.pm.IOtaDexopt; import android.content.pm.PackageParser; import android.content.pm.PackageParser.Package; -import android.content.pm.ResolveInfo; import android.os.Environment; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; -import android.os.UserHandle; import android.os.storage.StorageManager; -import android.util.ArraySet; import android.util.Log; +import android.util.Slog; -import dalvik.system.DexFile; +import com.android.internal.os.InstallerConnection.InstallerException; import java.io.File; import java.io.FileDescriptor; -import java.util.ArrayList; import java.util.Collection; -import java.util.Date; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; import java.util.List; -import java.util.Set; - -import static com.android.server.pm.Installer.DEXOPT_OTA; /** * A service for A/B OTA dexopting. @@ -70,6 +62,9 @@ public class OtaDexoptService extends IOtaDexopt.Stub { // Use the package manager install and install lock here for the OTA dex optimizer. mPackageDexOptimizer = new OTADexoptPackageDexOptimizer(packageManagerService.mInstaller, packageManagerService.mInstallLock, context); + + // Now it's time to check whether we need to move any A/B artifacts. + moveAbArtifacts(packageManagerService.mInstaller); } public static OtaDexoptService main(Context context, @@ -150,20 +145,50 @@ public class OtaDexoptService extends IOtaDexopt.Stub { false /* extractOnly */); } - private ArraySet getPackageNamesForIntent(Intent intent, int userId) { - List ris = null; - try { - ris = AppGlobals.getPackageManager().queryIntentReceivers( - intent, null, 0, userId); - } catch (RemoteException e) { + private void moveAbArtifacts(Installer installer) { + if (mDexoptPackages != null) { + throw new IllegalStateException("Should not be ota-dexopting when trying to move."); } - ArraySet pkgNames = new ArraySet(ris == null ? 0 : ris.size()); - if (ris != null) { - for (ResolveInfo ri : ris) { - pkgNames.add(ri.activityInfo.packageName); + + // Look into all packages. + Collection pkgs = mPackageManagerService.getPackages(); + for (PackageParser.Package pkg : pkgs) { + if (pkg == null) { + continue; + } + + // Does the package have code? If not, there won't be any artifacts. + if (!PackageDexOptimizer.canOptimizePackage(pkg)) { + continue; + } + if (pkg.codePath == null) { + Slog.w(TAG, "Package " + pkg + " can be optimized but has null codePath"); + 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")) { + continue; + } + + final String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo); + final List paths = pkg.getAllCodePathsExcludingResourceOnly(); + final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets); + for (String dexCodeInstructionSet : dexCodeInstructionSets) { + for (String path : paths) { + String oatDir = PackageDexOptimizer.getOatDir(new File(pkg.codePath)). + getAbsolutePath(); + + // TODO: Check first whether there is an artifact, to save the roundtrip time. + + try { + installer.moveAb(path, dexCodeInstructionSet, oatDir); + } catch (InstallerException e) { + } + } } } - return pkgNames; } private static class OTADexoptPackageDexOptimizer extends diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 31311f7f0b006..5562e76c024e6 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -19209,4 +19209,14 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); boolean isHistoricalPackageUsageAvailable() { return mPackageUsage.isHistoricalPackageUsageAvailable(); } + + /** + * Return a copy of the collection of packages known to the package manager. + * @return A copy of the values of mPackages. + */ + Collection getPackages() { + synchronized (mPackages) { + return new ArrayList<>(mPackages.values()); + } + } } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 9aa2b9452b87c..b8c31e3f063ef 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -431,6 +431,24 @@ public final class SystemServer { mPackageManager = mSystemContext.getPackageManager(); Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); + // Manages A/B OTA dexopting. This is a bootstrap service as we need it to rename + // A/B artifacts after boot, before anything else might touch/need them. + // Note: this isn't needed during decryption (we don't have /data anyways). + if (!mOnlyCore) { + boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt", + false); + if (!disableOtaDexopt) { + traceBeginAndSlog("StartOtaDexOptService"); + try { + OtaDexoptService.main(mSystemContext, mPackageManagerService); + } catch (Throwable e) { + reportWtf("starting OtaDexOptService", e); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); + } + } + } + traceBeginAndSlog("StartUserManagerService"); ServiceManager.addService(Context.USER_SERVICE, UserManagerService.getInstance()); Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); @@ -1124,19 +1142,6 @@ public final class SystemServer { reportWtf("starting BackgroundDexOptService", e); } Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); - - // Manages A/B OTA dexopting. - boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt", - false); - if (!disableOtaDexopt) { - traceBeginAndSlog("StartOtaDexOptService"); - try { - OtaDexoptService.main(mSystemContext, mPackageManagerService); - } catch (Throwable e) { - reportWtf("starting BackgroundDexOptService", e); - } - Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); - } } mSystemServiceManager.startService(LauncherAppsService.class);