diff options
10 files changed, 155 insertions, 277 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index decfc8cceeae..2b55d1671337 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -4705,7 +4705,7 @@ package android.content.pm.verify.pkg { @FlaggedApi("android.content.pm.verification_service") public final class VerificationSession implements android.os.Parcelable { method public int describeContents(); - method public long extendTimeRemaining(long); + method @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) public long extendTimeRemaining(long); method @NonNull public java.util.List<android.content.pm.SharedLibraryInfo> getDeclaredLibraries(); method @NonNull public android.os.PersistableBundle getExtensionParams(); method public int getId(); @@ -4713,12 +4713,12 @@ package android.content.pm.verify.pkg { method @NonNull public String getPackageName(); method @NonNull public android.content.pm.SigningInfo getSigningInfo(); method @NonNull public android.net.Uri getStagedPackageUri(); - method public long getTimeoutTime(); + method @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) public long getTimeoutTime(); method public int getVerificationPolicy(); - method public void reportVerificationComplete(@NonNull android.content.pm.verify.pkg.VerificationStatus); - method public void reportVerificationComplete(@NonNull android.content.pm.verify.pkg.VerificationStatus, @NonNull android.os.PersistableBundle); - method public void reportVerificationIncomplete(int); - method public boolean setVerificationPolicy(int); + method @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) public void reportVerificationComplete(@NonNull android.content.pm.verify.pkg.VerificationStatus); + method @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) public void reportVerificationComplete(@NonNull android.content.pm.verify.pkg.VerificationStatus, @NonNull android.os.PersistableBundle); + method @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) public void reportVerificationIncomplete(int); + method @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) public boolean setVerificationPolicy(int); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.verify.pkg.VerificationSession> CREATOR; field public static final int VERIFICATION_INCOMPLETE_NETWORK_UNAVAILABLE = 1; // 0x1 diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl index ecea47944c72..c911326ccffd 100644 --- a/core/java/android/content/pm/IPackageInstaller.aidl +++ b/core/java/android/content/pm/IPackageInstaller.aidl @@ -94,9 +94,9 @@ interface IPackageInstaller { @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf={android.Manifest.permission.INSTALL_PACKAGES,android.Manifest.permission.REQUEST_INSTALL_PACKAGES})") void reportUnarchivalStatus(int unarchiveId, int status, long requiredStorageBytes, in PendingIntent userActionIntent, in UserHandle userHandle); - @EnforcePermission("VERIFICATION_AGENT") + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT)") int getVerificationPolicy(); - @EnforcePermission("VERIFICATION_AGENT") + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT)") boolean setVerificationPolicy(int policy); } diff --git a/core/java/android/content/pm/verify/pkg/IVerificationSessionInterface.aidl b/core/java/android/content/pm/verify/pkg/IVerificationSessionInterface.aidl index 2ab745205193..66caf2d0fec0 100644 --- a/core/java/android/content/pm/verify/pkg/IVerificationSessionInterface.aidl +++ b/core/java/android/content/pm/verify/pkg/IVerificationSessionInterface.aidl @@ -24,9 +24,16 @@ import android.os.PersistableBundle; * @hide */ interface IVerificationSessionInterface { + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT)") long getTimeoutTime(int verificationId); + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT)") long extendTimeRemaining(int verificationId, long additionalMs); + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT)") boolean setVerificationPolicy(int verificationId, int policy); + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT)") void reportVerificationIncomplete(int verificationId, int reason); - void reportVerificationComplete(int verificationId, in VerificationStatus status, in @nullable PersistableBundle extensionResponse); + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT)") + void reportVerificationComplete(int verificationId, in VerificationStatus status); + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT)") + void reportVerificationCompleteWithExtensionResponse(int verificationId, in VerificationStatus status, in PersistableBundle response); }
\ No newline at end of file diff --git a/core/java/android/content/pm/verify/pkg/VerificationSession.java b/core/java/android/content/pm/verify/pkg/VerificationSession.java index 97f78e0978fa..4ade21198f37 100644 --- a/core/java/android/content/pm/verify/pkg/VerificationSession.java +++ b/core/java/android/content/pm/verify/pkg/VerificationSession.java @@ -19,6 +19,7 @@ package android.content.pm.verify.pkg; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.content.pm.Flags; import android.content.pm.PackageInstaller; @@ -165,8 +166,8 @@ public final class VerificationSession implements Parcelable { /** * Get the value of Clock.elapsedRealtime() at which time this verification * will timeout as incomplete if no other verification response is provided. - * @throws SecurityException if the caller is not the current verifier bound by the system. */ + @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) public long getTimeoutTime() { try { return mSession.getTimeoutTime(mId); @@ -189,8 +190,8 @@ public final class VerificationSession implements Parcelable { /** * Override the verification policy for this session. * @return True if the override was successful, False otherwise. - * @throws SecurityException if the caller is not the current verifier bound by the system. */ + @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) public boolean setVerificationPolicy(@PackageInstaller.VerificationPolicy int policy) { if (mVerificationPolicy == policy) { // No effective policy change @@ -214,8 +215,8 @@ public final class VerificationSession implements Parcelable { * This may be called multiple times. If the request would bypass any max * duration by the system, the method will return a lower value than the * requested amount that indicates how much the time was extended. - * @throws SecurityException if the caller is not the current verifier bound by the system. */ + @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) public long extendTimeRemaining(long additionalMs) { try { return mSession.extendTimeRemaining(mId, additionalMs); @@ -226,9 +227,9 @@ public final class VerificationSession implements Parcelable { /** * Report to the system that verification could not be completed along - * with an approximate reason to pass on to the installer.] - * @throws SecurityException if the caller is not the current verifier bound by the system. + * with an approximate reason to pass on to the installer. */ + @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) public void reportVerificationIncomplete(@VerificationIncompleteReason int reason) { try { mSession.reportVerificationIncomplete(mId, reason); @@ -241,11 +242,11 @@ public final class VerificationSession implements Parcelable { * Report to the system that the verification has completed and the * install process may act on that status to either block in the case * of failure or continue to process the install in the case of success. - * @throws SecurityException if the caller is not the current verifier bound by the system. */ + @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) public void reportVerificationComplete(@NonNull VerificationStatus status) { try { - mSession.reportVerificationComplete(mId, status, /* extensionResponse= */ null); + mSession.reportVerificationComplete(mId, status); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -255,12 +256,12 @@ public final class VerificationSession implements Parcelable { * Same as {@link #reportVerificationComplete(VerificationStatus)}, but also provide * a result to the extension params provided in the request, which will be passed to the * installer in the installation result. - * @throws SecurityException if the caller is not the current verifier bound by the system. */ + @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) public void reportVerificationComplete(@NonNull VerificationStatus status, - @NonNull PersistableBundle extensionResponse) { + @NonNull PersistableBundle response) { try { - mSession.reportVerificationComplete(mId, status, extensionResponse); + mSession.reportVerificationCompleteWithExtensionResponse(mId, status, response); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/tests/coretests/src/android/content/pm/verify/VerificationSessionTest.java b/core/tests/coretests/src/android/content/pm/verify/VerificationSessionTest.java index f1e1df5ae3fb..90ae306952fe 100644 --- a/core/tests/coretests/src/android/content/pm/verify/VerificationSessionTest.java +++ b/core/tests/coretests/src/android/content/pm/verify/VerificationSessionTest.java @@ -142,10 +142,10 @@ public class VerificationSessionTest { new VerificationStatus.Builder().setVerified(true).build(); mTestSession.reportVerificationComplete(status); verify(mTestSessionInterface, times(1)).reportVerificationComplete( - eq(TEST_ID), eq(status), eq(null)); + eq(TEST_ID), eq(status)); mTestSession.reportVerificationComplete(status, response); verify(mTestSessionInterface, times(1)) - .reportVerificationComplete( + .reportVerificationCompleteWithExtensionResponse( eq(TEST_ID), eq(status), eq(response)); final int reason = VerificationSession.VERIFICATION_INCOMPLETE_UNKNOWN; diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 74167f686dea..2f2b45b8e8fb 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -39,7 +39,6 @@ import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; import static org.xmlpull.v1.XmlPullParser.START_TAG; import android.Manifest; -import android.annotation.EnforcePermission; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; @@ -88,7 +87,6 @@ import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.ParcelableException; -import android.os.PermissionEnforcer; import android.os.Process; import android.os.RemoteCallback; import android.os.RemoteCallbackList; @@ -317,8 +315,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements public PackageInstallerService(Context context, PackageManagerService pm, Supplier<PackageParser2> apexParserSupplier) { - super(PermissionEnforcer.fromContext(context)); - mContext = context; mPm = pm; @@ -1886,20 +1882,23 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } @Override - @EnforcePermission(android.Manifest.permission.VERIFICATION_AGENT) public @PackageInstaller.VerificationPolicy int getVerificationPolicy() { - getVerificationPolicy_enforcePermission(); + if (mContext.checkCallingOrSelfPermission(Manifest.permission.VERIFICATION_AGENT) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("You need the " + + "com.android.permission.VERIFICATION_AGENT permission " + + "to get the verification policy"); + } return mVerificationPolicy.get(); } @Override - @EnforcePermission(android.Manifest.permission.VERIFICATION_AGENT) public boolean setVerificationPolicy(@PackageInstaller.VerificationPolicy int policy) { - setVerificationPolicy_enforcePermission(); - final int callingUid = getCallingUid(); - // Only the verifier currently bound by the system can change the policy, except for Shell - if (!PackageManagerServiceUtils.isRootOrShell(callingUid)) { - mVerifierController.assertCallerIsCurrentVerifier(callingUid); + if (mContext.checkCallingOrSelfPermission(Manifest.permission.VERIFICATION_AGENT) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("You need the " + + "com.android.permission.VERIFICATION_AGENT permission " + + "to set the verification policy"); } if (!isValidVerificationPolicy(policy)) { return false; diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index d417505f46e7..e7930890d0fe 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -2897,13 +2897,14 @@ 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. - final VerifierCallback verifierCallback = new VerifierCallback(); if (!mVerifierController.startVerificationSession(mPm::snapshotComputer, userId, sessionId, getPackageName(), Uri.fromFile(stageDir), signingInfo, declaredLibraries, mVerificationPolicy.get(), /* extensionParams= */ null, - verifierCallback, /* retry= */ false)) { - // A verifier is installed but cannot be connected. - verifierCallback.onConnectionFailed(); + new VerifierCallback(), /* retry= */ false)) { + // A verifier is installed but cannot be connected. Installation disallowed. + onSessionVerificationFailure(INSTALL_FAILED_INTERNAL_ERROR, + "A verifier agent is available on device but cannot be connected.", + /* extras= */ null); } } else { // No need to check with verifier. Proceed with the rest of the verification. @@ -3007,6 +3008,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { onSessionVerificationFailure(INSTALL_FAILED_VERIFICATION_FAILURE, "A verifier agent is available on device but cannot be connected.", bundle); + }); } /** diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 34005b37d1a1..e66ae21c4778 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -399,10 +399,6 @@ class PackageManagerShellCommand extends ShellCommand { return runUnarchive(); case "get-domain-verification-agent": return runGetDomainVerificationAgent(); - case "get-verification-policy": - return runGetVerificationPolicy(); - case "set-verification-policy": - return runSetVerificationPolicy(); default: { if (ART_SERVICE_COMMANDS.contains(cmd)) { return runArtServiceCommand(); @@ -4656,86 +4652,6 @@ class PackageManagerShellCommand extends ShellCommand { return 0; } - private int runGetVerificationPolicy() throws RemoteException { - final PrintWriter pw = getOutPrintWriter(); - int userId = UserHandle.USER_ALL; - - String opt; - while ((opt = getNextOption()) != null) { - if (opt.equals("--user")) { - userId = UserHandle.parseUserArg(getNextArgRequired()); - if (userId != UserHandle.USER_ALL && userId != UserHandle.USER_CURRENT) { - UserManagerInternal umi = - LocalServices.getService(UserManagerInternal.class); - UserInfo userInfo = umi.getUserInfo(userId); - if (userInfo == null) { - pw.println("Failure [user " + userId + " doesn't exist]"); - return 1; - } - } - } else { - pw.println("Error: Unknown option: " + opt); - return 1; - } - } - final int translatedUserId = - translateUserId(userId, UserHandle.USER_SYSTEM, "runGetVerificationPolicy"); - try { - final IPackageInstaller installer = mInterface.getPackageInstaller(); - // TODO(b/360129657): global verification policy should be per user - final int policy = installer.getVerificationPolicy(); - pw.println(policy); - } catch (Exception e) { - pw.println("Failure [" + e.getMessage() + "]"); - return 1; - } - return 0; - } - - private int runSetVerificationPolicy() throws RemoteException { - final PrintWriter pw = getOutPrintWriter(); - int userId = UserHandle.USER_ALL; - - String opt; - while ((opt = getNextOption()) != null) { - if (opt.equals("--user")) { - userId = UserHandle.parseUserArg(getNextArgRequired()); - if (userId != UserHandle.USER_ALL && userId != UserHandle.USER_CURRENT) { - UserManagerInternal umi = - LocalServices.getService(UserManagerInternal.class); - UserInfo userInfo = umi.getUserInfo(userId); - if (userInfo == null) { - pw.println("Failure [user " + userId + " doesn't exist]"); - return 1; - } - } - } else { - pw.println("Error: Unknown option: " + opt); - return 1; - } - } - final String policyStr = getNextArg(); - if (policyStr == null) { - pw.println("Error: policy not specified"); - return 1; - } - final int translatedUserId = - translateUserId(userId, UserHandle.USER_SYSTEM, "runSetVerificationPolicy"); - try { - final IPackageInstaller installer = mInterface.getPackageInstaller(); - // TODO(b/360129657): global verification policy should be per user - final boolean success = installer.setVerificationPolicy(Integer.parseInt(policyStr)); - if (!success) { - pw.println("Failure setting verification policy."); - return 1; - } - } catch (Exception e) { - pw.println("Failure [" + e.getMessage() + "]"); - return 1; - } - return 0; - } - @Override public void onHelp() { final PrintWriter pw = getOutPrintWriter(); @@ -5168,14 +5084,6 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(" --user: return the agent of the given user (SYSTEM_USER if unspecified)"); pw.println(" get-package-storage-stats [--user <USER_ID>] <PACKAGE>"); pw.println(" Return the storage stats for the given app, if present"); - pw.println(" get-verification-policy [--user USER_ID]"); - pw.println(" Display current verification enforcement policy which will be applied to"); - pw.println(" all the future installation sessions"); - pw.println(" --user: show the policy of the given user (SYSTEM_USER if unspecified)"); - pw.println(" set-verification-policy POLICY [--user USER_ID]"); - pw.println(" Sets the verification policy of all the future installation sessions."); - pw.println(" --user: set the policy of the given user (SYSTEM_USER if unspecified)"); - pw.println(""); pw.println(""); printArtServiceHelp(); pw.println(""); diff --git a/services/core/java/com/android/server/pm/verify/pkg/VerifierController.java b/services/core/java/com/android/server/pm/verify/pkg/VerifierController.java index 78849d286ebe..a35618b309bb 100644 --- a/services/core/java/com/android/server/pm/verify/pkg/VerifierController.java +++ b/services/core/java/com/android/server/pm/verify/pkg/VerifierController.java @@ -18,12 +18,13 @@ package com.android.server.pm.verify.pkg; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; -import static android.os.Process.INVALID_UID; import static android.os.Process.SYSTEM_UID; import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE; +import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.content.ComponentName; import android.content.Context; @@ -113,17 +114,10 @@ public class VerifierController { private final Context mContext; private final Handler mHandler; - // Guards the remote service object, as well as the verifier name and UID, which should all be - // changed at the same time. - private final Object mLock = new Object(); @Nullable - @GuardedBy("mLock") private ServiceConnector<IVerifierService> mRemoteService; @Nullable - @GuardedBy("mLock") private ComponentName mRemoteServiceComponentName; - @GuardedBy("mLock") - private int mRemoteServiceUid = INVALID_UID; @NonNull private Injector mInjector; @@ -149,11 +143,9 @@ public class VerifierController { */ @Nullable public String getVerifierPackageName(Supplier<Computer> snapshotSupplier, int userId) { - synchronized (mLock) { - if (isVerifierConnectedLocked()) { - // Verifier is connected or is being connected, so it must be installed. - return mRemoteServiceComponentName.getPackageName(); - } + if (isVerifierConnected()) { + // Verifier is connected or is being connected, so it must be installed. + return mRemoteServiceComponentName.getPackageName(); } // Verifier has been disconnected, or it hasn't been connected. Check if it's installed. return mInjector.getVerifierPackageName(snapshotSupplier.get(), userId); @@ -186,29 +178,16 @@ public class VerifierController { } return true; } - Computer snapshot = snapshotSupplier.get(); Pair<ServiceConnector<IVerifierService>, ComponentName> result = - mInjector.getRemoteService(snapshot, mContext, userId, mHandler); + mInjector.getRemoteService(snapshotSupplier.get(), mContext, userId, mHandler); if (result == null || result.first == null) { if (DEBUG) { Slog.i(TAG, "Unable to find a qualified verifier."); } return false; } - final int verifierUid = snapshot.getPackageUidInternal( - result.second.getPackageName(), 0, userId, /* callingUid= */ SYSTEM_UID); - if (verifierUid == INVALID_UID) { - if (DEBUG) { - Slog.i(TAG, "Unable to find the UID of the qualified verifier."); - } - return false; - } - synchronized (mLock) { - mRemoteService = result.first; - mRemoteServiceComponentName = result.second; - mRemoteServiceUid = verifierUid; - } - + mRemoteService = result.first; + mRemoteServiceComponentName = result.second; if (DEBUG) { Slog.i(TAG, "Connecting to a qualified verifier: " + mRemoteServiceComponentName); } @@ -233,13 +212,10 @@ public class VerifierController { } private void destroy() { - synchronized (mLock) { - if (isVerifierConnectedLocked()) { - mRemoteService.unbind(); - mRemoteService = null; - mRemoteServiceComponentName = null; - mRemoteServiceUid = INVALID_UID; - } + if (isVerifierConnected()) { + mRemoteService.unbind(); + mRemoteService = null; + mRemoteServiceComponentName = null; } } }); @@ -247,8 +223,7 @@ public class VerifierController { return true; } - @GuardedBy("mLock") - private boolean isVerifierConnectedLocked() { + private boolean isVerifierConnected() { return mRemoteService != null && mRemoteServiceComponentName != null; } @@ -257,21 +232,19 @@ public class VerifierController { * requested for verification. */ public void notifyPackageNameAvailable(@NonNull String packageName) { - synchronized (mLock) { - if (!isVerifierConnectedLocked()) { - if (DEBUG) { - Slog.i(TAG, "Verifier is not connected. Not notifying package name available"); - } - return; + if (!isVerifierConnected()) { + if (DEBUG) { + Slog.i(TAG, "Verifier is not connected. Not notifying package name available"); } - // Best effort. We don't check for the result. - mRemoteService.run(service -> { - if (DEBUG) { - Slog.i(TAG, "Notifying package name available for " + packageName); - } - service.onPackageNameAvailable(packageName); - }); + return; } + // Best effort. We don't check for the result. + mRemoteService.run(service -> { + if (DEBUG) { + Slog.i(TAG, "Notifying package name available for " + packageName); + } + service.onPackageNameAvailable(packageName); + }); } /** @@ -280,29 +253,27 @@ public class VerifierController { * will no longer be requested for verification, possibly because the installation is canceled. */ public void notifyVerificationCancelled(@NonNull String packageName) { - synchronized (mLock) { - if (!isVerifierConnectedLocked()) { - if (DEBUG) { - Slog.i(TAG, "Verifier is not connected. Not notifying verification cancelled"); - } - return; + if (!isVerifierConnected()) { + if (DEBUG) { + Slog.i(TAG, "Verifier is not connected. Not notifying verification cancelled"); } - // Best effort. We don't check for the result. - mRemoteService.run(service -> { - if (DEBUG) { - Slog.i(TAG, "Notifying verification cancelled for " + packageName); - } - service.onVerificationCancelled(packageName); - }); + return; } + // Best effort. We don't check for the result. + mRemoteService.run(service -> { + if (DEBUG) { + Slog.i(TAG, "Notifying verification cancelled for " + packageName); + } + service.onVerificationCancelled(packageName); + }); } /** * Called to notify the bound verifier agent that a package that's pending installation needs * to be verified right now. * <p>The verification request must be sent to the verifier as soon as the verifier is - * connected. If the connection cannot be made within the specified time limit from - * when the request is sent out, we consider the verification to be failed and notify the + * connected. If the connection cannot be made within {@link #CONNECTION_TIMEOUT_SECONDS}</p> + * of when the request is sent out, we consider the verification to be failed and notify the * installation session.</p> * <p>If a response is not returned from the verifier agent within a timeout duration from the * time the request is sent to the verifier, the verification will be considered a failure.</p> @@ -320,48 +291,43 @@ public class VerifierController { if (!bindToVerifierServiceIfNeeded(snapshotSupplier, userId)) { return false; } + if (!isVerifierConnected()) { + if (DEBUG) { + Slog.i(TAG, "Verifier is not connected. Not notifying verification required"); + } + // Normally this should not happen because we just tried to bind. But if the verifier + // just crashed or just became unavailable, we should notify the installation session so + // it can finish with a verification failure. + return false; + } // For now, the verification id is the same as the installation session id. final int verificationId = installationSessionId; - synchronized (mLock) { - if (!isVerifierConnectedLocked()) { + final VerificationSession session = new VerificationSession( + /* id= */ verificationId, + /* installSessionId= */ installationSessionId, + packageName, stagedPackageUri, signingInfo, declaredLibraries, extensionParams, + verificationPolicy, new VerificationSessionInterface(callback)); + AndroidFuture<Void> unusedFuture = mRemoteService.post(service -> { + if (!retry) { if (DEBUG) { - Slog.i(TAG, "Verifier is not connected. Not notifying verification required"); + Slog.i(TAG, "Notifying verification required for session " + verificationId); } - // Normally this should not happen because we just tried to bind. But if the - // verifier just crashed or just became unavailable, we should notify the - // installation session so it can finish with a verification failure. - return false; - } - final VerificationSession session = new VerificationSession( - /* id= */ verificationId, - /* installSessionId= */ installationSessionId, - packageName, stagedPackageUri, signingInfo, declaredLibraries, extensionParams, - verificationPolicy, new VerificationSessionInterface(callback)); - AndroidFuture<Void> unusedFuture = mRemoteService.post(service -> { - if (!retry) { - if (DEBUG) { - Slog.i(TAG, "Notifying verification required for session " - + verificationId); - } - service.onVerificationRequired(session); - } else { - if (DEBUG) { - Slog.i(TAG, "Notifying verification retry for session " - + verificationId); - } - service.onVerificationRetry(session); + service.onVerificationRequired(session); + } else { + if (DEBUG) { + Slog.i(TAG, "Notifying verification retry for session " + verificationId); } - }).orTimeout(mInjector.getVerifierConnectionTimeoutMillis(), TimeUnit.MILLISECONDS) - .whenComplete((res, err) -> { - if (err != null) { - Slog.e(TAG, "Error notifying verification request for session " - + verificationId, err); - // Notify the installation session so it can finish with verification - // failure. - callback.onConnectionFailed(); - } - }); - } + service.onVerificationRetry(session); + } + }).orTimeout(mInjector.getVerifierConnectionTimeoutMillis(), TimeUnit.MILLISECONDS) + .whenComplete((res, err) -> { + if (err != null) { + Slog.e(TAG, "Error notifying verification request for session " + verificationId, + err); + // Notify the installation session so it can finish with verification failure. + callback.onConnectionFailed(); + } + }); // Keep track of the session status with the ID. Start counting down the session timeout. final long defaultTimeoutMillis = mInjector.getVerificationRequestTimeoutMillis(); final long maxExtendedTimeoutMillis = mInjector.getMaxVerificationExtendedTimeoutMillis(); @@ -403,27 +369,24 @@ public class VerifierController { * Called to notify the bound verifier agent that a verification request has timed out. */ public void notifyVerificationTimeout(int verificationId) { - synchronized (mLock) { - if (!isVerifierConnectedLocked()) { - if (DEBUG) { - Slog.i(TAG, - "Verifier is not connected. Not notifying timeout for " - + verificationId); - } - return; + if (!isVerifierConnected()) { + if (DEBUG) { + Slog.i(TAG, + "Verifier is not connected. Not notifying timeout for " + verificationId); } - AndroidFuture<Void> unusedFuture = mRemoteService.post(service -> { - if (DEBUG) { - Slog.i(TAG, "Notifying timeout for " + verificationId); - } - service.onVerificationTimeout(verificationId); - }).whenComplete((res, err) -> { - if (err != null) { - Slog.e(TAG, "Error notifying VerificationTimeout for session " - + verificationId, err); - } - }); + return; } + AndroidFuture<Void> unusedFuture = mRemoteService.post(service -> { + if (DEBUG) { + Slog.i(TAG, "Notifying timeout for " + verificationId); + } + service.onVerificationTimeout(verificationId); + }).whenComplete((res, err) -> { + if (err != null) { + Slog.e(TAG, "Error notifying VerificationTimeout for session " + + verificationId, (Throwable) err); + } + }); } /** @@ -442,19 +405,17 @@ public class VerifierController { } } - /** - * Assert that the calling UID is the same as the UID of the currently connected verifier. - */ - public void assertCallerIsCurrentVerifier(int callingUid) { - synchronized (mLock) { - if (!isVerifierConnectedLocked()) { - throw new IllegalStateException( - "Unable to proceed because the verifier has been disconnected."); - } - if (callingUid != mRemoteServiceUid) { - throw new IllegalStateException( - "Calling uid " + callingUid + " is not the current verifier."); - } + @RequiresPermission(Manifest.permission.VERIFICATION_AGENT) + private void checkCallerPermission() { + // TODO: think of a better way to test it on non-eng builds + if (Build.IS_ENG) { + return; + } + if (mContext.checkCallingOrSelfPermission(Manifest.permission.VERIFICATION_AGENT) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("You need the" + + " com.android.permission.VERIFICATION_AGENT permission" + + " to use VerificationSession APIs."); } } @@ -468,7 +429,7 @@ public class VerifierController { @Override public long getTimeoutTime(int verificationId) { - assertCallerIsCurrentVerifier(getCallingUid()); + checkCallerPermission(); synchronized (mVerificationStatus) { final VerificationStatusTracker tracker = mVerificationStatus.get(verificationId); if (tracker == null) { @@ -481,7 +442,7 @@ public class VerifierController { @Override public long extendTimeRemaining(int verificationId, long additionalMs) { - assertCallerIsCurrentVerifier(getCallingUid()); + checkCallerPermission(); synchronized (mVerificationStatus) { final VerificationStatusTracker tracker = mVerificationStatus.get(verificationId); if (tracker == null) { @@ -495,7 +456,7 @@ public class VerifierController { @Override public boolean setVerificationPolicy(int verificationId, @PackageInstaller.VerificationPolicy int policy) { - assertCallerIsCurrentVerifier(getCallingUid()); + checkCallerPermission(); synchronized (mVerificationStatus) { final VerificationStatusTracker tracker = mVerificationStatus.get(verificationId); if (tracker == null) { @@ -508,7 +469,7 @@ public class VerifierController { @Override public void reportVerificationIncomplete(int id, int reason) { - assertCallerIsCurrentVerifier(getCallingUid()); + checkCallerPermission(); final VerificationStatusTracker tracker; synchronized (mVerificationStatus) { tracker = mVerificationStatus.get(id); @@ -523,9 +484,15 @@ public class VerifierController { } @Override - public void reportVerificationComplete(int id, VerificationStatus verificationStatus, - @Nullable PersistableBundle extensionResponse) { - assertCallerIsCurrentVerifier(getCallingUid()); + public void reportVerificationComplete(int id, VerificationStatus verificationStatus) { + reportVerificationCompleteWithExtensionResponse(id, verificationStatus, + /* extensionResponse= */ null); + } + + @Override + public void reportVerificationCompleteWithExtensionResponse(int id, + VerificationStatus verificationStatus, PersistableBundle extensionResponse) { + checkCallerPermission(); final VerificationStatusTracker tracker; synchronized (mVerificationStatus) { tracker = mVerificationStatus.get(id); diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/verify/pkg/VerifierControllerTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/verify/pkg/VerifierControllerTest.java index 3046d4beb7a3..24617984eaf7 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/verify/pkg/VerifierControllerTest.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/verify/pkg/VerifierControllerTest.java @@ -24,7 +24,6 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -50,7 +49,6 @@ import android.util.Pair; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; -import androidx.test.platform.app.InstrumentationRegistry; import com.android.internal.infra.AndroidFuture; import com.android.internal.infra.ServiceConnector; @@ -124,10 +122,6 @@ public class VerifierControllerTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); - // Mock that the UID of this test becomes the UID of the verifier - when(mSnapshot.getPackageUidInternal(anyString(), anyLong(), anyInt(), anyInt())) - .thenReturn(InstrumentationRegistry.getInstrumentation().getContext() - .getApplicationInfo().uid); when(mInjector.getVerifierPackageName(any(Computer.class), anyInt())).thenReturn( TEST_VERIFIER_COMPONENT_NAME.getPackageName()); when(mInjector.getRemoteService( |