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

Commit 8dda8313 authored by JW Wang's avatar JW Wang
Browse files

Migrate APEX package info from ApexPackageInfo to PMS

APEX is scanned and registered with the system for queries. Now PMS
is the only source of truth for all package info including both APEX
and APK.

* When ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX is true, APEX package
  info is stored in PMS. The results are filtered out if MATCH_APEX is
  not specified to preserve the original behavior.
* When ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX is false, APEX package
  info is stored in ApexPackageInfo.
* Don't generate an app id for APEX which doesn't need it anyway.
* Fix UserHandle#getUid which didn't translate invalid appIds
  correctly.

Bug: 225756739
Test: atest com.android.server.pm.ApexManagerTest \
            GtsStagedInstallHostTestCases \
            CtsStagedInstallHostTestCases \
            StagedInstallInternalTest \
            android.appsecurity.cts.InstantAppUserTest
Change-Id: I0003ea379d02a2ad3a37bcc57928a940ee83a86a
parent 6dc8a089
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -368,7 +368,7 @@ public final class UserHandle implements Parcelable {
    @UnsupportedAppUsage
    @TestApi
    public static int getUid(@UserIdInt int userId, @AppIdInt int appId) {
        if (MU_ENABLED) {
        if (MU_ENABLED && appId >= 0) {
            return userId * PER_USER_RANGE + (appId % PER_USER_RANGE);
        } else {
            return appId;
+4 −5
Original line number Diff line number Diff line
@@ -27,7 +27,6 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.util.ArrayMap;
import android.util.PrintWriterPrinter;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
@@ -271,11 +270,11 @@ class ApexPackageInfo {
            }
        }
        ipw.println("Active APEX packages:");
        dumpFromPackagesCache(getActivePackages(), packageName, ipw);
        dumpPackages(getActivePackages(), packageName, ipw);
        ipw.println("Inactive APEX packages:");
        dumpFromPackagesCache(getInactivePackages(), packageName, ipw);
        dumpPackages(getInactivePackages(), packageName, ipw);
        ipw.println("Factory APEX packages:");
        dumpFromPackagesCache(getFactoryPackages(), packageName, ipw);
        dumpPackages(getFactoryPackages(), packageName, ipw);
    }

    @GuardedBy("mLock")
@@ -370,7 +369,7 @@ class ApexPackageInfo {
     *                    only information about that specific package will be dumped.
     * @param ipw the {@link IndentingPrintWriter} object to send information to.
     */
    private static void dumpFromPackagesCache(List<PackageInfo> packagesCache,
    static void dumpPackages(List<PackageInfo> packagesCache,
            @Nullable String packageName, IndentingPrintWriter ipw) {
        ipw.println();
        ipw.increaseIndent();
+123 −26
Original line number Diff line number Diff line
@@ -984,9 +984,15 @@ public class ComputerEngine implements Computer {
                    TAG, "getApplicationInfo " + packageName
                            + ": " + p);
        }
        final boolean matchApex = (flags & MATCH_APEX) != 0;
        if (p != null) {
            PackageStateInternal ps = mSettings.getPackage(packageName);
            if (ps == null) return null;
            if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
                if (!matchApex && p.isApex()) {
                    return null;
                }
            }
            if (filterSharedLibPackage(ps, filterCallingUid, userId, flags)) {
                return null;
            }
@@ -1001,7 +1007,8 @@ public class ComputerEngine implements Computer {
            }
            return ai;
        }
        if ((flags & PackageManager.MATCH_APEX) != 0) {
        if (!ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
            if (matchApex) {
                // For APKs, PackageInfo.applicationInfo is not exactly the same as ApplicationInfo
                // returned from getApplicationInfo, but for APEX packages difference shouldn't be
                // very big.
@@ -1016,6 +1023,7 @@ public class ComputerEngine implements Computer {
                }
                return pi.applicationInfo;
            }
        }
        if ("android".equals(packageName) || "system".equals(packageName)) {
            return androidApplication();
        }
@@ -1704,14 +1712,22 @@ public class ComputerEngine implements Computer {
        packageName = resolveInternalPackageName(packageName, versionCode);

        final boolean matchFactoryOnly = (flags & MATCH_FACTORY_ONLY) != 0;
        final boolean matchApex = (flags & MATCH_APEX) != 0;
        if (matchFactoryOnly) {
            // Instant app filtering for APEX modules is ignored
            if ((flags & MATCH_APEX) != 0) {
            if (!ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
                if (matchApex) {
                    return mApexPackageInfo.getPackageInfo(packageName,
                            ApexManager.MATCH_FACTORY_PACKAGE);
                }
            }
            final PackageStateInternal ps = mSettings.getDisabledSystemPkg(packageName);
            if (ps != null) {
                if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
                    if (!matchApex && ps.getPkg() != null && ps.getPkg().isApex()) {
                        return null;
                    }
                }
                if (filterSharedLibPackage(ps, filterCallingUid, userId, flags)) {
                    return null;
                }
@@ -1731,6 +1747,11 @@ public class ComputerEngine implements Computer {
        }
        if (p != null) {
            final PackageStateInternal ps = getPackageStateInternal(p.getPackageName());
            if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
                if (!matchApex && p.isApex()) {
                    return null;
                }
            }
            if (filterSharedLibPackage(ps, filterCallingUid, userId, flags)) {
                return null;
            }
@@ -1751,8 +1772,11 @@ public class ComputerEngine implements Computer {
            }
            return generatePackageInfo(ps, flags, userId);
        }
        if ((flags & MATCH_APEX) != 0) {
            return mApexPackageInfo.getPackageInfo(packageName, ApexManager.MATCH_ACTIVE_PACKAGE);
        if (!ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
            if (matchApex) {
                return mApexPackageInfo.getPackageInfo(packageName,
                        ApexManager.MATCH_ACTIVE_PACKAGE);
            }
        }
        return null;
    }
@@ -1809,6 +1833,11 @@ public class ComputerEngine implements Computer {
                        ps = psDisabled;
                    }
                }
                if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
                    if (!listApex && ps.getPkg() != null && ps.getPkg().isApex()) {
                        continue;
                    }
                }
                if (filterSharedLibPackage(ps, callingUid, userId, flags)) {
                    continue;
                }
@@ -1834,6 +1863,11 @@ public class ComputerEngine implements Computer {
                        ps = psDisabled;
                    }
                }
                if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
                    if (!listApex && p.isApex()) {
                        continue;
                    }
                }
                if (filterSharedLibPackage(ps, callingUid, userId, flags)) {
                    continue;
                }
@@ -1846,6 +1880,7 @@ public class ComputerEngine implements Computer {
                }
            }
        }
        if (!ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
            if (listApex) {
                if (listFactory) {
                    list.addAll(mApexPackageInfo.getFactoryPackages());
@@ -1853,6 +1888,7 @@ public class ComputerEngine implements Computer {
                    list.addAll(mApexPackageInfo.getActivePackages());
                }
            }
        }
        return new ParceledListSlice<>(list);
    }

@@ -3338,13 +3374,58 @@ public class ComputerEngine implements Computer {
            case DumpState.DUMP_APEX: {
                if (packageName == null || isApexPackage(packageName)) {
                    mApexManager.dump(pw);
                    mApexPackageInfo.dump(pw, packageName);
                    dumpApex(pw, packageName);
                }
                break;
            }
        } // switch
    }

    private void generateApexPackageInfo(List<PackageInfo> activePackages,
            List<PackageInfo> inactivePackages, List<PackageInfo> factoryPackages) {
        for (AndroidPackage p : mPackages.values()) {
            final String packageName = p.getPackageName();
            PackageStateInternal ps = mSettings.getPackage(packageName);
            if (!p.isApex() || ps == null) {
                continue;
            }
            PackageInfo pi = generatePackageInfo(ps, 0, 0);
            if (pi == null) {
                continue;
            }
            pi.isActiveApex = true;
            activePackages.add(pi);
            if (!ps.isUpdatedSystemApp()) {
                factoryPackages.add(pi);
            } else {
                PackageStateInternal psDisabled = mSettings.getDisabledSystemPkg(packageName);
                pi = generatePackageInfo(psDisabled, 0, 0);
                if (pi != null) {
                    factoryPackages.add(pi);
                    inactivePackages.add(pi);
                }
            }
        }
    }

    private void dumpApex(PrintWriter pw, String packageName) {
        if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
            final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ", 120);
            List<PackageInfo> activePackages = new ArrayList<>();
            List<PackageInfo> inactivePackages = new ArrayList<>();
            List<PackageInfo> factoryPackages = new ArrayList<>();
            generateApexPackageInfo(activePackages, inactivePackages, factoryPackages);
            ipw.println("Active APEX packages:");
            ApexPackageInfo.dumpPackages(activePackages, packageName, ipw);
            ipw.println("Inactive APEX packages:");
            ApexPackageInfo.dumpPackages(inactivePackages, packageName, ipw);
            ipw.println("Factory APEX packages:");
            ApexPackageInfo.dumpPackages(factoryPackages, packageName, ipw);
        } else {
            mApexPackageInfo.dump(pw, packageName);
        }
    }

    // The body of findPreferredActivity.
    protected PackageManagerService.FindPreferredActivityBodyResult findPreferredActivityBody(
            Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
@@ -3721,7 +3802,12 @@ public class ComputerEngine implements Computer {

    @Override
    public boolean isApexPackage(String packageName) {
        if (!ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
            return mApexPackageInfo.isApexPackage(packageName);
        } else {
            final AndroidPackage pkg = mPackages.get(packageName);
            return pkg != null && pkg.isApex();
        }
    }

    @Override
@@ -4707,6 +4793,7 @@ public class ComputerEngine implements Computer {
        if (!mUserManager.exists(userId)) return Collections.emptyList();
        flags = updateFlagsForApplication(flags, userId);
        final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
        final boolean listApex = (flags & MATCH_APEX) != 0;

        enforceCrossUserPermission(
                callingUid,
@@ -4727,6 +4814,11 @@ public class ComputerEngine implements Computer {
                    effectiveFlags |= PackageManager.MATCH_ANY_USER;
                }
                if (ps.getPkg() != null) {
                    if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
                        if (!listApex && ps.getPkg().isApex()) {
                            continue;
                        }
                    }
                    if (filterSharedLibPackage(ps, callingUid, userId, flags)) {
                        continue;
                    }
@@ -4755,6 +4847,11 @@ public class ComputerEngine implements Computer {
                if (pkg == null) {
                    continue;
                }
                if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
                    if (!listApex && pkg.isApex()) {
                        continue;
                    }
                }
                if (filterSharedLibPackage(packageState, Binder.getCallingUid(), userId, flags)) {
                    continue;
                }
@@ -5105,7 +5202,7 @@ public class ComputerEngine implements Computer {
        final PackageStateInternal ps = mSettings.getPackage(packageName);

        // Installer info for Apex is not stored in PackageManager
        if (ps == null && mApexPackageInfo.isApexPackage(packageName)) {
        if (isApexPackage(packageName)) {
            return InstallSource.EMPTY;
        }

+0 −1
Original line number Diff line number Diff line
@@ -194,7 +194,6 @@ final class InitAppsHelper {
                apexScanResults = mInstallPackageHelper.scanApexPackages(
                        mApexManager.getAllApexInfos(), mSystemParseFlags, mSystemScanFlags,
                        packageParser, mExecutorService);
                mApexPackageInfo.notifyScanResult(apexScanResults);
            } else {
                apexScanResults = mApexPackageInfo.scanApexPackages(
                        mApexManager.getAllApexInfos(), packageParser, mExecutorService);
+97 −26
Original line number Diff line number Diff line
@@ -826,19 +826,24 @@ final class InstallPackageHelper {
            }
            return;
        }

        processApkInstallRequests(success, installRequests);
    }

    private void processApkInstallRequests(boolean success, List<InstallRequest> installRequests) {
        if (success) {
            for (InstallRequest request : apkInstallRequests) {
            for (InstallRequest request : installRequests) {
                request.mArgs.doPreInstall(request.mInstallResult.mReturnCode);
            }
            synchronized (mPm.mInstallLock) {
                installPackagesTracedLI(apkInstallRequests);
                installPackagesTracedLI(installRequests);
            }
            for (InstallRequest request : apkInstallRequests) {
            for (InstallRequest request : installRequests) {
                request.mArgs.doPostInstall(
                        request.mInstallResult.mReturnCode, request.mInstallResult.mUid);
            }
        }
        for (InstallRequest request : apkInstallRequests) {
        for (InstallRequest request : installRequests) {
            restoreAndPostInstall(request.mArgs.mUser.getIdentifier(),
                    request.mInstallResult,
                    new PostInstallData(request.mArgs,
@@ -880,11 +885,15 @@ final class InstallPackageHelper {
            try (PackageParser2 packageParser = mPm.mInjector.getScanningPackageParser()) {
                ApexInfo apexInfo = mApexManager.installPackage(apexes[0]);
                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());
                    // APEX has been handled successfully by apexd. Let's continue the install flow
                    // so it will be scanned and registered with the system.
                    // TODO(b/225756739): Improve atomicity of rebootless APEX install.
                    // The newly installed APEX will not be reverted even if
                    // processApkInstallRequests() fails. Need a way to keep info stored in apexd
                    // and PMS in sync in the face of install failures.
                    request.mInstallResult.mApexInfo = apexInfo;
                    mPm.mHandler.post(() -> processApkInstallRequests(true, requests));
                    return;
                } else {
                    mPm.mApexPackageInfo.notifyPackageInstalled(apexInfo, packageParser);
                }
@@ -985,7 +994,12 @@ final class InstallPackageHelper {
                                        + PackageManager.PROPERTY_NO_APP_DATA_STORAGE);
                        return;
                    }
                    final boolean isApex = (result.mRequest.mScanFlags & SCAN_AS_APEX) != 0;
                    if (!isApex) {
                        createdAppId.put(packageName, optimisticallyRegisterAppId(result));
                    } else {
                        result.mPkgSetting.setAppId(Process.INVALID_UID);
                    }
                    versionInfos.put(result.mPkgSetting.getPkg().getPackageName(),
                            mPm.getSettingsVersionForPackage(result.mPkgSetting.getPkg()));
                } catch (PackageManagerException e) {
@@ -1088,12 +1102,12 @@ final class InstallPackageHelper {
    private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res)
            throws PrepareFailure {
        final int installFlags = args.mInstallFlags;
        final File tmpPackageFile = new File(args.getCodePath());
        final boolean onExternal = args.mVolumeUuid != null;
        final boolean instantApp = ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0);
        final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0);
        final boolean virtualPreload =
                ((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
        final boolean isApex = ((installFlags & PackageManager.INSTALL_APEX) != 0);
        final boolean isRollback = args.mInstallReason == PackageManager.INSTALL_REASON_ROLLBACK;
        @PackageManagerService.ScanFlags int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
        if (args.mMoveInfo != null) {
@@ -1112,7 +1126,12 @@ final class InstallPackageHelper {
        if (virtualPreload) {
            scanFlags |= SCAN_AS_VIRTUAL_PRELOAD;
        }
        if (isApex) {
            scanFlags |= SCAN_AS_APEX;
        }

        final File tmpPackageFile = new File(
                isApex ? res.mApexInfo.modulePath : args.getCodePath());
        if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);

        // Validity check
@@ -1518,6 +1537,7 @@ final class InstallPackageHelper {
            }
        }

        if (!isApex) {
            if (!args.doRename(res.mReturnCode, parsedPackage)) {
                throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
            }
@@ -1529,6 +1549,11 @@ final class InstallPackageHelper {
                throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
                        "Failed to set up verity: " + e);
            }
        } else {
            // Use the path returned by apexd
            parsedPackage.setPath(res.mApexInfo.modulePath);
            parsedPackage.setBaseApkPath(res.mApexInfo.modulePath);
        }

        final PackageFreezer freezer =
                freezePackageForInstall(pkgName, installFlags, "installPackageLI");
@@ -1934,6 +1959,8 @@ final class InstallPackageHelper {
                // Set the update and install times
                PackageStateInternal deletedPkgSetting = mPm.snapshotComputer()
                        .getPackageStateInternal(oldPackage.getPackageName());
                // TODO(b/225756739): For rebootless APEX, consider using lastUpdateMillis provided
                //  by apexd to be more accurate.
                reconciledPkg.mPkgSetting
                        .setFirstInstallTimeFromReplaced(deletedPkgSetting, request.mAllUsers)
                        .setLastUpdateTime(System.currentTimeMillis());
@@ -2236,6 +2263,8 @@ final class InstallPackageHelper {
        for (ReconciledPackage reconciledPkg : commitRequest.mReconciledPackages.values()) {
            final boolean instantApp = ((reconciledPkg.mScanResult.mRequest.mScanFlags
                    & SCAN_AS_INSTANT_APP) != 0);
            final boolean isApex = ((reconciledPkg.mScanResult.mRequest.mScanFlags
                    & SCAN_AS_APEX) != 0);
            final AndroidPackage pkg = reconciledPkg.mPkgSetting.getPkg();
            final String packageName = pkg.getPackageName();
            final String codePath = pkg.getPath();
@@ -2323,7 +2352,8 @@ final class InstallPackageHelper {
                            android.provider.Settings.Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
                            && !pkg.isDebuggable()
                            && (!onIncremental)
                            && dexoptOptions.isCompilationEnabled();
                            && dexoptOptions.isCompilationEnabled()
                            && !isApex;

            if (performDexopt) {
                // Compile the layout resources.
@@ -3292,6 +3322,10 @@ final class InstallPackageHelper {
            final PackageSetting disabledPs =
                    mPm.mSettings.getDisabledSystemPkgLPr(packageName);
            if (scannedPkg != null) {
                if (scannedPkg.isApex()) {
                    // APEX on /data has been scanned. No need to expect better.
                    continue;
                }
                /*
                 * If the system app is both scanned and in the
                 * disabled packages list, then it must have been
@@ -3391,6 +3425,18 @@ final class InstallPackageHelper {
        }
    }

    /**
     * Scans APEX packages and registers them with the system.
     *
     * apexd has its own policy to decide which APEX to activate and which not. The policy might
     * conflicts that of PMS. The APEX package info stored in PMS is a mirror of that managed by
     * apexd. To keep things simple and keep activation status in sync for both apexd and PMS, we
     * don't persist APEX in settings and always scan APEX from scratch during boot. However, some
     * data like lastUpdateTime will be lost if PackageSetting is not persisted for APEX.
     *
     * TODO(b/225756739): Read lastUpdateTime from ApexInfoList to populate PackageSetting correctly
     */
    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
    public List<ApexManager.ScanResult> scanApexPackages(ApexInfo[] allPackages, int parseFlags,
            int scanFlags, PackageParser2 packageParser, ExecutorService executorService) {
        if (allPackages == null) {
@@ -3408,18 +3454,39 @@ final class InstallPackageHelper {
            parsingApexInfo.put(apexFile, ai);
        }

        // Process results one by one
        List<ApexManager.ScanResult> results = new ArrayList<>(parsingApexInfo.size());
        List<ParallelPackageParser.ParseResult> parseResults =
                new ArrayList<>(parsingApexInfo.size());
        for (int i = 0; i < parsingApexInfo.size(); i++) {
            ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
            parseResults.add(parseResult);
        }
        // Sort the list to ensure we always process factory packages first
        Collections.sort(parseResults, (a, b) -> {
            ApexInfo ai = parsingApexInfo.get(a.scanFile);
            return ai.isFactory ? -1 : 1;
        });


        // Process results one by one
        List<ApexManager.ScanResult> results = new ArrayList<>(parsingApexInfo.size());
        for (int i = 0; i < parseResults.size(); i++) {
            ParallelPackageParser.ParseResult parseResult = parseResults.get(i);
            Throwable throwable = parseResult.throwable;
            ApexInfo ai = parsingApexInfo.get(parseResult.scanFile);
            int newParseFlags = parseFlags;
            int newScanFlags = scanFlags | SCAN_AS_APEX;
            if (!ai.isFactory) {
                newParseFlags &= ~ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
                newScanFlags |= SCAN_NEW_INSTALL;
            }

            if (throwable == null) {
                try {
                    scanSystemPackageLI(parseResult.parsedPackage, parseFlags, newScanFlags, null);
                    AndroidPackage pkg = parseResult.parsedPackage.hideAsFinal();
                    AndroidPackage pkg = addForInitLI(
                            parseResult.parsedPackage, newParseFlags, newScanFlags, null);
                    if (ai.isFactory && !ai.isActive) {
                        disableSystemPackageLPw(pkg);
                    }
                    results.add(new ApexManager.ScanResult(ai, pkg, pkg.getPackageName()));
                } catch (PackageManagerException e) {
                    throw new IllegalStateException("Failed to scan: " + ai.modulePath, e);
@@ -3638,7 +3705,11 @@ final class InstallPackageHelper {
                            ReconcilePackageUtils.reconcilePackages(reconcileRequest,
                                    mSharedLibraries, mPm.mSettings.getKeySetManagerService(),
                                    mPm.mSettings);
                    if ((scanFlags & SCAN_AS_APEX) == 0) {
                        appIdCreated = optimisticallyRegisterAppId(scanResult);
                    } else {
                        scanResult.mPkgSetting.setAppId(Process.INVALID_UID);
                    }
                    commitReconciledScanResultLocked(reconcileResult.get(pkgName),
                            mPm.mUserManager.getUserIds());
                } catch (PackageManagerException e) {
Loading