Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2501c272 authored by Soonil Nagarkar's avatar Soonil Nagarkar
Browse files

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
parent 0aa410fe
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.app;

parcelable ActivityManager.MemoryInfo;
parcelable ActivityManager.PendingIntentInfo;
parcelable ActivityManager.ProcessErrorStateInfo;
parcelable ActivityManager.RecentTaskInfo;
parcelable ActivityManager.TaskDescription;
+67 −0
Original line number Diff line number Diff line
@@ -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<PendingIntentInfo> CREATOR =
                new Creator<PendingIntentInfo>() {
                    @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];
                    }
                };
    }
}
+2 −7
Original line number Diff line number Diff line
@@ -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<ResolveInfo> queryIntentComponentsForIntentSender(in IIntentSender sender, int matchFlags);

    boolean isIntentSenderAService(in IIntentSender sender);
}
+36 −60
Original line number Diff line number Diff line
@@ -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<CancelListener> 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);
        int uid = getCachedInfo().getCreatorUid();
        return uid > 0 ? new UserHandle(UserHandle.getUserId(uid)) : null;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
@@ -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;
    }
}
+21 −29
Original line number Diff line number Diff line
@@ -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);
        int uid = getCachedInfo().getCreatorUid();
        return uid > 0 ? new UserHandle(UserHandle.getUserId(uid)) : null;
        } catch (RemoteException e) {
            // Should never happen.
            return 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;
    }
}
Loading