From 2501c2728bd2415329957ad4b42c70a871831b08 Mon Sep 17 00:00:00 2001 From: Soonil Nagarkar Date: Thu, 18 Feb 2021 16:35:30 -0800 Subject: [PATCH] Proposal: Reduce the number of IPCs in PendingIntent Several PendingIntent methods are named such that there is very little hint they involve any IPC, leading devs to overuse them, and thus adds substantial strain on the system. Caching some of the most used method results could remove 1000s of unnecessary IPCs. Bug: 180518680 Test: manual sanity check Change-Id: I7658251113ebb1e51280a4b8f3b49159d4f764f0 --- core/java/android/app/ActivityManager.aidl | 1 + core/java/android/app/ActivityManager.java | 67 +++++++++++++ core/java/android/app/IActivityManager.aidl | 9 +- core/java/android/app/PendingIntent.java | 96 +++++++------------ core/java/android/content/IntentSender.java | 50 ++++------ .../server/am/ActivityManagerService.java | 66 ++----------- 6 files changed, 137 insertions(+), 152 deletions(-) diff --git a/core/java/android/app/ActivityManager.aidl b/core/java/android/app/ActivityManager.aidl index 341393c0d9697..eb7cac0768221 100644 --- a/core/java/android/app/ActivityManager.aidl +++ b/core/java/android/app/ActivityManager.aidl @@ -17,6 +17,7 @@ package android.app; parcelable ActivityManager.MemoryInfo; +parcelable ActivityManager.PendingIntentInfo; parcelable ActivityManager.ProcessErrorStateInfo; parcelable ActivityManager.RecentTaskInfo; parcelable ActivityManager.TaskDescription; diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index e2426d1163197..6aaca419f1593 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -4681,4 +4681,71 @@ public class ActivityManager { throw e.rethrowFromSystemServer(); } } + + /** + * A subset of immutable pending intent information suitable for caching on the client side. + * + * @hide + */ + public static final class PendingIntentInfo implements Parcelable { + + private final String mCreatorPackage; + private final int mCreatorUid; + private final boolean mImmutable; + private final int mIntentSenderType; + + public PendingIntentInfo(String creatorPackage, int creatorUid, boolean immutable, + int intentSenderType) { + mCreatorPackage = creatorPackage; + mCreatorUid = creatorUid; + mImmutable = immutable; + mIntentSenderType = intentSenderType; + } + + public String getCreatorPackage() { + return mCreatorPackage; + } + + public int getCreatorUid() { + return mCreatorUid; + } + + public boolean isImmutable() { + return mImmutable; + } + + public int getIntentSenderType() { + return mIntentSenderType; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeString(mCreatorPackage); + parcel.writeInt(mCreatorUid); + parcel.writeBoolean(mImmutable); + parcel.writeInt(mIntentSenderType); + } + + public static final @NonNull Creator CREATOR = + new Creator() { + @Override + public PendingIntentInfo createFromParcel(Parcel in) { + return new PendingIntentInfo( + /* creatorPackage= */ in.readString(), + /* creatorUid= */ in.readInt(), + /* immutable= */ in.readBoolean(), + /* intentSenderType= */ in.readInt()); + } + + @Override + public PendingIntentInfo[] newArray(int size) { + return new PendingIntentInfo[size]; + } + }; + } } diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 4ad13e1932dd8..0bc5958d45398 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -17,6 +17,7 @@ package android.app; import android.app.ActivityManager; +import android.app.ActivityManager.PendingIntentInfo; import android.app.ActivityTaskManager; import android.app.ApplicationErrorReport; import android.app.ApplicationExitInfo; @@ -248,7 +249,7 @@ interface IActivityManager { in IBinder token, in String resultWho, int requestCode, in Intent[] intents, in String[] resolvedTypes, int flags, in Bundle options, int userId); void cancelIntentSender(in IIntentSender sender); - String getPackageForIntentSender(in IIntentSender sender); + ActivityManager.PendingIntentInfo getInfoForIntentSender(in IIntentSender sender); void registerIntentSenderCancelListener(in IIntentSender sender, in IResultReceiver receiver); void unregisterIntentSenderCancelListener(in IIntentSender sender, in IResultReceiver receiver); void enterSafeMode(); @@ -293,7 +294,6 @@ interface IActivityManager { int operationType); void backupAgentCreated(in String packageName, in IBinder agent, int userId); void unbindBackupAgent(in ApplicationInfo appInfo); - int getUidForIntentSender(in IIntentSender sender); int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll, boolean requireFull, in String name, in String callerPackage); void addPackageDependency(in String packageName); @@ -345,7 +345,6 @@ interface IActivityManager { @UnsupportedAppUsage void unregisterProcessObserver(in IProcessObserver observer); boolean isIntentSenderTargetedToPackage(in IIntentSender sender); - boolean isIntentSenderImmutable(in IIntentSender sender); @UnsupportedAppUsage void updatePersistentConfiguration(in Configuration values); void updatePersistentConfigurationWithAttribution(in Configuration values, @@ -375,8 +374,6 @@ interface IActivityManager { void unstableProviderDied(in IBinder connection); @UnsupportedAppUsage boolean isIntentSenderAnActivity(in IIntentSender sender); - boolean isIntentSenderAForegroundService(in IIntentSender sender); - boolean isIntentSenderABroadcast(in IIntentSender sender); /** @deprecated Use {@link startActivityAsUserWithFeature} instead */ @UnsupportedAppUsage(maxTargetSdk=29, publicAlternatives="Use {@code android.content.Context#createContextAsUser(android.os.UserHandle, int)} and {@link android.content.Context#startActivity(android.content.Intent)} instead") int startActivityAsUser(in IApplicationThread caller, in String callingPackage, @@ -710,6 +707,4 @@ interface IActivityManager { /** Called by PendingIntent.queryIntentComponents() */ List queryIntentComponentsForIntentSender(in IIntentSender sender, int matchFlags); - - boolean isIntentSenderAService(in IIntentSender sender); } diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index 671315f37b206..2f06bdce9087c 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -16,6 +16,11 @@ package android.app; +import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY; +import static android.app.ActivityManager.INTENT_SENDER_BROADCAST; +import static android.app.ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE; +import static android.app.ActivityManager.INTENT_SENDER_SERVICE; + import android.Manifest.permission; import android.annotation.IntDef; import android.annotation.NonNull; @@ -25,6 +30,7 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemApi.Client; import android.annotation.TestApi; +import android.app.ActivityManager.PendingIntentInfo; import android.compat.Compatibility; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; @@ -122,6 +128,9 @@ public final class PendingIntent implements Parcelable { private IBinder mWhitelistToken; private ArraySet mCancelListeners; + // cached pending intent information + private @Nullable PendingIntentInfo mCachedInfo; + /** * It is now required to specify either {@link #FLAG_IMMUTABLE} * or {@link #FLAG_MUTABLE} when creating a PendingIntent. @@ -463,7 +472,7 @@ public final class PendingIntent implements Parcelable { intent.prepareToLeaveProcess(context); IIntentSender target = ActivityManager.getService().getIntentSenderWithFeature( - ActivityManager.INTENT_SENDER_ACTIVITY, packageName, + INTENT_SENDER_ACTIVITY, packageName, context.getAttributionTag(), null, null, requestCode, new Intent[] { intent }, resolvedType != null ? new String[] { resolvedType } : null, flags, options, user.getIdentifier()); @@ -596,7 +605,7 @@ public final class PendingIntent implements Parcelable { try { IIntentSender target = ActivityManager.getService().getIntentSenderWithFeature( - ActivityManager.INTENT_SENDER_ACTIVITY, packageName, + INTENT_SENDER_ACTIVITY, packageName, context.getAttributionTag(), null, null, requestCode, intents, resolvedTypes, flags, options, user.getIdentifier()); return target != null ? new PendingIntent(target) : null; @@ -650,7 +659,7 @@ public final class PendingIntent implements Parcelable { intent.prepareToLeaveProcess(context); IIntentSender target = ActivityManager.getService().getIntentSenderWithFeature( - ActivityManager.INTENT_SENDER_BROADCAST, packageName, + INTENT_SENDER_BROADCAST, packageName, context.getAttributionTag(), null, null, requestCode, new Intent[] { intent }, resolvedType != null ? new String[] { resolvedType } : null, flags, null, userHandle.getIdentifier()); @@ -687,7 +696,7 @@ public final class PendingIntent implements Parcelable { public static PendingIntent getService(Context context, int requestCode, @NonNull Intent intent, @Flags int flags) { return buildServicePendingIntent(context, requestCode, intent, flags, - ActivityManager.INTENT_SENDER_SERVICE); + INTENT_SENDER_SERVICE); } /** @@ -717,7 +726,7 @@ public final class PendingIntent implements Parcelable { public static PendingIntent getForegroundService(Context context, int requestCode, @NonNull Intent intent, @Flags int flags) { return buildServicePendingIntent(context, requestCode, intent, flags, - ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE); + INTENT_SENDER_FOREGROUND_SERVICE); } private static PendingIntent buildServicePendingIntent(Context context, int requestCode, @@ -1001,12 +1010,7 @@ public final class PendingIntent implements Parcelable { */ @Deprecated public String getTargetPackage() { - try { - return ActivityManager.getService() - .getPackageForIntentSender(mTarget); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getCreatorPackage(); } /** @@ -1029,12 +1033,7 @@ public final class PendingIntent implements Parcelable { */ @Nullable public String getCreatorPackage() { - try { - return ActivityManager.getService() - .getPackageForIntentSender(mTarget); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getCachedInfo().getCreatorPackage(); } /** @@ -1056,12 +1055,7 @@ public final class PendingIntent implements Parcelable { * none associated with it. */ public int getCreatorUid() { - try { - return ActivityManager.getService() - .getUidForIntentSender(mTarget); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getCachedInfo().getCreatorUid(); } /** @@ -1154,13 +1148,8 @@ public final class PendingIntent implements Parcelable { */ @Nullable public UserHandle getCreatorUserHandle() { - try { - int uid = ActivityManager.getService() - .getUidForIntentSender(mTarget); - return uid > 0 ? new UserHandle(UserHandle.getUserId(uid)) : null; - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + int uid = getCachedInfo().getCreatorUid(); + return uid > 0 ? new UserHandle(UserHandle.getUserId(uid)) : null; } /** @@ -1180,12 +1169,7 @@ public final class PendingIntent implements Parcelable { * Check if this PendingIntent is marked with {@link #FLAG_IMMUTABLE}. */ public boolean isImmutable() { - try { - return ActivityManager.getService() - .isIntentSenderImmutable(mTarget); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getCachedInfo().isImmutable(); } /** @@ -1193,48 +1177,28 @@ public final class PendingIntent implements Parcelable { * {@link #getActivity} or {@link #getActivities}. */ public boolean isActivity() { - try { - return ActivityManager.getService() - .isIntentSenderAnActivity(mTarget); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getCachedInfo().getIntentSenderType() == INTENT_SENDER_ACTIVITY; } /** * @return TRUE if this {@link PendingIntent} was created with {@link #getForegroundService}. */ public boolean isForegroundService() { - try { - return ActivityManager.getService() - .isIntentSenderAForegroundService(mTarget); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getCachedInfo().getIntentSenderType() == INTENT_SENDER_FOREGROUND_SERVICE; } /** * @return TRUE if this {@link PendingIntent} was created with {@link #getService}. */ public boolean isService() { - try { - return ActivityManager.getService() - .isIntentSenderAService(mTarget); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getCachedInfo().getIntentSenderType() == INTENT_SENDER_SERVICE; } /** * @return TRUE if this {@link PendingIntent} was created with {@link #getBroadcast}. */ public boolean isBroadcast() { - try { - return ActivityManager.getService() - .isIntentSenderABroadcast(mTarget); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getCachedInfo().getIntentSenderType() == INTENT_SENDER_BROADCAST; } /** @@ -1433,4 +1397,16 @@ public final class PendingIntent implements Parcelable { */ void onCancelled(PendingIntent intent); } + + private PendingIntentInfo getCachedInfo() { + if (mCachedInfo == null) { + try { + mCachedInfo = ActivityManager.getService().getInfoForIntentSender(mTarget); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + return mCachedInfo; + } } diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java index 858d1e4987833..b1252fd0b21f1 100644 --- a/core/java/android/content/IntentSender.java +++ b/core/java/android/content/IntentSender.java @@ -18,6 +18,7 @@ package android.content; import android.annotation.Nullable; import android.app.ActivityManager; +import android.app.ActivityManager.PendingIntentInfo; import android.compat.annotation.UnsupportedAppUsage; import android.os.Bundle; import android.os.Handler; @@ -60,6 +61,9 @@ public class IntentSender implements Parcelable { private final IIntentSender mTarget; IBinder mWhitelistToken; + // cached pending intent information + private @Nullable PendingIntentInfo mCachedInfo; + /** * Exception thrown when trying to send through a PendingIntent that * has been canceled or is otherwise no longer able to execute the request. @@ -209,13 +213,7 @@ public class IntentSender implements Parcelable { */ @Deprecated public String getTargetPackage() { - try { - return ActivityManager.getService() - .getPackageForIntentSender(mTarget); - } catch (RemoteException e) { - // Should never happen. - return null; - } + return getCreatorPackage(); } /** @@ -228,13 +226,7 @@ public class IntentSender implements Parcelable { * none associated with it. */ public String getCreatorPackage() { - try { - return ActivityManager.getService() - .getPackageForIntentSender(mTarget); - } catch (RemoteException e) { - // Should never happen. - return null; - } + return getCachedInfo().getCreatorPackage(); } /** @@ -247,13 +239,7 @@ public class IntentSender implements Parcelable { * none associated with it. */ public int getCreatorUid() { - try { - return ActivityManager.getService() - .getUidForIntentSender(mTarget); - } catch (RemoteException e) { - // Should never happen. - return -1; - } + return getCachedInfo().getCreatorUid(); } /** @@ -268,14 +254,8 @@ public class IntentSender implements Parcelable { * none associated with it. */ public UserHandle getCreatorUserHandle() { - try { - int uid = ActivityManager.getService() - .getUidForIntentSender(mTarget); - return uid > 0 ? new UserHandle(UserHandle.getUserId(uid)) : null; - } catch (RemoteException e) { - // Should never happen. - return null; - } + int uid = getCachedInfo().getCreatorUid(); + return uid > 0 ? new UserHandle(UserHandle.getUserId(uid)) : null; } /** @@ -384,4 +364,16 @@ public class IntentSender implements Parcelable { public IntentSender(IBinder target) { mTarget = IIntentSender.Stub.asInterface(target); } + + private PendingIntentInfo getCachedInfo() { + if (mCachedInfo == null) { + try { + mCachedInfo = ActivityManager.getService().getInfoForIntentSender(mTarget); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + return mCachedInfo; + } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 0b1c1154ba75d..bc47f79ff19e6 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -141,6 +141,7 @@ import android.annotation.UserIdInt; import android.app.Activity; import android.app.ActivityClient; import android.app.ActivityManager; +import android.app.ActivityManager.PendingIntentInfo; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManagerInternal; import android.app.ActivityTaskManager.RootTaskInfo; @@ -4856,19 +4857,6 @@ public class ActivityManagerService extends IActivityManager.Stub mPendingIntentController.cancelIntentSender(sender); } - @Override - public String getPackageForIntentSender(IIntentSender pendingResult) { - if (!(pendingResult instanceof PendingIntentRecord)) { - return null; - } - try { - PendingIntentRecord res = (PendingIntentRecord)pendingResult; - return res.key.packageName; - } catch (ClassCastException e) { - } - return null; - } - @Override public void registerIntentSenderCancelListener(IIntentSender sender, IResultReceiver receiver) { mPendingIntentController.registerIntentSenderCancelListener(sender, receiver); @@ -4881,15 +4869,17 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public int getUidForIntentSender(IIntentSender sender) { + public PendingIntentInfo getInfoForIntentSender(IIntentSender sender) { if (sender instanceof PendingIntentRecord) { - try { - PendingIntentRecord res = (PendingIntentRecord)sender; - return res.uid; - } catch (ClassCastException e) { - } + PendingIntentRecord res = (PendingIntentRecord) sender; + return new PendingIntentInfo( + res.key.packageName, + res.uid, + (res.key.flags & PendingIntent.FLAG_IMMUTABLE) != 0, + res.key.type); + } else { + throw new IllegalArgumentException(); } - return -1; } @Override @@ -4914,15 +4904,6 @@ public class ActivityManagerService extends IActivityManager.Stub return false; } - @Override - public boolean isIntentSenderImmutable(IIntentSender pendingResult) { - if (pendingResult instanceof PendingIntentRecord) { - final PendingIntentRecord res = (PendingIntentRecord) pendingResult; - return (res.key.flags & PendingIntent.FLAG_IMMUTABLE) != 0; - } - return false; - } - @Override public boolean isIntentSenderAnActivity(IIntentSender pendingResult) { if (!(pendingResult instanceof PendingIntentRecord)) { @@ -4939,33 +4920,6 @@ public class ActivityManagerService extends IActivityManager.Stub return false; } - @Override - public boolean isIntentSenderAForegroundService(IIntentSender pendingResult) { - if (pendingResult instanceof PendingIntentRecord) { - final PendingIntentRecord res = (PendingIntentRecord) pendingResult; - return res.key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE; - } - return false; - } - - @Override - public boolean isIntentSenderAService(IIntentSender pendingResult) { - if (pendingResult instanceof PendingIntentRecord) { - final PendingIntentRecord res = (PendingIntentRecord) pendingResult; - return res.key.type == ActivityManager.INTENT_SENDER_SERVICE; - } - return false; - } - - @Override - public boolean isIntentSenderABroadcast(IIntentSender pendingResult) { - if (pendingResult instanceof PendingIntentRecord) { - final PendingIntentRecord res = (PendingIntentRecord) pendingResult; - return res.key.type == ActivityManager.INTENT_SENDER_BROADCAST; - } - return false; - } - @Override public Intent getIntentForIntentSender(IIntentSender pendingResult) { enforceCallingPermission(Manifest.permission.GET_INTENT_SENDER_INTENT,