diff options
3 files changed, 64 insertions, 8 deletions
| diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index 9329f063aee5..0d417e457509 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -136,9 +136,7 @@ public class Installer extends SystemService {      }      /** -     * @param isolated indicates if this object should <em>not</em> connect to -     *            the real {@code installd}. All remote calls will be ignored -     *            unless you extend this class and intercept them. +     * @param isolated Make the installer isolated. See {@link isIsolated}.       */      public Installer(Context context, boolean isolated) {          super(context); @@ -153,6 +151,15 @@ public class Installer extends SystemService {          mWarnIfHeld = warnIfHeld;      } +    /** +     * Returns true if the installer is isolated, i.e. if this object should <em>not</em> connect to +     * the real {@code installd}. All remote calls will be ignored unless you extend this class and +     * intercept them. +     */ +    public boolean isIsolated() { +        return mIsolated; +    } +      @Override      public void onStart() {          if (mIsolated) { diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java index 767c0a73bc54..6a2ddc8f94b0 100644 --- a/services/core/java/com/android/server/pm/OtaDexoptService.java +++ b/services/core/java/com/android/server/pm/OtaDexoptService.java @@ -16,6 +16,7 @@  package com.android.server.pm; +import static com.android.server.pm.DexOptHelper.useArtService;  import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;  import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;  import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; @@ -301,6 +302,15 @@ public class OtaDexoptService extends IOtaDexopt.Stub {                      throws InstallerException {                  final StringBuilder builder = new StringBuilder(); +                if (useArtService()) { +                    if ((dexFlags & DEXOPT_SECONDARY_DEX) != 0) { +                        // installd may change the reference profile in place for secondary dex +                        // files, which isn't safe with the lock free approach in ART Service. +                        throw new IllegalArgumentException( +                                "Invalid OTA dexopt call for secondary dex"); +                    } +                } +                  // The current version. For v10, see b/115993344.                  builder.append("10 "); @@ -353,7 +363,6 @@ public class OtaDexoptService extends IOtaDexopt.Stub {          PackageDexOptimizer optimizer = new OTADexoptPackageDexOptimizer(                  collectingInstaller, mPackageManagerService.mInstallLock, mContext); -        // TODO(b/251903639): Allow this use of legacy dexopt code even when ART Service is enabled.          try {              optimizer.performDexOpt(pkg, pkgSetting, null /* ISAs */,                      null /* CompilerStats.PackageStats */, @@ -362,9 +371,19 @@ public class OtaDexoptService extends IOtaDexopt.Stub {                      new DexoptOptions(pkg.getPackageName(), compilationReason,                              DexoptOptions.DEXOPT_BOOT_COMPLETE));          } catch (LegacyDexoptDisabledException e) { -            throw new RuntimeException(e); +            // OTA is still allowed to use the legacy dexopt code even when ART Service is enabled. +            // The installer is isolated and won't call into installd, and the dexopt() method is +            // overridden to only collect the command above. Hence we shouldn't go into any code +            // path where this exception is thrown. +            Slog.wtf(TAG, e);          } +        // ART Service compat note: These commands are consumed by the otapreopt binary, which uses +        // the same legacy dexopt code as installd to invoke dex2oat. It provides output path +        // implementations (see calculate_odex_file_path and create_cache_path in +        // frameworks/native/cmds/installd/otapreopt.cpp) to write to different odex files than +        // those used by ART Service in its ordinary operations, so it doesn't interfere with ART +        // Service even when dalvik.vm.useartservice is true.          return commands;      } diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index 0a90e7a30db6..8a4080ff029d 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -18,6 +18,7 @@ package com.android.server.pm;  import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DISABLED; +import static com.android.server.pm.DexOptHelper.useArtService;  import static com.android.server.pm.Installer.DEXOPT_BOOTCOMPLETE;  import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE;  import static com.android.server.pm.Installer.DEXOPT_ENABLE_HIDDEN_API_CHECKS; @@ -329,8 +330,22 @@ public class PackageDexOptimizer {              String profileName = ArtManager.getProfileName(                      i == 0 ? null : pkg.getSplitNames()[i - 1]); -            final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary() -                    || packageUseInfo.isUsedByOtherApps(path); + +            final boolean isUsedByOtherApps; +            if (options.isDexoptAsSharedLibrary()) { +                isUsedByOtherApps = true; +            } else if (useArtService()) { +                // We get here when collecting dexopt commands in OTA preopt, even when ART Service +                // is in use. packageUseInfo isn't useful in that case since the legacy dex use +                // database hasn't been updated. So we'd have to query ART Service instead, but it +                // doesn't provide that API. Just cop-out and bypass the cloud profile handling. +                // That means such apps will get preopted wrong, and we'll leave it to a later +                // background dexopt after reboot instead. +                isUsedByOtherApps = false; +            } else { +                isUsedByOtherApps = packageUseInfo.isUsedByOtherApps(path); +            } +              String compilerFilter = getRealCompilerFilter(pkg, options.getCompilerFilter());              // If the app is used by other apps, we must not use the existing profile because it              // may contain user data, unless the profile is newly created on install. @@ -446,6 +461,14 @@ public class PackageDexOptimizer {      private boolean prepareCloudProfile(AndroidPackage pkg, String profileName, String path,              @Nullable String dexMetadataPath) throws LegacyDexoptDisabledException {          if (dexMetadataPath != null) { +            if (mInstaller.isIsolated()) { +                // If the installer is isolated, the two calls to it below will return immediately, +                // so this only short-circuits that a bit. We need to do it to avoid the +                // LegacyDexoptDisabledException getting thrown first, when we get here during OTA +                // preopt and ART Service is enabled. +                return true; +            } +              try {                  // Make sure we don't keep any existing contents.                  mInstaller.deleteReferenceProfile(pkg.getPackageName(), profileName); @@ -879,7 +902,12 @@ public class PackageDexOptimizer {      private int getDexoptNeeded(String packageName, String path, String isa, String compilerFilter,              String classLoaderContext, int profileAnalysisResult, boolean downgrade,              int dexoptFlags, String oatDir) throws LegacyDexoptDisabledException { -        Installer.checkLegacyDexoptDisabled(); +        // Allow calls from OtaDexoptService even when ART Service is in use. The installer is +        // isolated in that case so later calls to it won't call into installd anyway. +        if (!mInstaller.isIsolated()) { +            Installer.checkLegacyDexoptDisabled(); +        } +          final boolean shouldBePublic = (dexoptFlags & DEXOPT_PUBLIC) != 0;          final boolean isProfileGuidedFilter = (dexoptFlags & DEXOPT_PROFILE_GUIDED) != 0;          boolean newProfile = profileAnalysisResult == PROFILE_ANALYSIS_OPTIMIZE; @@ -948,6 +976,8 @@ public class PackageDexOptimizer {       */      private int analyseProfiles(AndroidPackage pkg, int uid, String profileName,              String compilerFilter) throws LegacyDexoptDisabledException { +        Installer.checkLegacyDexoptDisabled(); +          // Check if we are allowed to merge and if the compiler filter is profile guided.          if (!isProfileGuidedCompilerFilter(compilerFilter)) {              return PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA; |