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

Commit d9180ce8 authored by Chun-Wei Wang's avatar Chun-Wei Wang Committed by Android (Google) Code Review
Browse files

Merge "Scan APEX packages"

parents f1609db5 e3976630
Loading
Loading
Loading
Loading
+10 −15
Original line number Diff line number Diff line
@@ -104,11 +104,11 @@ public abstract class ApexManager {

    static class ScanResult {
        public final ApexInfo apexInfo;
        public final ParsedPackage parsedPackage;
        public final AndroidPackage pkg;
        public final String packageName;
        ScanResult(ApexInfo apexInfo, ParsedPackage parsedPackage, String packageName) {
        ScanResult(ApexInfo apexInfo, AndroidPackage pkg, String packageName) {
            this.apexInfo = apexInfo;
            this.parsedPackage = parsedPackage;
            this.pkg = pkg;
            this.packageName = packageName;
        }
    }
@@ -357,8 +357,10 @@ public abstract class ApexManager {

    /**
     * Performs a non-staged install of the given {@code apexFile}.
     *
     * @return {@code ApeInfo} about the newly installed APEX package.
     */
    abstract void installPackage(File apexFile, PackageParser2 packageParser,
    abstract ApexInfo installPackage(File apexFile, PackageParser2 packageParser,
            ApexPackageInfo apexPackageInfo) throws PackageManagerException;

    /**
@@ -470,7 +472,7 @@ public abstract class ApexManager {
                ApexInfo ai = scanResult.apexInfo;
                String packageName = scanResult.packageName;
                for (ParsedApexSystemService service :
                        scanResult.parsedPackage.getApexSystemServices()) {
                        scanResult.pkg.getApexSystemServices()) {
                    String minSdkVersion = service.getMinSdkVersion();
                    if (minSdkVersion != null && !UnboundedSdkLevel.isAtLeast(minSdkVersion)) {
                        Slog.d(TAG, String.format(
@@ -896,7 +898,7 @@ public abstract class ApexManager {
        }

        @Override
        void installPackage(File apexFile, PackageParser2 packageParser,
        ApexInfo installPackage(File apexFile, PackageParser2 packageParser,
                ApexPackageInfo apexPackageInfo)
                throws PackageManagerException {
            try {
@@ -919,14 +921,7 @@ public abstract class ApexManager {
                            "It is forbidden to install new APEX packages");
                }
                checkApexSignature(existingApexPkg, newApexPkg);
                ApexInfo apexInfo = waitForApexService().installAndActivatePackage(
                        apexFile.getAbsolutePath());
                final ParsedPackage parsedPackage2 = packageParser.parsePackage(
                        new File(apexInfo.modulePath), flags, /* useCaches= */ false);
                final PackageInfo finalApexPkg = PackageInfoWithoutStateUtils.generate(
                        parsedPackage2, apexInfo, flags);
                // Installation was successful, time to update cached PackageInfo
                apexPackageInfo.notifyPackageInstalled(existingApexPkg, finalApexPkg);
                return waitForApexService().installAndActivatePackage(apexFile.getAbsolutePath());
            } catch (RemoteException e) {
                throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
                        "apexservice not available");
@@ -1166,7 +1161,7 @@ public abstract class ApexManager {
        }

        @Override
        void installPackage(File apexFile, PackageParser2 packageParser,
        ApexInfo installPackage(File apexFile, PackageParser2 packageParser,
                ApexPackageInfo apexPackageInfo) {
            throw new UnsupportedOperationException("APEX updates are not supported");
        }
+31 −4
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
import com.android.server.pm.pkg.parsing.ParsingPackageUtils;

@@ -50,6 +52,8 @@ import java.util.concurrent.ExecutorService;
 * including both APK and APEX. This class will no longer be needed when the migration is done.
 */
class ApexPackageInfo {
    public static final boolean ENABLE_FEATURE_SCAN_APEX = true;

    private static final String TAG = "ApexManager";
    private static final String VNDK_APEX_MODULE_NAME_PREFIX = "com.android.vndk.";

@@ -83,6 +87,12 @@ class ApexPackageInfo {
        }
    }

    void notifyScanResult(List<ApexManager.ScanResult> scanResults) {
        synchronized (mLock) {
            notifyScanResultLocked(scanResults);
        }
    }

    /**
     * Retrieves information about an APEX package.
     *
@@ -200,12 +210,29 @@ class ApexPackageInfo {
    }

    /**
     * Called by ApexManager to update cached PackageInfo when installing rebootless APEX.
     * Called to update cached PackageInfo when installing rebootless APEX.
     */
    void notifyPackageInstalled(PackageInfo oldApexPkg, PackageInfo newApexPkg) {
    void notifyPackageInstalled(ApexInfo apexInfo, PackageParser2 packageParser)
            throws PackageManagerException {
        final int flags = PackageManager.GET_META_DATA
                | PackageManager.GET_SIGNING_CERTIFICATES
                | PackageManager.GET_SIGNATURES;
        final ParsedPackage parsedPackage = packageParser.parsePackage(
                new File(apexInfo.modulePath), flags, /* useCaches= */ false);
        notifyPackageInstalled(apexInfo, parsedPackage.hideAsFinal());
    }

    void notifyPackageInstalled(ApexInfo apexInfo, AndroidPackage pkg) {
        final int flags = PackageManager.GET_META_DATA
                | PackageManager.GET_SIGNING_CERTIFICATES
                | PackageManager.GET_SIGNATURES;
        final PackageInfo newApexPkg = PackageInfoWithoutStateUtils.generate(
                pkg, apexInfo, flags);
        final String packageName = newApexPkg.packageName;
        synchronized (mLock) {
            for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
                if (mAllPackagesCache.get(i).equals(oldApexPkg)) {
                PackageInfo oldApexPkg = mAllPackagesCache.get(i);
                if (oldApexPkg.isActiveApex && oldApexPkg.packageName.equals(packageName)) {
                    if (isFactory(oldApexPkg)) {
                        oldApexPkg.isActiveApex = false;
                        mAllPackagesCache.add(newApexPkg);
@@ -264,7 +291,7 @@ class ApexPackageInfo {
            ApexInfo ai = result.apexInfo;

            final PackageInfo packageInfo = PackageInfoWithoutStateUtils.generate(
                    result.parsedPackage, ai, flags);
                    result.pkg, ai, flags);
            if (packageInfo == null) {
                throw new IllegalStateException("Unable to generate package info: "
                        + ai.modulePath);
+12 −2
Original line number Diff line number Diff line
@@ -185,9 +185,19 @@ final class InitAppsHelper {
    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
    private List<ApexManager.ScanResult> scanApexPackagesTraced(PackageParser2 packageParser) {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanApexPackages");

        try {
            return mApexPackageInfo.scanApexPackages(
            final List<ApexManager.ScanResult> apexScanResults;
            if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
                apexScanResults = mInstallPackageHelper.scanApexPackages(
                        mApexManager.getAllApexInfos(), mSystemParseFlags, mSystemScanFlags,
                        packageParser, mExecutorService);
                mApexPackageInfo.notifyScanResult(apexScanResults);
            } else {
                apexScanResults = mApexPackageInfo.scanApexPackages(
                        mApexManager.getAllApexInfos(), packageParser, mExecutorService);
            }
            return apexScanResults;
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
+68 −2
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ import static com.android.server.pm.PackageManagerService.EMPTY_INT_ARRAY;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static com.android.server.pm.PackageManagerService.POST_INSTALL;
import static com.android.server.pm.PackageManagerService.PRECOMPILE_LAYOUTS;
import static com.android.server.pm.PackageManagerService.SCAN_AS_APEX;
import static com.android.server.pm.PackageManagerService.SCAN_AS_APK_IN_APEX;
import static com.android.server.pm.PackageManagerService.SCAN_AS_FACTORY;
import static com.android.server.pm.PackageManagerService.SCAN_AS_FULL_APP;
@@ -92,6 +93,7 @@ import static com.android.server.pm.SharedUidMigration.BEST_EFFORT;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.apex.ApexInfo;
import android.app.AppOpsManager;
import android.app.ApplicationPackageManager;
import android.app.backup.IBackupManager;
@@ -870,7 +872,17 @@ final class InstallPackageHelper {
                                + " got: " + apexes.length);
            }
            try (PackageParser2 packageParser = mPm.mInjector.getScanningPackageParser()) {
                mApexManager.installPackage(apexes[0], packageParser, mPm.mApexPackageInfo);
                ApexInfo apexInfo = mApexManager.installPackage(
                        apexes[0], packageParser, mPm.mApexPackageInfo);
                if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
                    ParsedPackage parsedPackage = packageParser.parsePackage(
                            new File(apexInfo.modulePath), 0, /* useCaches= */ false);
                    scanSystemPackageLI(parsedPackage, 0, SCAN_AS_APEX, null);
                    mPm.mApexPackageInfo.notifyPackageInstalled(
                            apexInfo, parsedPackage.hideAsFinal());
                } else {
                    mPm.mApexPackageInfo.notifyPackageInstalled(apexInfo, packageParser);
                }
            }
        } catch (PackageManagerException e) {
            request.mInstallResult.setError("APEX installation failed", e);
@@ -3378,6 +3390,56 @@ final class InstallPackageHelper {
        }
    }

    public List<ApexManager.ScanResult> scanApexPackages(ApexInfo[] allPackages, int parseFlags,
            int scanFlags, PackageParser2 packageParser, ExecutorService executorService) {
        if (allPackages == null) {
            return Collections.EMPTY_LIST;
        }

        ParallelPackageParser parallelPackageParser =
                new ParallelPackageParser(packageParser, executorService);

        // Submit files for parsing in parallel
        ArrayMap<File, ApexInfo> parsingApexInfo = new ArrayMap<>();
        for (ApexInfo ai : allPackages) {
            File apexFile = new File(ai.modulePath);
            parallelPackageParser.submit(apexFile, parseFlags);
            parsingApexInfo.put(apexFile, ai);
        }

        // Process results one by one
        List<ApexManager.ScanResult> results = new ArrayList<>(parsingApexInfo.size());
        for (int i = 0; i < parsingApexInfo.size(); i++) {
            ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
            Throwable throwable = parseResult.throwable;
            ApexInfo ai = parsingApexInfo.get(parseResult.scanFile);
            int newScanFlags = scanFlags | SCAN_AS_APEX;

            if (throwable == null) {
                try {
                    scanSystemPackageLI(parseResult.parsedPackage, parseFlags, newScanFlags, null);
                    AndroidPackage pkg = parseResult.parsedPackage.hideAsFinal();
                    results.add(new ApexManager.ScanResult(ai, pkg, pkg.getPackageName()));
                } catch (PackageManagerException e) {
                    throw new IllegalStateException("Failed to scan: " + ai.modulePath, e);
                }
            } else if (throwable instanceof PackageManagerException) {
                final PackageManagerException e = (PackageManagerException) throwable;
                // Skip parsing non-coreApp apex file if system is in minimal boot state.
                if (e.error == PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED) {
                    Slog.w(TAG, "Scan apex failed, not a coreApp:" + ai.modulePath);
                    continue;
                }
                throw new IllegalStateException("Unable to parse: " + ai.modulePath, throwable);
            } else {
                throw new IllegalStateException("Unexpected exception occurred while parsing "
                        + ai.modulePath, throwable);
            }
        }

        return results;
    }

    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
    public void installPackagesFromDir(File scanDir, List<File> frameworkSplits, int parseFlags,
            int scanFlags, PackageParser2 packageParser,
@@ -4079,8 +4141,12 @@ final class InstallPackageHelper {
        // after OTA.
        final boolean isUserInstall = (scanFlags & SCAN_BOOTING) == 0;
        final boolean isFirstBootOrUpgrade = (scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0;
        // It is allowed to install a new APEX with the same name. But there shouldn't be
        // conflicting names between APK and APEX.
        final boolean installApex = (scanFlags & SCAN_AS_APEX) != 0;
        if ((isUserInstall || isFirstBootOrUpgrade)
                && mPm.mApexPackageInfo.isApexPackage(pkg.getPackageName())) {
                && mPm.mApexPackageInfo.isApexPackage(pkg.getPackageName())
                && !installApex) {
            throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
                    pkg.getPackageName()
                            + " is an APEX package and can't be installed as an APK.");
+1 −0
Original line number Diff line number Diff line
@@ -375,6 +375,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
    static final int SCAN_AS_ODM = 1 << 22;
    static final int SCAN_AS_APK_IN_APEX = 1 << 23;
    static final int SCAN_AS_FACTORY = 1 << 24;
    static final int SCAN_AS_APEX = 1 << 25;

    @IntDef(flag = true, prefix = { "SCAN_" }, value = {
            SCAN_NO_DEX,
Loading