diff options
4 files changed, 74 insertions, 21 deletions
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 080352408a67..605340061994 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -561,6 +561,14 @@ public abstract class ActivityManagerInternal { public abstract Intent getIntentForIntentSender(IIntentSender sender); /** + * Effectively PendingIntent.getActivityForUser(), but the PendingIntent is + * owned by the given uid rather than by the caller (i.e. the system). + */ + public abstract PendingIntent getPendingIntentActivityAsApp( + int requestCode, @NonNull Intent intent, int flags, Bundle options, + String ownerPkgName, int ownerUid); + + /** * @return mBootTimeTempAllowlistDuration of ActivityManagerConstants. */ public abstract long getBootTimeTempAllowListDuration(); diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index ca0868310dee..0136a35e3975 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -358,12 +358,6 @@ public final class PendingIntent implements Parcelable { private static void checkFlags(int flags, String packageName) { final boolean flagImmutableSet = (flags & PendingIntent.FLAG_IMMUTABLE) != 0; final boolean flagMutableSet = (flags & PendingIntent.FLAG_MUTABLE) != 0; - String msg = packageName + ": Targeting S+ (version " + Build.VERSION_CODES.S - + " and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE" - + " be specified when creating a PendingIntent.\nStrongly consider" - + " using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality" - + " depends on the PendingIntent being mutable, e.g. if it needs to" - + " be used with inline replies or bubbles."; if (flagImmutableSet && flagMutableSet) { throw new IllegalArgumentException( @@ -372,6 +366,12 @@ public final class PendingIntent implements Parcelable { if (Compatibility.isChangeEnabled(PENDING_INTENT_EXPLICIT_MUTABILITY_REQUIRED) && !flagImmutableSet && !flagMutableSet) { + String msg = packageName + ": Targeting S+ (version " + Build.VERSION_CODES.S + + " and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE" + + " be specified when creating a PendingIntent.\nStrongly consider" + + " using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality" + + " depends on the PendingIntent being mutable, e.g. if it needs to" + + " be used with inline replies or bubbles."; throw new IllegalArgumentException(msg); } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 4b640a61f1dd..ded66d5dc135 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -27,6 +27,7 @@ import static android.app.ActivityManager.INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS; import static android.app.ActivityManager.INSTR_FLAG_DISABLE_ISOLATED_STORAGE; import static android.app.ActivityManager.INSTR_FLAG_DISABLE_TEST_API_CHECKS; import static android.app.ActivityManager.INSTR_FLAG_NO_RESTART; +import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY; import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; import static android.app.ActivityManager.PROCESS_STATE_TOP; @@ -4814,10 +4815,27 @@ public class ActivityManagerService extends IActivityManager.Stub public IIntentSender getIntentSenderWithFeature(int type, String packageName, String featureId, IBinder token, String resultWho, int requestCode, Intent[] intents, String[] resolvedTypes, int flags, Bundle bOptions, int userId) { + enforceNotIsolatedCaller("getIntentSender"); + + return getIntentSenderWithFeatureAsApp(type, packageName, featureId, token, resultWho, + requestCode, intents, resolvedTypes, flags, bOptions, userId, + Binder.getCallingUid()); + } + + /** + * System-internal callers can invoke this with owningUid being the app's own identity + * rather than the public API's behavior of always assigning ownership to the actual + * caller identity. This will create an IntentSender as though the package/userid/uid app + * were the caller, so that the ultimate PendingIntent is triggered with only the app's + * capabilities and not the system's. Used in cases like notification groups where + * the OS must synthesize a PendingIntent on an app's behalf. + */ + public IIntentSender getIntentSenderWithFeatureAsApp(int type, String packageName, + String featureId, IBinder token, String resultWho, int requestCode, Intent[] intents, + String[] resolvedTypes, int flags, Bundle bOptions, int userId, int owningUid) { // NOTE: The service lock isn't held in this method because nothing in the method requires // the service lock to be held. - enforceNotIsolatedCaller("getIntentSender"); // Refuse possible leaked file descriptors if (intents != null) { if (intents.length < 1) { @@ -4848,9 +4866,8 @@ public class ActivityManagerService extends IActivityManager.Stub } } - int callingUid = Binder.getCallingUid(); int origUserId = userId; - userId = mUserController.handleIncomingUser(Binder.getCallingPid(), callingUid, userId, + userId = mUserController.handleIncomingUser(Binder.getCallingPid(), owningUid, userId, type == ActivityManager.INTENT_SENDER_BROADCAST, ALLOW_NON_FULL, "getIntentSender", null); if (origUserId == UserHandle.USER_CURRENT) { @@ -4860,27 +4877,27 @@ public class ActivityManagerService extends IActivityManager.Stub userId = UserHandle.USER_CURRENT; } try { - if (callingUid != 0 && callingUid != SYSTEM_UID) { + if (owningUid != 0 && owningUid != SYSTEM_UID) { final int uid = AppGlobals.getPackageManager().getPackageUid(packageName, - MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(callingUid)); - if (!UserHandle.isSameApp(callingUid, uid)) { + MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(owningUid)); + if (!UserHandle.isSameApp(owningUid, uid)) { String msg = "Permission Denial: getIntentSender() from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid() - + ", (need uid=" + uid + ")" - + " is not allowed to send as package " + packageName; + + Binder.getCallingPid() + + ", uid=" + owningUid + + ", (need uid=" + uid + ")" + + " is not allowed to send as package " + packageName; Slog.w(TAG, msg); throw new SecurityException(msg); } } if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) { - return mAtmInternal.getIntentSender(type, packageName, featureId, callingUid, + return mAtmInternal.getIntentSender(type, packageName, featureId, owningUid, userId, token, resultWho, requestCode, intents, resolvedTypes, flags, bOptions); } return mPendingIntentController.getIntentSender(type, packageName, featureId, - callingUid, userId, token, resultWho, requestCode, intents, resolvedTypes, + owningUid, userId, token, resultWho, requestCode, intents, resolvedTypes, flags, bOptions); } catch (RemoteException e) { throw new SecurityException(e); @@ -16064,6 +16081,32 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override + public PendingIntent getPendingIntentActivityAsApp( + int requestCode, @NonNull Intent intent, int flags, Bundle options, + String ownerPkg, int ownerUid) { + // system callers must explicitly set mutability state + final boolean flagImmutableSet = (flags & PendingIntent.FLAG_IMMUTABLE) != 0; + final boolean flagMutableSet = (flags & PendingIntent.FLAG_MUTABLE) != 0; + if (flagImmutableSet == flagMutableSet) { + throw new IllegalArgumentException( + "Must set exactly one of FLAG_IMMUTABLE or FLAG_MUTABLE"); + } + + final Context context = ActivityManagerService.this.mContext; + String resolvedType = intent.resolveTypeIfNeeded(context.getContentResolver()); + intent.migrateExtraStreamToClipData(context); + intent.prepareToLeaveProcess(context); + IIntentSender target = + ActivityManagerService.this.getIntentSenderWithFeatureAsApp( + INTENT_SENDER_ACTIVITY, ownerPkg, + context.getAttributionTag(), null, null, requestCode, + new Intent[] { intent }, + resolvedType != null ? new String[] { resolvedType } : null, + flags, options, UserHandle.getUserId(ownerUid), ownerUid); + return target != null ? new PendingIntent(target) : null; + } + + @Override public long getBootTimeTempAllowListDuration() { // Do not lock ActivityManagerService.this here, this API is called by // PackageManagerService. diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 52a5dc1e8982..ef6f11ae7dbf 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -5680,9 +5680,11 @@ public class NotificationManagerService extends SystemService { summaryNotification.extras.putAll(extras); Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg); if (appIntent != null) { - summaryNotification.contentIntent = PendingIntent.getActivityAsUser( - getContext(), 0, appIntent, PendingIntent.FLAG_IMMUTABLE, null, - UserHandle.of(userId)); + final ActivityManagerInternal ami = LocalServices + .getService(ActivityManagerInternal.class); + summaryNotification.contentIntent = ami.getPendingIntentActivityAsApp( + 0, appIntent, PendingIntent.FLAG_IMMUTABLE, null, + pkg, appInfo.uid); } final StatusBarNotification summarySbn = new StatusBarNotification(adjustedSbn.getPackageName(), |