| /* |
| * Copyright (C) 2021 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.server.pm; |
| |
| import static android.content.Intent.EXTRA_LONG_VERSION_CODE; |
| import static android.content.Intent.EXTRA_PACKAGE_NAME; |
| import static android.content.Intent.EXTRA_VERSION_CODE; |
| import static android.content.pm.PackageInstaller.SessionParams.MODE_INHERIT_EXISTING; |
| import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID; |
| import static android.content.pm.PackageManager.INSTALL_SUCCEEDED; |
| import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING; |
| import static android.content.pm.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4; |
| import static android.os.PowerWhitelistManager.REASON_PACKAGE_VERIFIER; |
| import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED; |
| import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; |
| |
| import static com.android.server.pm.PackageManagerService.CHECK_PENDING_INTEGRITY_VERIFICATION; |
| import static com.android.server.pm.PackageManagerService.CHECK_PENDING_VERIFICATION; |
| import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL; |
| import static com.android.server.pm.PackageManagerService.DEBUG_VERIFY; |
| import static com.android.server.pm.PackageManagerService.DEFAULT_VERIFICATION_RESPONSE; |
| import static com.android.server.pm.PackageManagerService.ENABLE_ROLLBACK_TIMEOUT; |
| import static com.android.server.pm.PackageManagerService.PACKAGE_MIME_TYPE; |
| import static com.android.server.pm.PackageManagerService.TAG; |
| |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.app.AppOpsManager; |
| import android.app.BroadcastOptions; |
| import android.content.BroadcastReceiver; |
| import android.content.ComponentName; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.pm.ActivityInfo; |
| import android.content.pm.DataLoaderType; |
| import android.content.pm.IPackageInstallObserver2; |
| import android.content.pm.PackageInfoLite; |
| import android.content.pm.PackageInstaller; |
| import android.content.pm.PackageManager; |
| import android.content.pm.PackageManagerInternal; |
| import android.content.pm.ParceledListSlice; |
| import android.content.pm.ResolveInfo; |
| import android.content.pm.SigningDetails; |
| import android.content.pm.VerifierInfo; |
| import android.content.pm.parsing.PackageLite; |
| import android.net.Uri; |
| import android.os.Bundle; |
| import android.os.Message; |
| import android.os.Process; |
| import android.os.RemoteException; |
| import android.os.SystemProperties; |
| import android.os.Trace; |
| import android.os.UserHandle; |
| import android.os.UserManager; |
| import android.os.incremental.IncrementalManager; |
| import android.provider.DeviceConfig; |
| import android.provider.Settings; |
| import android.text.TextUtils; |
| import android.util.Pair; |
| import android.util.Slog; |
| |
| import com.android.server.DeviceIdleInternal; |
| import com.android.server.sdksandbox.SdkSandboxManagerLocal; |
| |
| import java.io.File; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| |
| final class VerifyingSession { |
| /** |
| * Whether verification is enabled by default. |
| */ |
| private static final boolean DEFAULT_VERIFY_ENABLE = true; |
| |
| /** |
| * Whether integrity verification is enabled by default. |
| */ |
| private static final boolean DEFAULT_INTEGRITY_VERIFY_ENABLE = true; |
| /** |
| * The default maximum time to wait for the integrity verification to return in |
| * milliseconds. |
| */ |
| private static final long DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT = 30 * 1000; |
| /** |
| * Timeout duration in milliseconds for enabling package rollback. If we fail to enable |
| * rollback within that period, the install will proceed without rollback enabled. |
| * |
| * <p>If flag value is negative, the default value will be assigned. |
| * |
| * Flag type: {@code long} |
| * Namespace: NAMESPACE_ROLLBACK |
| */ |
| private static final String PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS = "enable_rollback_timeout"; |
| /** |
| * The default duration to wait for rollback to be enabled in |
| * milliseconds. |
| */ |
| private static final long DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS = 10 * 1000; |
| |
| final OriginInfo mOriginInfo; |
| final IPackageInstallObserver2 mObserver; |
| private final int mInstallFlags; |
| @NonNull |
| private final InstallSource mInstallSource; |
| private final String mPackageAbiOverride; |
| private final VerificationInfo mVerificationInfo; |
| private final SigningDetails mSigningDetails; |
| @Nullable |
| MultiPackageVerifyingSession mParentVerifyingSession; |
| private final long mRequiredInstalledVersionCode; |
| private final int mDataLoaderType; |
| private final int mSessionId; |
| private final boolean mUserActionRequired; |
| private final int mUserActionRequiredType; |
| private boolean mWaitForVerificationToComplete; |
| private boolean mWaitForIntegrityVerificationToComplete; |
| private boolean mWaitForEnableRollbackToComplete; |
| private int mRet = PackageManager.INSTALL_SUCCEEDED; |
| private String mErrorMessage = null; |
| private final boolean mIsInherit; |
| private final boolean mIsStaged; |
| |
| private final PackageLite mPackageLite; |
| private final UserHandle mUser; |
| @NonNull |
| private final PackageManagerService mPm; |
| private final InstallPackageHelper mInstallPackageHelper; |
| |
| VerifyingSession(UserHandle user, File stagedDir, IPackageInstallObserver2 observer, |
| PackageInstaller.SessionParams sessionParams, InstallSource installSource, |
| int installerUid, SigningDetails signingDetails, int sessionId, PackageLite lite, |
| boolean userActionRequired, PackageManagerService pm) { |
| mPm = pm; |
| mUser = user; |
| mInstallPackageHelper = new InstallPackageHelper(mPm); |
| mOriginInfo = OriginInfo.fromStagedFile(stagedDir); |
| mObserver = observer; |
| mInstallFlags = sessionParams.installFlags; |
| mInstallSource = installSource; |
| mPackageAbiOverride = sessionParams.abiOverride; |
| mVerificationInfo = new VerificationInfo( |
| sessionParams.originatingUri, |
| sessionParams.referrerUri, |
| sessionParams.originatingUid, |
| installerUid |
| ); |
| mSigningDetails = signingDetails; |
| mRequiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode; |
| mDataLoaderType = (sessionParams.dataLoaderParams != null) |
| ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE; |
| mSessionId = sessionId; |
| mPackageLite = lite; |
| mUserActionRequired = userActionRequired; |
| mUserActionRequiredType = sessionParams.requireUserAction; |
| mIsInherit = sessionParams.mode == MODE_INHERIT_EXISTING; |
| mIsStaged = sessionParams.isStaged; |
| } |
| |
| @Override |
| public String toString() { |
| return "VerifyingSession{" + Integer.toHexString(System.identityHashCode(this)) |
| + " file=" + mOriginInfo.mFile + "}"; |
| } |
| |
| public void handleStartVerify() { |
| PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mPm.mContext, |
| mPackageLite, mOriginInfo.mResolvedPath, mInstallFlags, mPackageAbiOverride); |
| |
| Pair<Integer, String> ret = mInstallPackageHelper.verifyReplacingVersionCode( |
| pkgLite, mRequiredInstalledVersionCode, mInstallFlags); |
| setReturnCode(ret.first, ret.second); |
| if (mRet != INSTALL_SUCCEEDED) { |
| return; |
| } |
| |
| // Perform package verification and enable rollback (unless we are simply moving the |
| // package). |
| if (!mOriginInfo.mExisting) { |
| if (!isApex()) { |
| // TODO(b/182426975): treat APEX as APK when APK verification is concerned |
| sendApkVerificationRequest(pkgLite); |
| } |
| if ((mInstallFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) { |
| sendEnableRollbackRequest(); |
| } |
| } |
| } |
| |
| private void sendApkVerificationRequest(PackageInfoLite pkgLite) { |
| final int verificationId = mPm.mPendingVerificationToken++; |
| |
| PackageVerificationState verificationState = |
| new PackageVerificationState(this); |
| mPm.mPendingVerification.append(verificationId, verificationState); |
| |
| sendIntegrityVerificationRequest(verificationId, pkgLite, verificationState); |
| sendPackageVerificationRequest( |
| verificationId, pkgLite, verificationState); |
| |
| // If both verifications are skipped, we should remove the state. |
| if (verificationState.areAllVerificationsComplete()) { |
| mPm.mPendingVerification.remove(verificationId); |
| } |
| } |
| |
| void sendEnableRollbackRequest() { |
| final int enableRollbackToken = mPm.mPendingEnableRollbackToken++; |
| Trace.asyncTraceBegin( |
| TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken); |
| mPm.mPendingEnableRollback.append(enableRollbackToken, this); |
| |
| Intent enableRollbackIntent = new Intent(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK); |
| enableRollbackIntent.putExtra( |
| PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN, |
| enableRollbackToken); |
| enableRollbackIntent.putExtra( |
| PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID, |
| mSessionId); |
| enableRollbackIntent.setType(PACKAGE_MIME_TYPE); |
| enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION |
| | Intent.FLAG_RECEIVER_FOREGROUND); |
| |
| // Allow the broadcast to be sent before boot complete. |
| // This is needed when committing the apk part of a staged |
| // session in early boot. The rollback manager registers |
| // its receiver early enough during the boot process that |
| // it will not miss the broadcast. |
| enableRollbackIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); |
| |
| mPm.mContext.sendBroadcastAsUser(enableRollbackIntent, UserHandle.SYSTEM, |
| android.Manifest.permission.PACKAGE_ROLLBACK_AGENT); |
| |
| mWaitForEnableRollbackToComplete = true; |
| |
| // the duration to wait for rollback to be enabled, in millis |
| long rollbackTimeout = DeviceConfig.getLong( |
| DeviceConfig.NAMESPACE_ROLLBACK, |
| PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS, |
| DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS); |
| if (rollbackTimeout < 0) { |
| rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS; |
| } |
| final Message msg = mPm.mHandler.obtainMessage(ENABLE_ROLLBACK_TIMEOUT); |
| msg.arg1 = enableRollbackToken; |
| msg.arg2 = mSessionId; |
| mPm.mHandler.sendMessageDelayed(msg, rollbackTimeout); |
| } |
| |
| /** |
| * Send a request to check the integrity of the package. |
| */ |
| void sendIntegrityVerificationRequest( |
| int verificationId, |
| PackageInfoLite pkgLite, |
| PackageVerificationState verificationState) { |
| if (!isIntegrityVerificationEnabled()) { |
| // Consider the integrity check as passed. |
| verificationState.setIntegrityVerificationResult( |
| PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW); |
| return; |
| } |
| |
| final Intent integrityVerification = |
| new Intent(Intent.ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION); |
| |
| integrityVerification.setDataAndType(Uri.fromFile(new File(mOriginInfo.mResolvedPath)), |
| PACKAGE_MIME_TYPE); |
| |
| final int flags = Intent.FLAG_GRANT_READ_URI_PERMISSION |
| | Intent.FLAG_RECEIVER_REGISTERED_ONLY |
| | Intent.FLAG_RECEIVER_FOREGROUND; |
| integrityVerification.addFlags(flags); |
| |
| integrityVerification.putExtra(EXTRA_VERIFICATION_ID, verificationId); |
| integrityVerification.putExtra(EXTRA_PACKAGE_NAME, pkgLite.packageName); |
| integrityVerification.putExtra(EXTRA_VERSION_CODE, pkgLite.versionCode); |
| integrityVerification.putExtra(EXTRA_LONG_VERSION_CODE, pkgLite.getLongVersionCode()); |
| populateInstallerExtras(integrityVerification); |
| |
| // send to integrity component only. |
| integrityVerification.setPackage("android"); |
| |
| final BroadcastOptions options = BroadcastOptions.makeBasic(); |
| |
| mPm.mContext.sendOrderedBroadcastAsUser(integrityVerification, UserHandle.SYSTEM, |
| /* receiverPermission= */ null, |
| /* appOp= */ AppOpsManager.OP_NONE, |
| /* options= */ options.toBundle(), |
| new BroadcastReceiver() { |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| final Message msg = |
| mPm.mHandler.obtainMessage(CHECK_PENDING_INTEGRITY_VERIFICATION); |
| msg.arg1 = verificationId; |
| mPm.mHandler.sendMessageDelayed(msg, getIntegrityVerificationTimeout()); |
| } |
| }, /* scheduler= */ null, |
| /* initialCode= */ 0, |
| /* initialData= */ null, |
| /* initialExtras= */ null); |
| |
| Trace.asyncTraceBegin( |
| TRACE_TAG_PACKAGE_MANAGER, "integrity_verification", verificationId); |
| |
| // stop the copy until verification succeeds. |
| mWaitForIntegrityVerificationToComplete = true; |
| } |
| |
| |
| /** |
| * Get the integrity verification timeout. |
| * |
| * @return verification timeout in milliseconds |
| */ |
| private long getIntegrityVerificationTimeout() { |
| long timeout = Settings.Global.getLong(mPm.mContext.getContentResolver(), |
| Settings.Global.APP_INTEGRITY_VERIFICATION_TIMEOUT, |
| DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT); |
| // The setting can be used to increase the timeout but not decrease it, since that is |
| // equivalent to disabling the integrity component. |
| return Math.max(timeout, DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT); |
| } |
| |
| /** |
| * Check whether or not integrity verification has been enabled. |
| */ |
| private boolean isIntegrityVerificationEnabled() { |
| // We are not exposing this as a user-configurable setting because we don't want to provide |
| // an easy way to get around the integrity check. |
| return DEFAULT_INTEGRITY_VERIFY_ENABLE; |
| } |
| |
| /** |
| * Send a request to verifier(s) to verify the package if necessary. |
| */ |
| private void sendPackageVerificationRequest( |
| int verificationId, |
| PackageInfoLite pkgLite, |
| PackageVerificationState verificationState) { |
| |
| // Apps installed for "all" users use the current user to verify the app |
| UserHandle verifierUser = getUser(); |
| if (verifierUser == UserHandle.ALL) { |
| verifierUser = UserHandle.of(mPm.mUserManager.getCurrentUserId()); |
| } |
| final int verifierUserId = verifierUser.getIdentifier(); |
| |
| List<String> requiredVerifierPackages = new ArrayList<>( |
| Arrays.asList(mPm.mRequiredVerifierPackages)); |
| boolean requiredVerifierPackagesOverridden = false; |
| |
| // Allow verifier override for ADB installations which could already be unverified using |
| // PackageManager.INSTALL_DISABLE_VERIFICATION flag. |
| if ((mInstallFlags & PackageManager.INSTALL_FROM_ADB) != 0 |
| && (mInstallFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) == 0) { |
| String property = SystemProperties.get("debug.pm.adb_verifier_override_packages", ""); |
| if (!TextUtils.isEmpty(property)) { |
| String[] verifierPackages = property.split(";"); |
| List<String> adbVerifierOverridePackages = new ArrayList<>(); |
| for (String verifierPackage : verifierPackages) { |
| if (!TextUtils.isEmpty(verifierPackage) && packageExists(verifierPackage)) { |
| adbVerifierOverridePackages.add(verifierPackage); |
| } |
| } |
| // Check if the package installed. |
| if (adbVerifierOverridePackages.size() > 0) { |
| // Pretend we requested to disable verification from command line. |
| boolean requestedDisableVerification = true; |
| // If this returns false then the caller can already skip verification, so we |
| // are not adding a new way to disable verifications. |
| if (!isAdbVerificationEnabled(pkgLite, verifierUserId, |
| requestedDisableVerification)) { |
| requiredVerifierPackages = adbVerifierOverridePackages; |
| requiredVerifierPackagesOverridden = true; |
| } |
| } |
| } |
| } |
| |
| if (mOriginInfo.mExisting || !isVerificationEnabled(pkgLite, verifierUserId, |
| requiredVerifierPackages)) { |
| verificationState.passRequiredVerification(); |
| return; |
| } |
| |
| /* |
| * Determine if we have any installed package verifiers. If we |
| * do, then we'll defer to them to verify the packages. |
| */ |
| final Computer snapshot = mPm.snapshotComputer(); |
| |
| final int numRequiredVerifierPackages = requiredVerifierPackages.size(); |
| for (int i = numRequiredVerifierPackages - 1; i >= 0; i--) { |
| if (!snapshot.isApplicationEffectivelyEnabled(requiredVerifierPackages.get(i), |
| verifierUser)) { |
| Slog.w(TAG, |
| "Required verifier: " + requiredVerifierPackages.get(i) + " is disabled"); |
| requiredVerifierPackages.remove(i); |
| } |
| } |
| |
| for (String requiredVerifierPackage : requiredVerifierPackages) { |
| final int requiredUid = snapshot.getPackageUid(requiredVerifierPackage, |
| MATCH_DEBUG_TRIAGED_MISSING, verifierUserId); |
| verificationState.addRequiredVerifierUid(requiredUid); |
| } |
| |
| final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION); |
| verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); |
| verification.setDataAndType(Uri.fromFile(new File(mOriginInfo.mResolvedPath)), |
| PACKAGE_MIME_TYPE); |
| verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); |
| |
| // Query all live verifiers based on current user state |
| final ParceledListSlice<ResolveInfo> receivers = mPm.queryIntentReceivers(snapshot, |
| verification, PACKAGE_MIME_TYPE, 0, verifierUserId); |
| |
| if (DEBUG_VERIFY) { |
| Slog.d(TAG, "Found " + receivers.getList().size() + " verifiers for intent " |
| + verification.toString() + " with " + pkgLite.verifiers.length |
| + " optional verifiers"); |
| } |
| |
| verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId); |
| |
| verification.putExtra( |
| PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS, mInstallFlags); |
| |
| verification.putExtra( |
| PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME, pkgLite.packageName); |
| |
| verification.putExtra( |
| PackageManager.EXTRA_VERIFICATION_VERSION_CODE, pkgLite.versionCode); |
| |
| verification.putExtra( |
| PackageManager.EXTRA_VERIFICATION_LONG_VERSION_CODE, |
| pkgLite.getLongVersionCode()); |
| |
| final String baseCodePath = mPackageLite.getBaseApkPath(); |
| final String[] splitCodePaths = mPackageLite.getSplitApkPaths(); |
| |
| final String rootHashString; |
| if (IncrementalManager.isIncrementalPath(baseCodePath)) { |
| rootHashString = PackageManagerServiceUtils.buildVerificationRootHashString( |
| baseCodePath, splitCodePaths); |
| verification.putExtra(PackageManager.EXTRA_VERIFICATION_ROOT_HASH, rootHashString); |
| } else { |
| rootHashString = null; |
| } |
| |
| verification.putExtra(PackageInstaller.EXTRA_DATA_LOADER_TYPE, mDataLoaderType); |
| |
| verification.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId); |
| |
| verification.putExtra(PackageManager.EXTRA_USER_ACTION_REQUIRED, mUserActionRequired); |
| |
| populateInstallerExtras(verification); |
| |
| // Streaming installation timeout schema is enabled only for: |
| // 1. Incremental installs with v4, |
| // 2. If device/policy allow unverified app installs by default. |
| final boolean streaming = (mDataLoaderType == DataLoaderType.INCREMENTAL) |
| && (mSigningDetails.getSignatureSchemeVersion() == SIGNING_BLOCK_V4) |
| && (getDefaultVerificationResponse() == PackageManager.VERIFICATION_ALLOW); |
| |
| final long verificationTimeout = VerificationUtils.getVerificationTimeout(mPm.mContext, |
| streaming); |
| |
| List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite, |
| receivers.getList(), verificationState); |
| |
| // Add broadcastReceiver Component to verify Sdk before run in Sdk sandbox. |
| if (pkgLite.isSdkLibrary) { |
| if (sufficientVerifiers == null) { |
| sufficientVerifiers = new ArrayList<>(); |
| } |
| ComponentName sdkSandboxComponentName = new ComponentName("android", |
| SdkSandboxManagerLocal.VERIFIER_RECEIVER); |
| sufficientVerifiers.add(sdkSandboxComponentName); |
| |
| // Add uid of system_server the same uid for SdkSandboxManagerService |
| verificationState.addSufficientVerifier(Process.myUid()); |
| } |
| |
| DeviceIdleInternal idleController = |
| mPm.mInjector.getLocalService(DeviceIdleInternal.class); |
| final BroadcastOptions options = BroadcastOptions.makeBasic(); |
| options.setTemporaryAppAllowlist(verificationTimeout, |
| TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, |
| REASON_PACKAGE_VERIFIER, ""); |
| |
| /* |
| * If any sufficient verifiers were listed in the package |
| * manifest, attempt to ask them. |
| */ |
| if (sufficientVerifiers != null) { |
| final int n = sufficientVerifiers.size(); |
| if (n == 0) { |
| String errorMsg = "Additional verifiers required, but none installed."; |
| Slog.i(TAG, errorMsg); |
| setReturnCode(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, errorMsg); |
| } else { |
| for (int i = 0; i < n; i++) { |
| final ComponentName verifierComponent = sufficientVerifiers.get(i); |
| idleController.addPowerSaveTempWhitelistApp(Process.myUid(), |
| verifierComponent.getPackageName(), verificationTimeout, |
| verifierUserId, false, |
| REASON_PACKAGE_VERIFIER, "package verifier"); |
| |
| final Intent sufficientIntent = new Intent(verification); |
| sufficientIntent.setComponent(verifierComponent); |
| mPm.mContext.sendBroadcastAsUser(sufficientIntent, verifierUser, |
| /* receiverPermission= */ null, |
| options.toBundle()); |
| } |
| } |
| } |
| |
| if (requiredVerifierPackages.size() == 0) { |
| Slog.e(TAG, "No required verifiers"); |
| return; |
| } |
| |
| final int verificationCodeAtTimeout; |
| if (getDefaultVerificationResponse() == PackageManager.VERIFICATION_ALLOW) { |
| verificationCodeAtTimeout = PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT; |
| } else { |
| verificationCodeAtTimeout = PackageManager.VERIFICATION_REJECT; |
| } |
| |
| for (String requiredVerifierPackage : requiredVerifierPackages) { |
| final int requiredUid = snapshot.getPackageUid(requiredVerifierPackage, |
| MATCH_DEBUG_TRIAGED_MISSING, verifierUserId); |
| |
| final Intent requiredIntent; |
| final String receiverPermission; |
| if (!requiredVerifierPackagesOverridden || requiredVerifierPackages.size() == 1) { |
| // Prod code OR test code+single verifier. |
| requiredIntent = new Intent(verification); |
| if (!requiredVerifierPackagesOverridden) { |
| ComponentName requiredVerifierComponent = matchComponentForVerifier( |
| requiredVerifierPackage, receivers.getList()); |
| requiredIntent.setComponent(requiredVerifierComponent); |
| } else { |
| requiredIntent.setPackage(requiredVerifierPackage); |
| } |
| receiverPermission = android.Manifest.permission.PACKAGE_VERIFICATION_AGENT; |
| } else { |
| // Test code+multiple verifiers. |
| // Recreate the intent to contain test-only information. |
| requiredIntent = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION); |
| requiredIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); |
| requiredIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); |
| requiredIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); |
| requiredIntent.setDataAndType(Uri.fromFile(new File(mOriginInfo.mResolvedPath)), |
| PACKAGE_MIME_TYPE); |
| requiredIntent.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId); |
| requiredIntent.putExtra(PackageInstaller.EXTRA_DATA_LOADER_TYPE, mDataLoaderType); |
| if (rootHashString != null) { |
| requiredIntent.putExtra(PackageManager.EXTRA_VERIFICATION_ROOT_HASH, |
| rootHashString); |
| } |
| requiredIntent.setPackage(requiredVerifierPackage); |
| // Negative verification id. |
| requiredIntent.putExtra(PackageManager.EXTRA_VERIFICATION_ID, -verificationId); |
| // OK not to have permission. |
| receiverPermission = null; |
| } |
| |
| idleController.addPowerSaveTempWhitelistApp(Process.myUid(), requiredVerifierPackage, |
| verificationTimeout, verifierUserId, false, REASON_PACKAGE_VERIFIER, |
| "package verifier"); |
| |
| final PackageVerificationResponse response = new PackageVerificationResponse( |
| verificationCodeAtTimeout, requiredUid); |
| |
| if (streaming) { |
| // For streaming installations, count verification timeout from the broadcast. |
| startVerificationTimeoutCountdown(verificationId, streaming, response, |
| verificationTimeout); |
| } |
| |
| // Send the intent to the required verification agent, but only start the |
| // verification timeout after the target BroadcastReceivers have run. |
| mPm.mContext.sendOrderedBroadcastAsUser(requiredIntent, verifierUser, |
| receiverPermission, AppOpsManager.OP_NONE, options.toBundle(), |
| new BroadcastReceiver() { |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| if (!streaming) { |
| // For NON-streaming installations, count verification timeout from |
| // the broadcast was processed by all receivers. |
| startVerificationTimeoutCountdown(verificationId, streaming, |
| response, verificationTimeout); |
| } |
| } |
| }, null, 0, null, null); |
| } |
| |
| Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId); |
| |
| /* |
| * We don't want the copy to proceed until verification |
| * succeeds. |
| */ |
| mWaitForVerificationToComplete = true; |
| } |
| |
| private void startVerificationTimeoutCountdown(int verificationId, boolean streaming, |
| PackageVerificationResponse response, long verificationTimeout) { |
| final Message msg = mPm.mHandler.obtainMessage(CHECK_PENDING_VERIFICATION); |
| msg.arg1 = verificationId; |
| msg.arg2 = streaming ? 1 : 0; |
| msg.obj = response; |
| mPm.mHandler.sendMessageDelayed(msg, verificationTimeout); |
| } |
| |
| /** |
| * Get the default verification agent response code. |
| * |
| * @return default verification response code |
| */ |
| int getDefaultVerificationResponse() { |
| if (mPm.mUserManager.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS, |
| getUser().getIdentifier())) { |
| return PackageManager.VERIFICATION_REJECT; |
| } |
| return android.provider.Settings.Global.getInt(mPm.mContext.getContentResolver(), |
| android.provider.Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE, |
| DEFAULT_VERIFICATION_RESPONSE); |
| } |
| |
| private boolean packageExists(String packageName) { |
| Computer snapshot = mPm.snapshotComputer(); |
| return snapshot.getPackageStateInternal(packageName) != null; |
| } |
| |
| private boolean isAdbVerificationEnabled(PackageInfoLite pkgInfoLite, int userId, |
| boolean requestedDisableVerification) { |
| boolean verifierIncludeAdb = android.provider.Settings.Global.getInt( |
| mPm.mContext.getContentResolver(), |
| android.provider.Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, 1) != 0; |
| |
| if (mPm.isUserRestricted(userId, UserManager.ENSURE_VERIFY_APPS)) { |
| if (!verifierIncludeAdb) { |
| Slog.w(TAG, "Force verification of ADB install because of user restriction."); |
| } |
| return true; |
| } |
| |
| // Check if the verification disabled globally, first. |
| if (!verifierIncludeAdb) { |
| return false; |
| } |
| |
| // Check if the developer wants to skip verification for ADB installs. |
| if (requestedDisableVerification) { |
| if (!packageExists(pkgInfoLite.packageName)) { |
| // Always verify fresh install. |
| return true; |
| } |
| // Only skip when apk is debuggable. |
| return !pkgInfoLite.debuggable; |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Check whether package verification has been enabled. |
| * |
| * @return true if verification should be performed |
| */ |
| private boolean isVerificationEnabled(PackageInfoLite pkgInfoLite, int userId, |
| List<String> requiredVerifierPackages) { |
| if (!DEFAULT_VERIFY_ENABLE) { |
| return false; |
| } |
| |
| final int installerUid = mVerificationInfo == null ? -1 : mVerificationInfo.mInstallerUid; |
| final boolean requestedDisableVerification = |
| (mInstallFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) != 0; |
| |
| // Check if installing from ADB |
| if ((mInstallFlags & PackageManager.INSTALL_FROM_ADB) != 0) { |
| return isAdbVerificationEnabled(pkgInfoLite, userId, requestedDisableVerification); |
| } else if (requestedDisableVerification) { |
| // Skip verification for non-adb installs |
| return false; |
| } |
| |
| // only when not installed from ADB, skip verification for instant apps when |
| // the installer and verifier are the same. |
| if (isInstant() && mPm.mInstantAppInstallerActivity != null) { |
| String installerPackage = mPm.mInstantAppInstallerActivity.packageName; |
| for (String requiredVerifierPackage : requiredVerifierPackages) { |
| if (installerPackage.equals(requiredVerifierPackage)) { |
| try { |
| mPm.mInjector.getSystemService(AppOpsManager.class) |
| .checkPackage(installerUid, requiredVerifierPackage); |
| if (DEBUG_VERIFY) { |
| Slog.i(TAG, "disable verification for instant app"); |
| } |
| return false; |
| } catch (SecurityException ignore) { |
| } |
| } |
| } |
| } |
| return true; |
| } |
| |
| private List<ComponentName> matchVerifiers(PackageInfoLite pkgInfo, |
| List<ResolveInfo> receivers, final PackageVerificationState verificationState) { |
| if (pkgInfo.verifiers == null || pkgInfo.verifiers.length == 0) { |
| return null; |
| } |
| |
| final int n = pkgInfo.verifiers.length; |
| final List<ComponentName> sufficientVerifiers = new ArrayList<>(n + 1); |
| for (int i = 0; i < n; i++) { |
| final VerifierInfo verifierInfo = pkgInfo.verifiers[i]; |
| |
| final ComponentName comp = matchComponentForVerifier(verifierInfo.packageName, |
| receivers); |
| if (comp == null) { |
| continue; |
| } |
| |
| final int verifierUid = mInstallPackageHelper.getUidForVerifier(verifierInfo); |
| if (verifierUid == -1) { |
| continue; |
| } |
| |
| if (DEBUG_VERIFY) { |
| Slog.d(TAG, "Added sufficient verifier " + verifierInfo.packageName |
| + " with the correct signature"); |
| } |
| sufficientVerifiers.add(comp); |
| verificationState.addSufficientVerifier(verifierUid); |
| } |
| |
| return sufficientVerifiers; |
| } |
| |
| private static ComponentName matchComponentForVerifier(String packageName, |
| List<ResolveInfo> receivers) { |
| ActivityInfo targetReceiver = null; |
| |
| final int nr = receivers.size(); |
| for (int i = 0; i < nr; i++) { |
| final ResolveInfo info = receivers.get(i); |
| if (info.activityInfo == null) { |
| continue; |
| } |
| |
| if (packageName.equals(info.activityInfo.packageName)) { |
| targetReceiver = info.activityInfo; |
| break; |
| } |
| } |
| |
| if (targetReceiver == null) { |
| return null; |
| } |
| |
| return new ComponentName(targetReceiver.packageName, targetReceiver.name); |
| } |
| |
| void populateInstallerExtras(Intent intent) { |
| intent.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE, |
| mInstallSource.mInitiatingPackageName); |
| |
| if (mVerificationInfo != null) { |
| if (mVerificationInfo.mOriginatingUri != null) { |
| intent.putExtra(Intent.EXTRA_ORIGINATING_URI, |
| mVerificationInfo.mOriginatingUri); |
| } |
| if (mVerificationInfo.mReferrer != null) { |
| intent.putExtra(Intent.EXTRA_REFERRER, |
| mVerificationInfo.mReferrer); |
| } |
| if (mVerificationInfo.mOriginatingUid >= 0) { |
| intent.putExtra(Intent.EXTRA_ORIGINATING_UID, |
| mVerificationInfo.mOriginatingUid); |
| } |
| if (mVerificationInfo.mInstallerUid >= 0) { |
| intent.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID, |
| mVerificationInfo.mInstallerUid); |
| } |
| } |
| } |
| |
| void setReturnCode(int ret, String message) { |
| if (mRet == PackageManager.INSTALL_SUCCEEDED) { |
| // Only update mRet if it was previously INSTALL_SUCCEEDED to |
| // ensure we do not overwrite any previous failure results. |
| mRet = ret; |
| mErrorMessage = message; |
| } |
| } |
| |
| void handleVerificationFinished() { |
| mWaitForVerificationToComplete = false; |
| handleReturnCode(); |
| } |
| |
| void handleIntegrityVerificationFinished() { |
| mWaitForIntegrityVerificationToComplete = false; |
| handleReturnCode(); |
| } |
| |
| void handleRollbackEnabled() { |
| // TODO(b/112431924): Consider halting the install if we |
| // couldn't enable rollback. |
| mWaitForEnableRollbackToComplete = false; |
| handleReturnCode(); |
| } |
| |
| void handleReturnCode() { |
| if (mWaitForVerificationToComplete || mWaitForIntegrityVerificationToComplete |
| || mWaitForEnableRollbackToComplete) { |
| return; |
| } |
| sendVerificationCompleteNotification(); |
| if (mRet != INSTALL_SUCCEEDED) { |
| PackageMetrics.onVerificationFailed(this); |
| } |
| } |
| |
| private void sendVerificationCompleteNotification() { |
| if (mParentVerifyingSession != null) { |
| mParentVerifyingSession.trySendVerificationCompleteNotification(this); |
| } else { |
| try { |
| mObserver.onPackageInstalled(null, mRet, mErrorMessage, |
| new Bundle()); |
| } catch (RemoteException e) { |
| Slog.i(TAG, "Observer no longer exists."); |
| } |
| } |
| } |
| |
| private void start() { |
| if (DEBUG_INSTALL) Slog.i(TAG, "start " + mUser + ": " + this); |
| Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueVerify", |
| System.identityHashCode(this)); |
| Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "start"); |
| handleStartVerify(); |
| handleReturnCode(); |
| Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); |
| } |
| |
| public void verifyStage() { |
| Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueVerify", |
| System.identityHashCode(this)); |
| mPm.mHandler.post(this::start); |
| } |
| |
| public void verifyStage(List<VerifyingSession> children) |
| throws PackageManagerException { |
| final MultiPackageVerifyingSession multiPackageVerifyingSession = |
| new MultiPackageVerifyingSession(this, children); |
| mPm.mHandler.post(multiPackageVerifyingSession::start); |
| } |
| |
| public int getRet() { |
| return mRet; |
| } |
| public String getErrorMessage() { |
| return mErrorMessage; |
| } |
| public UserHandle getUser() { |
| return mUser; |
| } |
| public int getSessionId() { |
| return mSessionId; |
| } |
| public int getDataLoaderType() { |
| return mDataLoaderType; |
| } |
| public int getUserActionRequiredType() { |
| return mUserActionRequiredType; |
| } |
| public boolean isInstant() { |
| return (mInstallFlags & PackageManager.INSTALL_INSTANT_APP) != 0; |
| } |
| public boolean isInherit() { |
| return mIsInherit; |
| } |
| public int getInstallerPackageUid() { |
| return mInstallSource.mInstallerPackageUid; |
| } |
| public boolean isApex() { |
| return (mInstallFlags & PackageManager.INSTALL_APEX) != 0; |
| } |
| public boolean isStaged() { |
| return mIsStaged; |
| } |
| } |