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

Commit 60014e1c authored by Jiakai Zhang's avatar Jiakai Zhang Committed by Android (Google) Code Review
Browse files

Merge "Preserve user's reference profile for apps used by other apps." into tm-dev

parents fdaa18f5 da575809
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -692,6 +692,20 @@ public class Installer extends SystemService {
        }
    }

    /**
     * Deletes the reference profile with the given name of the given package.
     * @throws InstallerException if the deletion fails.
     */
    public void deleteReferenceProfile(String packageName, String profileName)
            throws InstallerException {
        if (!checkBeforeRemote()) return;
        try {
            mInstalld.deleteReferenceProfile(packageName, profileName);
        } catch (Exception e) {
            throw InstallerException.from(e);
        }
    }

    public void createUserData(String uuid, int userId, int userSerial, int flags)
            throws InstallerException {
        if (!checkBeforeRemote()) return;
+92 −67
Original line number Diff line number Diff line
@@ -324,12 +324,12 @@ public class PackageDexOptimizer {
            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.
            final boolean resetProfile = isProfileGuidedCompilerFilter(compilerFilter)
            final boolean useCloudProfile = isProfileGuidedCompilerFilter(compilerFilter)
                    && isUsedByOtherApps
                    && options.getCompilationReason() != PackageManagerService.REASON_INSTALL;

            String dexMetadataPath = null;
            if (options.isDexoptInstallWithDexMetadata() || resetProfile) {
            if (options.isDexoptInstallWithDexMetadata() || useCloudProfile) {
                File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(new File(path));
                dexMetadataPath = dexMetadataFile == null
                        ? null : dexMetadataFile.getAbsolutePath();
@@ -339,22 +339,35 @@ public class PackageDexOptimizer {
            // PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA which will be a no-op with respect to
            // profiles.
            int profileAnalysisResult = PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA;
            if (resetProfile) {
                if (!resetProfile(pkg, profileName, path, dexMetadataPath)) {
            if (options.isCheckForProfileUpdates()) {
                profileAnalysisResult =
                        analyseProfiles(pkg, sharedGid, profileName, compilerFilter);
            }
            String cloudProfileName = null;
            try {
                if (useCloudProfile) {
                    cloudProfileName = "cloud-" + profileName;
                    if (prepareCloudProfile(pkg, cloudProfileName, path, dexMetadataPath)) {
                        profileName = cloudProfileName;
                    } else {
                        // Fall back to use the shared filter.
                        compilerFilter =
                                PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
                                        PackageManagerService.REASON_SHARED);
                        profileName = null;
                    }
            } else if (options.isCheckForProfileUpdates()) {
                profileAnalysisResult =
                        analyseProfiles(pkg, sharedGid, profileName, compilerFilter);

                    // We still run `analyseProfiles` even if `useCloudProfile` is true because it
                    // merges profiles into the reference profile, which a system API
                    // `ArtManager.snapshotRuntimeProfile` takes snapshots from. However, we don't
                    // want the result to affect the decision of whether dexopt is needed.
                    profileAnalysisResult = PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA;
                }

                // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct
                // flags.
            final int dexoptFlags = getDexFlags(pkg, pkgSetting, compilerFilter, resetProfile,
                    options);
                final int dexoptFlags = getDexFlags(pkg, pkgSetting, compilerFilter,
                        useCloudProfile, options);

                for (String dexCodeIsa : dexCodeInstructionSets) {
                    int newResult = dexOptPath(pkg, pkgSetting, path, dexCodeIsa, compilerFilter,
@@ -400,27 +413,39 @@ public class PackageDexOptimizer {
                        result = newResult;
                    }
                }
            } finally {
                if (cloudProfileName != null) {
                    try {
                        mInstaller.deleteReferenceProfile(pkg.getPackageName(), cloudProfileName);
                    } catch (InstallerException e) {
                        Slog.w(TAG, "Failed to cleanup cloud profile", e);
                    }
                }
            }
        }
        return result;
    }

    /**
     * Resets the profiles of the dex file at {@code path} belonging to the package {@code pkg} to
     * the initial state as if the package is newly installed. Returns true on success, or false
     * otherwise.
     * Creates a profile with the name {@code profileName} from the dex metadata file at {@code
     * dexMetadataPath} for the dex file at {@code path} belonging to the package {@code pkg}.
     *
     * @return true on success, or false otherwise.
     */
    @GuardedBy("mInstallLock")
    private boolean resetProfile(AndroidPackage pkg, String profileName, String path,
    private boolean prepareCloudProfile(AndroidPackage pkg, String profileName, String path,
            @Nullable String dexMetadataPath) {
        if (dexMetadataPath != null) {
            try {
                mInstaller.clearAppProfiles(pkg.getPackageName(), profileName);
                // Make sure we don't keep any existing contents.
                mInstaller.deleteReferenceProfile(pkg.getPackageName(), profileName);

                final int appId = UserHandle.getAppId(pkg.getUid());
                mInstaller.prepareAppProfile(pkg.getPackageName(), UserHandle.USER_NULL,
                        appId, profileName, path, dexMetadataPath);
                mInstaller.prepareAppProfile(pkg.getPackageName(), UserHandle.USER_NULL, appId,
                        profileName, path, dexMetadataPath);
                return true;
            } catch (InstallerException e) {
                Slog.w(TAG, "Failed to reset profile", e);
                Slog.w(TAG, "Failed to prepare cloud profile", e);
                return false;
            }
        } else {
@@ -835,16 +860,16 @@ public class PackageDexOptimizer {
    private int getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options) {
        return getDexFlags((info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0,
                info.getHiddenApiEnforcementPolicy(), info.splitDependencies,
                info.requestsIsolatedSplitLoading(), compilerFilter, false /* resetProfile */,
                info.requestsIsolatedSplitLoading(), compilerFilter, false /* useCloudProfile */,
                options);
    }

    private int getDexFlags(AndroidPackage pkg, @NonNull PackageStateInternal pkgSetting,
            String compilerFilter, boolean resetProfile, DexoptOptions options) {
            String compilerFilter, boolean useCloudProfile, DexoptOptions options) {
        return getDexFlags(pkg.isDebuggable(),
                AndroidPackageUtils.getHiddenApiEnforcementPolicy(pkg, pkgSetting),
                pkg.getSplitDependencies(), pkg.isIsolatedSplitLoading(), compilerFilter,
                resetProfile, options);
                useCloudProfile, options);
    }

    /**
@@ -853,15 +878,15 @@ public class PackageDexOptimizer {
     */
    private int getDexFlags(boolean debuggable, int hiddenApiEnforcementPolicy,
            SparseArray<int[]> splitDependencies, boolean requestsIsolatedSplitLoading,
            String compilerFilter, boolean resetProfile, DexoptOptions options) {
            String compilerFilter, boolean useCloudProfile, DexoptOptions options) {
        // Profile guide compiled oat files should not be public unles they are based
        // on profiles from dex metadata archives.
        // The flag isDexoptInstallWithDexMetadata applies only on installs when we know that
        // the user does not have an existing profile.
        // The flag resetProfile applies only when the existing profile is already reset.
        // The flag useCloudProfile applies only when the cloud profile should be used.
        boolean isProfileGuidedFilter = isProfileGuidedCompilerFilter(compilerFilter);
        boolean isPublic = !isProfileGuidedFilter || options.isDexoptInstallWithDexMetadata()
                || resetProfile;
                || useCloudProfile;
        int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
        // Some apps are executed with restrictions on hidden API usage. If this app is one
        // of them, pass a flag to dexopt to enable the same restrictions during compilation.