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

Commit 63aa98db authored by Jackal Guo's avatar Jackal Guo
Browse files

Invalidate the cache for APK-in-APEX

PackageCacher uses file name and modified time to determine if the
parsed cache is still valid. However, all APK-in-APEX would have
the same name and modified time. This results in the out-of-date
cache would be treated as valid.

We need to invlidate the cache for the APK-in-APEX when that APEX
is going to be installed.

Bug: 152352677
Test: atest -p frameworks/base/core/java/android/content/pm
Test: atest -p frameworks/base/services/core/java/android/content/pm
Test: Update/rollback an APK-in-APEX, and check its version code

Change-Id: I2a722036d8b1e9c5121d385f8d0667fb908cc7a1
parent ec38d551
Loading
Loading
Loading
Loading
+6 −0
Original line number Original line Diff line number Diff line
@@ -479,6 +479,12 @@ public abstract class PackageManagerInternal {
     */
     */
    public abstract void pruneInstantApps();
    public abstract void pruneInstantApps();


    /**
     * Prunes the cache of the APKs in the given APEXes.
     * @param apexPackages The list of APEX packages that may contain APK-in-APEX.
     */
    public abstract void pruneCachedApksInApex(@NonNull List<PackageInfo> apexPackages);

    /**
    /**
     * @return The SetupWizard package name.
     * @return The SetupWizard package name.
     */
     */
+20 −0
Original line number Original line Diff line number Diff line
@@ -348,6 +348,7 @@ import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.dex.PackageDexUsage;
import com.android.server.pm.dex.PackageDexUsage;
import com.android.server.pm.dex.ViewCompiler;
import com.android.server.pm.dex.ViewCompiler;
import com.android.server.pm.parsing.PackageCacher;
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.library.PackageBackwardCompatibility;
import com.android.server.pm.parsing.library.PackageBackwardCompatibility;
@@ -24111,6 +24112,25 @@ public class PackageManagerService extends IPackageManager.Stub
            mInstantAppRegistry.pruneInstantApps();
            mInstantAppRegistry.pruneInstantApps();
        }
        }
        @Override
        public void pruneCachedApksInApex(@NonNull List<PackageInfo> apexPackages) {
            if (mCacheDir == null) {
                return;
            }
            final PackageCacher cacher = new PackageCacher(mCacheDir);
            synchronized (mLock) {
                for (int i = 0, size = apexPackages.size(); i < size; i++) {
                    final List<String> apkNames =
                            mApexManager.getApksInApex(apexPackages.get(i).packageName);
                    for (int j = 0, apksInApex = apkNames.size(); j < apksInApex; j++) {
                        final AndroidPackage pkg = getPackage(apkNames.get(j));
                        cacher.cleanCachedResult(new File(pkg.getCodePath()));
                    }
                }
            }
        }
        @Override
        @Override
        public String getSetupWizardPackageName() {
        public String getSetupWizardPackageName() {
            return mSetupWizardPackage;
            return mSetupWizardPackage;
+6 −1
Original line number Original line Diff line number Diff line
@@ -1218,8 +1218,9 @@ public class StagingManager {
            // APEX checks. For single-package sessions, check if they contain an APEX. For
            // APEX checks. For single-package sessions, check if they contain an APEX. For
            // multi-package sessions, find all the child sessions that contain an APEX.
            // multi-package sessions, find all the child sessions that contain an APEX.
            if (hasApex) {
            if (hasApex) {
                final List<PackageInfo> apexPackages;
                try {
                try {
                    final List<PackageInfo> apexPackages = submitSessionToApexService(session);
                    apexPackages = submitSessionToApexService(session);
                    for (int i = 0, size = apexPackages.size(); i < size; i++) {
                    for (int i = 0, size = apexPackages.size(); i < size; i++) {
                        validateApexSignature(apexPackages.get(i));
                        validateApexSignature(apexPackages.get(i));
                    }
                    }
@@ -1227,6 +1228,10 @@ public class StagingManager {
                    session.setStagedSessionFailed(e.error, e.getMessage());
                    session.setStagedSessionFailed(e.error, e.getMessage());
                    return;
                    return;
                }
                }

                final PackageManagerInternal packageManagerInternal =
                        LocalServices.getService(PackageManagerInternal.class);
                packageManagerInternal.pruneCachedApksInApex(apexPackages);
            }
            }


            notifyPreRebootVerification_Apex_Complete(session.sessionId);
            notifyPreRebootVerification_Apex_Complete(session.sessionId);
+15 −0
Original line number Original line Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.pm.parsing;


import android.annotation.NonNull;
import android.annotation.NonNull;
import android.content.pm.PackageParserCacheHelper;
import android.content.pm.PackageParserCacheHelper;
import android.os.FileUtils;
import android.os.Parcel;
import android.os.Parcel;
import android.system.ErrnoException;
import android.system.ErrnoException;
import android.system.Os;
import android.system.Os;
@@ -197,4 +198,18 @@ public class PackageCacher {
            Slog.w(TAG, "Error saving package cache.", e);
            Slog.w(TAG, "Error saving package cache.", e);
        }
        }
    }
    }

    /**
     * Delete the cache files for the given {@code packageFile}.
     */
    public void cleanCachedResult(@NonNull File packageFile) {
        final String packageName = packageFile.getName();
        final File[] files = FileUtils.listFilesOrEmpty(mCacheDir,
                (dir, name) -> name.startsWith(packageName));
        for (File file : files) {
            if (!file.delete()) {
                Slog.e(TAG, "Unable to clean cache file: " + file);
            }
        }
    }
}
}