diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl index 115d4b0cb2705..e3016a4253709 100644 --- a/core/java/android/content/pm/IPackageInstaller.aidl +++ b/core/java/android/content/pm/IPackageInstaller.aidl @@ -65,6 +65,8 @@ interface IPackageInstaller { void bypassNextAllowedApexUpdateCheck(boolean value); + void disableVerificationForUid(int uid); + void setAllowUnlimitedSilentUpdates(String installerPackageName); void setSilentUpdatesThrottleTime(long throttleTimeInSeconds); void checkInstallConstraints(String installerPackageName, in List packageNames, diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 239853c857ccf..617561a58351b 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -184,6 +184,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements private volatile boolean mOkToSendBroadcasts = false; private volatile boolean mBypassNextStagedInstallerCheck = false; private volatile boolean mBypassNextAllowedApexUpdateCheck = false; + private volatile int mDisableVerificationForUid = INVALID_UID; /** * File storing persisted {@link #mSessions} metadata. @@ -712,7 +713,16 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements params.installFlags &= ~PackageManager.INSTALL_REQUEST_DOWNGRADE; } - if ((params.installFlags & ADB_DEV_MODE) != ADB_DEV_MODE) { + if (mDisableVerificationForUid != INVALID_UID) { + if (callingUid == mDisableVerificationForUid) { + params.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION; + } else { + // Clear the flag if current calling uid doesn't match the requested uid. + params.installFlags &= ~PackageManager.INSTALL_DISABLE_VERIFICATION; + } + // Reset the field as this is a one-off request. + mDisableVerificationForUid = INVALID_UID; + } else if ((params.installFlags & ADB_DEV_MODE) != ADB_DEV_MODE) { // Only tools under specific conditions (test app installed through ADB, and // verification disabled flag specified) can disable verification. params.installFlags &= ~PackageManager.INSTALL_DISABLE_VERIFICATION; @@ -1367,6 +1377,14 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements mBypassNextAllowedApexUpdateCheck = value; } + @Override + public void disableVerificationForUid(int uid) { + if (!isCalledBySystemOrShell(Binder.getCallingUid())) { + throw new SecurityException("Operation not allowed for caller"); + } + mDisableVerificationForUid = uid; + } + /** * Set an installer to allow for the unlimited silent updates. */ diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 849cbeba0300f..56fb7d0d1e0cd 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -342,6 +342,8 @@ class PackageManagerShellCommand extends ShellCommand { return runBypassStagedInstallerCheck(); case "bypass-allowed-apex-update-check": return runBypassAllowedApexUpdateCheck(); + case "disable-verification-for-uid": + return runDisableVerificationForUid(); case "set-silent-updates-policy": return runSetSilentUpdatesPolicy(); default: { @@ -514,6 +516,29 @@ class PackageManagerShellCommand extends ShellCommand { } } + private int runDisableVerificationForUid() { + final PrintWriter pw = getOutPrintWriter(); + try { + int uid = Integer.parseInt(getNextArgRequired()); + var amInternal = LocalServices.getService(ActivityManagerInternal.class); + boolean isInstrumented = + amInternal.getInstrumentationSourceUid(uid) != Process.INVALID_UID; + if (isInstrumented) { + mInterface.getPackageInstaller().disableVerificationForUid(uid); + return 0; + } else { + // Only available for testing + pw.println("Error: must specify an instrumented uid"); + return -1; + } + } catch (RemoteException e) { + pw.println("Failure [" + + e.getClass().getName() + " - " + + e.getMessage() + "]"); + return -1; + } + } + private int uninstallSystemUpdates(String packageName) { final PrintWriter pw = getOutPrintWriter(); boolean failedUninstalls = false; diff --git a/services/core/java/com/android/server/pm/VerifyingSession.java b/services/core/java/com/android/server/pm/VerifyingSession.java index a54f52619f357..b2fd46c172d5c 100644 --- a/services/core/java/com/android/server/pm/VerifyingSession.java +++ b/services/core/java/com/android/server/pm/VerifyingSession.java @@ -680,12 +680,15 @@ final class VerifyingSession { } 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) { - boolean requestedDisableVerification = - (mInstallFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) != 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