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

Commit 425d3d5a authored by Song Chun Fan's avatar Song Chun Fan
Browse files

[6/N] allow adb installs to bypass verifier

By default, adb installs will bypass the verifier, unless
"--force-verification" is passed in the command.

FLAG: android.content.pm.verification_service

BUG: 360129657
Test: atest CtsPackageManagerTestCases:VerifierServiceTest

Change-Id: I314f968e286a17dbd573359320894dc2bdc8552c
parent f27be658
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -2934,6 +2934,8 @@ public class PackageInstaller {
        public int unarchiveId = -1;
        /** {@hide} */
        public @Nullable String dexoptCompilerFilter = null;
        /** {@hide} */
        public boolean forceVerification;

        private final ArrayMap<String, Integer> mPermissionStates;

@@ -2988,6 +2990,7 @@ public class PackageInstaller {
            developmentInstallFlags = source.readInt();
            unarchiveId = source.readInt();
            dexoptCompilerFilter = source.readString();
            forceVerification = source.readBoolean();
        }

        /** {@hide} */
@@ -3024,6 +3027,7 @@ public class PackageInstaller {
            ret.developmentInstallFlags = developmentInstallFlags;
            ret.unarchiveId = unarchiveId;
            ret.dexoptCompilerFilter = dexoptCompilerFilter;
            ret.forceVerification = forceVerification;
            return ret;
        }

@@ -3732,6 +3736,14 @@ public class PackageInstaller {
            return grantedPermissions.toArray(ArrayUtils.emptyArray(String.class));
        }

        /**
         * Used by adb installations to force enable the verification for this install.
         * {@hide}
         */
        public void setForceVerification() {
            this.forceVerification = true;
        }

        /** {@hide} */
        public void dump(IndentingPrintWriter pw) {
            pw.printPair("mode", mode);
@@ -3767,6 +3779,7 @@ public class PackageInstaller {
            pw.printHexPair("developmentInstallFlags", developmentInstallFlags);
            pw.printPair("unarchiveId", unarchiveId);
            pw.printPair("dexoptCompilerFilter", dexoptCompilerFilter);
            pw.printPair("forceVerification", forceVerification);
            pw.println();
        }

@@ -3813,6 +3826,7 @@ public class PackageInstaller {
            dest.writeInt(developmentInstallFlags);
            dest.writeInt(unarchiveId);
            dest.writeString(dexoptCompilerFilter);
            dest.writeBoolean(forceVerification);
        }

        public static final Parcelable.Creator<SessionParams>
+49 −29
Original line number Diff line number Diff line
@@ -234,7 +234,6 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;
import java.util.function.Supplier;

public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    private static final String TAG = "PackageInstallerSession";
@@ -1279,9 +1278,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
            }
        }

        if (Flags.verificationService()) {
        if (shouldUseVerificationService()) {
            // Start binding to the verification service, if not bound already.
            mVerifierController.bindToVerifierServiceIfNeeded(() -> pm.snapshotComputer(), userId);
            mVerifierController.bindToVerifierServiceIfNeeded(mPm::snapshotComputer, userId);
            if (!TextUtils.isEmpty(params.appPackageName)) {
                mVerifierController.notifyPackageNameAvailable(params.appPackageName);
            }
@@ -2875,9 +2874,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
            setSessionFailed(e.error, errorMsg);
            onSessionVerificationFailure(e.error, errorMsg, /* extras= */ null);
        }
        if (Flags.verificationService()) {
            final Supplier<Computer> snapshotSupplier = mPm::snapshotComputer;
            if (mVerifierController.isVerifierInstalled(snapshotSupplier, userId)) {
        if (shouldUseVerificationService()) {
            final SigningInfo signingInfo;
            final List<SharedLibraryInfo> declaredLibraries;
            synchronized (mLock) {
@@ -2887,7 +2884,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
            }
            // Send the request to the verifier and wait for its response before the rest of
            // the installation can proceed.
                if (!mVerifierController.startVerificationSession(snapshotSupplier, userId,
            if (!mVerifierController.startVerificationSession(mPm::snapshotComputer, userId,
                    sessionId, getPackageName(), Uri.fromFile(stageDir), signingInfo,
                    declaredLibraries, mVerificationPolicy.get(), /* extensionParams= */ null,
                    new VerifierCallback(), /* retry= */ false)) {
@@ -2897,13 +2894,36 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
                        /* extras= */ null);
            }
        } else {
                // Verifier is not installed. Let the installation pass for now.
            // No need to check with verifier. Proceed with the rest of the verification.
            resumeVerify();
        }
        } else {
            // New verification feature is not enabled. Proceed to the rest of the verification.
            resumeVerify();
    }

    private boolean shouldUseVerificationService() {
        if (!Flags.verificationService()) {
            // Feature is not enabled.
            return false;
        }
        if ((params.installFlags & PackageManager.INSTALL_FROM_ADB) != 0) {
            // adb installs are exempted from verification unless explicitly requested
            if (!params.forceVerification) {
                return false;
            }
        }
        final String verifierPackageName = mVerifierController.getVerifierPackageName(
                mPm::snapshotComputer, userId);
        if (verifierPackageName == null) {
            // Feature is enabled but no verifier installed.
            return false;
        }
        synchronized (mLock) {
            if (verifierPackageName.equals(mPackageName)) {
                // The verifier itself is being updated. Skip.
                Slog.w(TAG, "Skipping verification service because the verifier is being updated");
                return false;
            }
        }
        return true;
    }

    private void resumeVerify() {
@@ -5597,7 +5617,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
            }
        } catch (InstallerException ignored) {
        }
        if (Flags.verificationService()
        if (shouldUseVerificationService()
                && !TextUtils.isEmpty(params.appPackageName)
                && !isCommitted()) {
            // Only notify for the cancellation if the verification request has not
+4 −0
Original line number Diff line number Diff line
@@ -3599,6 +3599,9 @@ class PackageManagerShellCommand extends ShellCommand {
                            .setCompilerFilter(sessionParams.dexoptCompilerFilter)
                            .build();
                    break;
                case "--force-verification":
                    sessionParams.setForceVerification();
                    break;
                default:
                    throw new IllegalArgumentException("Unknown option " + opt);
            }
@@ -4805,6 +4808,7 @@ class PackageManagerShellCommand extends ShellCommand {
        pw.println("          https://source.android.com/docs/core/runtime/configure"
                + "#compiler_filters");
        pw.println("          or 'skip'");
        pw.println("      --force-verification: if set, enable the verification for this install");
        pw.println("");
        pw.println("  install-existing [--user USER_ID|all|current]");
        pw.println("       [--instant] [--full] [--wait] [--restrict-permissions] PACKAGE");
+1 −11
Original line number Diff line number Diff line
@@ -30,9 +30,6 @@ public final class VerificationStatusTracker {
    private final @CurrentTimeMillisLong long mMaxTimeoutTime;
    @NonNull
    private final VerifierController.Injector mInjector;
    // Record the package name associated with the verification result
    @NonNull
    private final String mPackageName;

    /**
     * By default, the timeout time is the default timeout duration plus the current time (when
@@ -41,10 +38,8 @@ public final class VerificationStatusTracker {
     * can be extended via {@link #extendTimeRemaining} to the maximum allowed.
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
    public VerificationStatusTracker(@NonNull String packageName,
            long defaultTimeoutMillis, long maxExtendedTimeoutMillis,
    public VerificationStatusTracker(long defaultTimeoutMillis, long maxExtendedTimeoutMillis,
            @NonNull VerifierController.Injector injector) {
        mPackageName = packageName;
        mStartTime = injector.getCurrentTimeMillis();
        mTimeoutTime = mStartTime + defaultTimeoutMillis;
        mMaxTimeoutTime = mStartTime + maxExtendedTimeoutMillis;
@@ -93,9 +88,4 @@ public final class VerificationStatusTracker {
    public boolean isTimeout() {
        return mInjector.getCurrentTimeMillis() >= mTimeoutTime;
    }

    @NonNull
    public String getPackageName() {
        return mPackageName;
    }
}
+14 −8
Original line number Diff line number Diff line
@@ -139,15 +139,16 @@ public class VerifierController {
    }

    /**
     * Used by the installation session to check if a verifier is installed.
     * Used by the installation session to get the package name of the installed verifier.
     */
    public boolean isVerifierInstalled(Supplier<Computer> snapshotSupplier, int userId) {
    @Nullable
    public String getVerifierPackageName(Supplier<Computer> snapshotSupplier, int userId) {
        if (isVerifierConnected()) {
            // Verifier is connected or is being connected, so it must be installed.
            return true;
            return mRemoteServiceComponentName.getPackageName();
        }
        // Verifier has been disconnected, or it hasn't been connected. Check if it's installed.
        return mInjector.isVerifierInstalled(snapshotSupplier.get(), userId);
        return mInjector.getVerifierPackageName(snapshotSupplier.get(), userId);
    }

    /**
@@ -331,7 +332,7 @@ public class VerifierController {
        final long defaultTimeoutMillis = mInjector.getVerificationRequestTimeoutMillis();
        final long maxExtendedTimeoutMillis = mInjector.getMaxVerificationExtendedTimeoutMillis();
        final VerificationStatusTracker tracker = new VerificationStatusTracker(
                packageName, defaultTimeoutMillis, maxExtendedTimeoutMillis, mInjector);
                defaultTimeoutMillis, maxExtendedTimeoutMillis, mInjector);
        synchronized (mVerificationStatus) {
            mVerificationStatus.put(verificationId, tracker);
        }
@@ -542,10 +543,15 @@ public class VerifierController {
        }

        /**
         * Check if a verifier is installed on this device.
         * Return the package name of the verifier installed on this device.
         */
        public boolean isVerifierInstalled(Computer snapshot, int userId) {
            return resolveVerifierComponentName(snapshot, userId) != null;
        @Nullable
        public String getVerifierPackageName(Computer snapshot, int userId) {
            final ComponentName componentName = resolveVerifierComponentName(snapshot, userId);
            if (componentName == null) {
                return null;
            }
            return componentName.getPackageName();
        }

        /**
Loading