Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dd63eba2 authored by Martin Stjernholm's avatar Martin Stjernholm
Browse files

Exclude the system server from background dexopt and remove the code

that optimizes it.

The system server can only be compiled and signed by odrefresh in early
boot, so it is no use capturing dex load events for it.

This complements commit 9789a45e.

Test: boot
Bug: 254043366
Change-Id: Idda7957da72d72ddccccf95580d1bd85b520358f
parent 98c05366
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -555,9 +555,9 @@ public final class DexOptHelper {
    private int performDexOptInternalWithDependenciesLI(
            AndroidPackage p, @NonNull PackageStateInternal pkgSetting, DexoptOptions options)
            throws LegacyDexoptDisabledException {
        // System server gets a special path.
        if (PLATFORM_PACKAGE_NAME.equals(p.getPackageName())) {
            return mPm.getDexManager().dexoptSystemServer(options);
            // This needs to be done in odrefresh in early boot, for security reasons.
            throw new IllegalArgumentException("Cannot dexopt the system server");
        }

        // Select the dex optimizer based on the force parameter.
+8 −65
Original line number Diff line number Diff line
@@ -59,7 +59,6 @@ import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.os.WorkSource;
import android.os.storage.StorageManager;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -184,10 +183,13 @@ public class PackageDexOptimizer {
    }

    boolean canOptimizePackage(@NonNull AndroidPackage pkg) {
        // The system package has to be optimized during early boot by odrefresh instead.
        if (PLATFORM_PACKAGE_NAME.equals(pkg.getPackageName())) {
            return false;
        }

        // We do not dexopt a package with no code.
        // Note that the system package is marked as having no code, however we can
        // still optimize it via dexoptSystemServerPath.
        if (!PLATFORM_PACKAGE_NAME.equals(pkg.getPackageName()) && !pkg.isHasCode()) {
        if (!pkg.isHasCode()) {
            return false;
        }

@@ -223,8 +225,8 @@ public class PackageDexOptimizer {
            PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options)
            throws LegacyDexoptDisabledException {
        if (PLATFORM_PACKAGE_NAME.equals(pkg.getPackageName())) {
            throw new IllegalArgumentException("System server dexopting should be done via "
                    + " DexManager and PackageDexOptimizer#dexoptSystemServerPath");
            throw new IllegalArgumentException(
                    "System server dexopting should be done via odrefresh");
        }
        if (pkg.getUid() == -1) {
            throw new IllegalArgumentException("Dexopt for " + pkg.getPackageName()
@@ -523,65 +525,6 @@ public class PackageDexOptimizer {
        }
    }

    /**
     * Perform dexopt (if needed) on a system server code path).
     */
    @GuardedBy("mInstallLock")
    @DexOptResult
    public int dexoptSystemServerPath(String dexPath, PackageDexUsage.DexUseInfo dexUseInfo,
            DexoptOptions options) throws LegacyDexoptDisabledException {
        int dexoptFlags = DEXOPT_PUBLIC
                | (options.isBootComplete() ? DEXOPT_BOOTCOMPLETE : 0)
                | (options.isDexoptIdleBackgroundJob() ? DEXOPT_IDLE_BACKGROUND_JOB : 0);

        int result = DEX_OPT_SKIPPED;
        for (String isa : dexUseInfo.getLoaderIsas()) {
            int dexoptNeeded = getDexoptNeeded(
                    PackageManagerService.PLATFORM_PACKAGE_NAME,
                    dexPath,
                    isa,
                    options.getCompilerFilter(),
                    dexUseInfo.getClassLoaderContext(),
                    PROFILE_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES,
                    /* downgrade= */ false,
                    dexoptFlags,
                    /* oatDir= */ null);

            if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) {
                continue;
            }
            try {
                synchronized (mInstallLock) {
                    boolean completed = getInstallerLI().dexopt(
                            dexPath,
                            android.os.Process.SYSTEM_UID,
                            /* pkgName= */ "android",
                            isa,
                            dexoptNeeded,
                            /* outputPath= */ null,
                            dexoptFlags,
                            options.getCompilerFilter(),
                            StorageManager.UUID_PRIVATE_INTERNAL,
                            dexUseInfo.getClassLoaderContext(),
                            /* seInfo= */ null,
                            /* downgrade= */ false,
                            /* targetSdkVersion= */ 0,
                            /* profileName= */ null,
                            /* dexMetadataPath= */ null,
                            getReasonName(options.getCompilationReason()));
                    if (!completed) {
                        return DEX_OPT_CANCELLED;
                    }
                }
            } catch (InstallerException e) {
                Slog.w(TAG, "Failed to dexopt", e);
                return DEX_OPT_FAILED;
            }
            result = DEX_OPT_PERFORMED;
        }
        return result;
    }

    private String getAugmentedReasonName(int compilationReason, boolean useDexMetadata) {
        String annotation = useDexMetadata
                ? ArtManagerService.DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION : "";
+0 −83
Original line number Diff line number Diff line
@@ -564,89 +564,6 @@ public class DexManager {
        return success;
    }

    /**
     * Performs dexopt on system server dex files.
     *
     * <p>Verfifies that the package name is {@link PackageManagerService#PLATFORM_PACKAGE_NAME}.
     *
     * @return
     * <p>PackageDexOptimizer.DEX_OPT_SKIPPED if dexopt was skipped because no system server
     * files were recorded or if no dexopt was needed.
     * <p>PackageDexOptimizer.DEX_OPT_FAILED if any dexopt operation failed.
     * <p>PackageDexOptimizer.DEX_OPT_PERFORMED if all dexopt operations succeeded.
     */
    public int dexoptSystemServer(DexoptOptions options) throws LegacyDexoptDisabledException {
        // TODO(b/254043366): Clean this up.
        if (!isPlatformPackage(options.getPackageName())) {
            Slog.wtf(TAG, "Non system server package used when trying to dexopt system server:"
                    + options.getPackageName());
            return PackageDexOptimizer.DEX_OPT_FAILED;
        }

        // Override compiler filter for system server to the expected one.
        //
        // We could let the caller do this every time the invoke PackageManagerServer#dexopt.
        // However, there are a few places were this will need to be done which creates
        // redundancy and the danger of overlooking the config (and thus generating code that will
        // waste storage and time).
        DexoptOptions overriddenOptions = options.overrideCompilerFilter(
                SYSTEM_SERVER_COMPILER_FILTER);

        PackageDexOptimizer pdo = getPackageDexOptimizer(overriddenOptions);
        String packageName = overriddenOptions.getPackageName();
        PackageUseInfo useInfo = getPackageUseInfoOrDefault(packageName);
        if (useInfo.getDexUseInfoMap().isEmpty()) {
            if (DEBUG) {
                Slog.d(TAG, "No dex files recorded for system server");
            }
            // Nothing to compile, return true.
            return PackageDexOptimizer.DEX_OPT_SKIPPED;
        }

        boolean usageUpdated = false;
        int result = PackageDexOptimizer.DEX_OPT_SKIPPED;
        for (Map.Entry<String, DexUseInfo> entry : useInfo.getDexUseInfoMap().entrySet()) {
            String dexPath = entry.getKey();
            DexUseInfo dexUseInfo = entry.getValue();
            if (!Files.exists(Paths.get(dexPath))) {
                if (DEBUG) {
                    Slog.w(TAG, "A dex file previously loaded by System Server does not exist "
                            + " anymore: " + dexPath);
                }
                usageUpdated = mPackageDexUsage.removeDexFile(
                            packageName, dexPath, dexUseInfo.getOwnerUserId()) || usageUpdated;
                continue;
            }

            if (dexUseInfo.isUnsupportedClassLoaderContext()
                    || dexUseInfo.isVariableClassLoaderContext()) {
                String debugMsg = dexUseInfo.isUnsupportedClassLoaderContext()
                        ? "unsupported"
                        : "variable";
                Slog.w(TAG, "Skipping dexopt for system server path loaded with " + debugMsg
                        + " class loader context: " + dexPath);
                continue;
            }

            int newResult = pdo.dexoptSystemServerPath(dexPath, dexUseInfo, overriddenOptions);

            // The end result is:
            //  - FAILED if any path failed,
            //  - PERFORMED if at least one path needed compilation,
            //  - SKIPPED when all paths are up to date
            if ((result != PackageDexOptimizer.DEX_OPT_FAILED)
                    && (newResult != PackageDexOptimizer.DEX_OPT_SKIPPED)) {
                result = newResult;
            }
        }

        if (usageUpdated) {
            mPackageDexUsage.maybeWriteAsync();
        }

        return result;
    }

    /**
     * Select the dex optimizer based on the force parameter.
     * Forced compilation is done through ForcedUpdatePackageDexOptimizer which will adjust