blob: f0610180040c4ea9174db69037579d7849e758d1 [file] [log] [blame]
/*
* 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.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.server.pm.PackageManagerService.PACKAGE_MIME_TYPE;
import static com.android.server.pm.PackageManagerService.TAG;
import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
final class VerificationUtils {
/**
* The default maximum time to wait for the verification agent to return in
* milliseconds.
*/
private static final long DEFAULT_VERIFICATION_TIMEOUT = 10 * 1000;
/**
* The default maximum time to wait for the verification agent to return in
* milliseconds.
*/
private static final long DEFAULT_STREAMING_VERIFICATION_TIMEOUT = 3 * 1000;
public static long getVerificationTimeout(Context context, boolean streaming) {
if (streaming) {
return getDefaultStreamingVerificationTimeout(context);
}
return getDefaultVerificationTimeout(context);
}
/**
* Get the default verification agent timeout. Used for both the APK verifier and the
* intent filter verifier.
*
* @return verification timeout in milliseconds
*/
public static long getDefaultVerificationTimeout(Context context) {
long timeout = Settings.Global.getLong(context.getContentResolver(),
Settings.Global.PACKAGE_VERIFIER_TIMEOUT, DEFAULT_VERIFICATION_TIMEOUT);
// The setting can be used to increase the timeout but not decrease it, since that is
// equivalent to disabling the verifier.
return Math.max(timeout, DEFAULT_VERIFICATION_TIMEOUT);
}
/**
* Get the default verification agent timeout for streaming installations.
*
* @return verification timeout in milliseconds
*/
public static long getDefaultStreamingVerificationTimeout(Context context) {
long timeout = Settings.Global.getLong(context.getContentResolver(),
Settings.Global.PACKAGE_STREAMING_VERIFIER_TIMEOUT,
DEFAULT_STREAMING_VERIFICATION_TIMEOUT);
// The setting can be used to increase the timeout but not decrease it, since that is
// equivalent to disabling the verifier.
return Math.max(timeout, DEFAULT_STREAMING_VERIFICATION_TIMEOUT);
}
public static void broadcastPackageVerified(int verificationId, Uri packageUri,
int verificationCode, @Nullable String rootHashString, int dataLoaderType,
UserHandle user, Context context) {
final Intent intent = new Intent(Intent.ACTION_PACKAGE_VERIFIED);
intent.setDataAndType(packageUri, PACKAGE_MIME_TYPE);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
intent.putExtra(PackageManager.EXTRA_VERIFICATION_RESULT, verificationCode);
if (rootHashString != null) {
intent.putExtra(PackageManager.EXTRA_VERIFICATION_ROOT_HASH, rootHashString);
}
intent.putExtra(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType);
context.sendBroadcastAsUser(intent, user,
android.Manifest.permission.PACKAGE_VERIFICATION_AGENT);
}
@VisibleForTesting(visibility = PACKAGE)
static void processVerificationResponseOnTimeout(int verificationId,
PackageVerificationState state, PackageVerificationResponse response,
PackageManagerService pms) {
state.setVerifierResponseOnTimeout(response.callerUid, response.code);
processVerificationResponse(verificationId, state, response.code, "Verification timed out",
pms);
}
@VisibleForTesting(visibility = PACKAGE)
static void processVerificationResponse(int verificationId, PackageVerificationState state,
PackageVerificationResponse response, PackageManagerService pms) {
state.setVerifierResponse(response.callerUid, response.code);
processVerificationResponse(verificationId, state, response.code, "Install not allowed",
pms);
}
private static void processVerificationResponse(int verificationId,
PackageVerificationState state, int verificationResult, String failureReason,
PackageManagerService pms) {
if (!state.isVerificationComplete()) {
return;
}
final VerifyingSession verifyingSession = state.getVerifyingSession();
final Uri originUri = verifyingSession != null ? Uri.fromFile(
verifyingSession.mOriginInfo.mResolvedFile) : null;
final int verificationCode =
state.isInstallAllowed() ? verificationResult : PackageManager.VERIFICATION_REJECT;
if (pms != null && verifyingSession != null) {
VerificationUtils.broadcastPackageVerified(verificationId, originUri,
verificationCode, null,
verifyingSession.getDataLoaderType(), verifyingSession.getUser(),
pms.mContext);
}
if (state.isInstallAllowed()) {
Slog.i(TAG, "Continuing with installation of " + originUri);
} else {
String errorMsg = failureReason + " for " + originUri;
Slog.i(TAG, errorMsg);
if (verifyingSession != null) {
verifyingSession.setReturnCode(
PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, errorMsg);
}
}
if (pms != null && state.areAllVerificationsComplete()) {
pms.mPendingVerification.remove(verificationId);
}
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
if (verifyingSession != null) {
verifyingSession.handleVerificationFinished();
}
}
}