Check commit() IntentSender should come from a mutable PendingIntent
When an IMMUTABLE PendingIntent was used to create an IntentSender
which was passed into Session.commit(IntentSender statusReceiver),
the PendingIntent cannot be modified and the caller couldn't receive
EXTRA_STATUS or any installation results.
The system should provide an error signal to let the caller know to
pass the correct parameter.
Bug: 240618202
Test: atest android.packageinstaller.install.cts.SessionTest
Test: manual. A sample app with an immutable PendingIntent
Change-Id: If3d2ade7d8acb8a91f1223618a02b751e7f5970a
diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java
index ccb53cf..3686898 100644
--- a/core/java/android/content/IntentSender.java
+++ b/core/java/android/content/IntentSender.java
@@ -417,4 +417,12 @@
return mCachedInfo;
}
+
+ /**
+ * Check if the PendingIntent is marked with {@link android.app.PendingIntent#FLAG_IMMUTABLE}.
+ * @hide
+ */
+ public boolean isImmutable() {
+ return getCachedInfo().isImmutable();
+ }
}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 0ce8b7e..ea43afa 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1062,6 +1062,9 @@
* @param timeoutMillis The maximum time to wait, in milliseconds until the
* constraints are satisfied. The caller will be notified via
* {@code statusReceiver} if timeout happens before commit.
+ * @throws IllegalArgumentException if the {@code statusReceiver} from an immutable
+ * {@link android.app.PendingIntent} when caller has a target SDK of API
+ * {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} or above.
*/
public void commitSessionAfterInstallConstraintsAreMet(int sessionId,
@NonNull IntentSender statusReceiver, @NonNull InstallConstraints constraints,
@@ -1736,6 +1739,9 @@
*
* @throws SecurityException if streams opened through
* {@link #openWrite(String, long, long)} are still open.
+ * @throws IllegalArgumentException if the {@code statusReceiver} from an immutable
+ * {@link android.app.PendingIntent} when caller has a target SDK of API
+ * version {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} or above.
*
* @see android.app.admin.DevicePolicyManager
* @see #requestUserPreapproval
@@ -1764,6 +1770,9 @@
* @param statusReceiver Called when the state of the session changes. Intents
* sent to this receiver contain {@link #EXTRA_STATUS}. Refer to the
* individual status codes on how to handle them.
+ * @throws IllegalArgumentException if the {@code statusReceiver} from an immutable
+ * {@link android.app.PendingIntent} when caller has a target SDK of API
+ * {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} or above.
*
* @hide
*/
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index b8e0ad1..8f70c77 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -66,6 +66,7 @@
import android.app.admin.DevicePolicyEventLogger;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
+import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.content.ComponentName;
@@ -333,6 +334,15 @@
private static final int APP_METADATA_FILE_ACCESS_MODE = 0640;
+ /**
+ * Throws IllegalArgumentException if the {@link IntentSender} from an immutable
+ * {@link android.app.PendingIntent} when caller has a target SDK of API
+ * {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} or above.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ private static final long THROW_EXCEPTION_COMMIT_WITH_IMMUTABLE_PENDING_INTENT = 240618202L;
+
// TODO: enforce INSTALL_ALLOW_TEST
// TODO: enforce INSTALL_ALLOW_DOWNGRADE
@@ -1864,6 +1874,12 @@
@Override
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
assertNotChild("commit");
+ boolean throwsExceptionCommitImmutableCheck = CompatChanges.isChangeEnabled(
+ THROW_EXCEPTION_COMMIT_WITH_IMMUTABLE_PENDING_INTENT, Binder.getCallingUid());
+ if (throwsExceptionCommitImmutableCheck && statusReceiver.isImmutable()) {
+ throw new IllegalArgumentException(
+ "The commit() status receiver should come from a mutable PendingIntent");
+ }
if (!markAsSealed(statusReceiver, forTransfer)) {
return;