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

Commit 04cded96 authored by Rhed Jao's avatar Rhed Jao
Browse files

Do not split the suspended packages intent into multiple ones

Previously, we splitted the intent into multiple ones to prevent
from the disclosure of information of packages. This approach impacts
system health. A lots of intents were sent when hundreds of packages
information stored in the intent extras.

This cl stopped splitting of intent. Instead, it passes a filter to the
am#broadcastIntent api for intent broadcast to filter the intent extras
by using the rules of package visibility when passing the intent to the
receiver.

Bug: 238448280
Test: atest AppEnumerationTests
Test: atest SuspendPackagesTest
Test: atest SuspendPackageHelperTest
Change-Id: I6c4051168b855155b49b0bd6b19e0de7dc826df7
parent 200d61e3
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiFunction;

/**
 * Activity manager local system service interface.
@@ -623,6 +624,11 @@ public abstract class ActivityManagerInternal {
     * broadcast my be sent to; any app Ids < {@link android.os.Process#FIRST_APPLICATION_UID} are
     * automatically allowlisted.
     *
     * @param filterExtrasForReceiver A function to filter intent extras for the given receiver by
     * using the rules of package visibility. Returns extras with legitimate package info that the
     * receiver is able to access, or {@code null} if none of the packages is visible to the
     * receiver.
     *
     * @see com.android.server.am.ActivityManagerService#broadcastIntentWithFeature(
     *      IApplicationThread, String, Intent, String, IIntentReceiver, int, String, Bundle,
     *      String[], int, Bundle, boolean, boolean, int)
@@ -630,7 +636,9 @@ public abstract class ActivityManagerInternal {
    public abstract int broadcastIntent(Intent intent,
            IIntentReceiver resultTo,
            String[] requiredPermissions, boolean serialized,
            int userId, int[] appIdAllowList, @Nullable Bundle bOptions);
            int userId, int[] appIdAllowList,
            @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver,
            @Nullable Bundle bOptions);

    /**
     * Add uid to the ActivityManagerService PendingStartActivityUids list.
+18 −9
Original line number Diff line number Diff line
@@ -459,6 +459,7 @@ import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiFunction;
public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback, ActivityManagerGlobalLock {
@@ -4304,7 +4305,8 @@ public class ActivityManagerService extends IActivityManager.Stub
                null /* excludedPackages */, OP_NONE, null /* bOptions */, false /* ordered */,
                false /* sticky */, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
                Binder.getCallingPid(), userId, false /* allowBackgroundActivityStarts */,
                null /* backgroundActivityStartsToken */, broadcastAllowList);
                null /* backgroundActivityStartsToken */,
                broadcastAllowList, null /* filterExtrasForReceiver */);
    }
    private void cleanupDisabledPackageComponentsLocked(
@@ -13357,7 +13359,8 @@ public class ActivityManagerService extends IActivityManager.Stub
                    BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                            null, null, -1, -1, false, null, null, null, null, OP_NONE, null,
                            receivers, null, 0, null, null, false, true, true, -1, false, null,
                            false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */);
                            false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */,
                            null /* filterExtrasForReceiver */);
                    queue.enqueueParallelBroadcastLocked(r);
                    queue.scheduleBroadcastsLocked();
                }
@@ -13620,7 +13623,8 @@ public class ActivityManagerService extends IActivityManager.Stub
                excludedPermissions, excludedPackages, appOp, bOptions, ordered, sticky, callingPid,
                callingUid, realCallingUid, realCallingPid, userId,
                false /* allowBackgroundActivityStarts */,
                null /* tokenNeededForBackgroundActivityStarts */, null /* broadcastAllowList */);
                null /* tokenNeededForBackgroundActivityStarts */,
                null /* broadcastAllowList */, null /* filterExtrasForReceiver */);
    }
    @GuardedBy("this")
@@ -13633,7 +13637,8 @@ public class ActivityManagerService extends IActivityManager.Stub
            int realCallingUid, int realCallingPid, int userId,
            boolean allowBackgroundActivityStarts,
            @Nullable IBinder backgroundActivityStartsToken,
            @Nullable int[] broadcastAllowList) {
            @Nullable int[] broadcastAllowList,
            @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) {
        intent = new Intent(intent);
        final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);
@@ -14233,7 +14238,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                    requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
                    registeredReceivers, resultTo, resultCode, resultData, resultExtras, ordered,
                    sticky, false, userId, allowBackgroundActivityStarts,
                    backgroundActivityStartsToken, timeoutExempt);
                    backgroundActivityStartsToken, timeoutExempt, filterExtrasForReceiver);
            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
            final boolean replaced = replacePending
                    && (queue.replaceParallelBroadcastLocked(r) != null);
@@ -14331,7 +14336,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                    requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
                    receivers, resultTo, resultCode, resultData, resultExtras,
                    ordered, sticky, false, userId, allowBackgroundActivityStarts,
                    backgroundActivityStartsToken, timeoutExempt);
                    backgroundActivityStartsToken, timeoutExempt, filterExtrasForReceiver);
            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);
@@ -14523,7 +14528,8 @@ public class ActivityManagerService extends IActivityManager.Stub
                        resultTo, resultCode, resultData, resultExtras, requiredPermissions, null,
                        null, OP_NONE, bOptions, serialized, sticky, -1, uid, realCallingUid,
                        realCallingPid, userId, allowBackgroundActivityStarts,
                        backgroundActivityStartsToken, broadcastAllowList);
                        backgroundActivityStartsToken, broadcastAllowList,
                        null /* filterExtrasForReceiver */);
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
@@ -17058,7 +17064,9 @@ public class ActivityManagerService extends IActivityManager.Stub
        public int broadcastIntent(Intent intent,
                IIntentReceiver resultTo,
                String[] requiredPermissions,
                boolean serialized, int userId, int[] appIdAllowList, @Nullable Bundle bOptions) {
                boolean serialized, int userId, int[] appIdAllowList,
                @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver,
                @Nullable Bundle bOptions) {
            synchronized (ActivityManagerService.this) {
                intent = verifyBroadcastLocked(intent);
@@ -17074,7 +17082,8 @@ public class ActivityManagerService extends IActivityManager.Stub
                            AppOpsManager.OP_NONE, bOptions /*options*/, serialized,
                            false /*sticky*/, callingPid, callingUid, callingUid, callingPid,
                            userId, false /*allowBackgroundStarts*/,
                            null /*tokenNeededForBackgroundActivityStarts*/, appIdAllowList);
                            null /*tokenNeededForBackgroundActivityStarts*/,
                            appIdAllowList, filterExtrasForReceiver);
                } finally {
                    Binder.restoreCallingIdentity(origId);
                }
+50 −3
Original line number Diff line number Diff line
@@ -361,8 +361,8 @@ public final class BroadcastQueue {
                    + ": " + r);
            mService.notifyPackageUse(r.intent.getComponent().getPackageName(),
                                      PackageManager.NOTIFY_PACKAGE_USE_BROADCAST_RECEIVER);
            thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
                    null /* compatInfo (unused but need to keep method signature) */,
            thread.scheduleReceiver(prepareReceiverIntent(r.intent, r.curFilteredExtras),
                    r.curReceiver, null /* compatInfo (unused but need to keep method signature) */,
                    r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
                    app.mState.getReportedProcState());
            if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
@@ -590,6 +590,7 @@ public final class BroadcastQueue {
        r.curFilter = null;
        r.curReceiver = null;
        r.curApp = null;
        r.curFilteredExtras = null;
        mPendingBroadcast = null;

        r.resultCode = resultCode;
@@ -941,6 +942,24 @@ public final class BroadcastQueue {
            skip = true;
        }

        // Filter packages in the intent extras, skipping delivery if none of the packages is
        // visible to the receiver.
        Bundle filteredExtras = null;
        if (!skip && r.filterExtrasForReceiver != null) {
            final Bundle extras = r.intent.getExtras();
            if (extras != null) {
                filteredExtras = r.filterExtrasForReceiver.apply(filter.receiverList.uid, extras);
                if (filteredExtras == null) {
                    if (DEBUG_BROADCAST) {
                        Slog.v(TAG, "Skipping delivery to "
                                + filter.receiverList.app
                                + " : receiver is filtered by the package visibility");
                    }
                    skip = true;
                }
            }
        }

        if (skip) {
            r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;
            return;
@@ -997,7 +1016,7 @@ public final class BroadcastQueue {
                maybeScheduleTempAllowlistLocked(filter.owningUid, r, r.options);
                maybeReportBroadcastDispatchedEventLocked(r, filter.owningUid);
                performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                        new Intent(r.intent), r.resultCode, r.resultData,
                        prepareReceiverIntent(r.intent, filteredExtras), r.resultCode, r.resultData,
                        r.resultExtras, r.ordered, r.initialSticky, r.userId,
                        filter.receiverList.uid, r.callingUid,
                        r.dispatchTime - r.enqueueTime,
@@ -1164,6 +1183,15 @@ public final class BroadcastQueue {
                + ", uid=" + r.callingUid + ") to " + component.flattenToShortString();
    }

    private static Intent prepareReceiverIntent(@NonNull Intent originalIntent,
            @Nullable Bundle filteredExtras) {
        final Intent intent = new Intent(originalIntent);
        if (filteredExtras != null) {
            intent.replaceExtras(filteredExtras);
        }
        return intent;
    }

    final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
        BroadcastRecord r;

@@ -1834,6 +1862,24 @@ public final class BroadcastQueue {
            }
        }

        // Filter packages in the intent extras, skipping delivery if none of the packages is
        // visible to the receiver.
        Bundle filteredExtras = null;
        if (!skip && r.filterExtrasForReceiver != null) {
            final Bundle extras = r.intent.getExtras();
            if (extras != null) {
                filteredExtras = r.filterExtrasForReceiver.apply(receiverUid, extras);
                if (filteredExtras == null) {
                    if (DEBUG_BROADCAST) {
                        Slog.v(TAG, "Skipping delivery to "
                                + info.activityInfo.packageName + " / " + receiverUid
                                + " : receiver is filtered by the package visibility");
                    }
                    skip = true;
                }
            }
        }

        if (skip) {
            if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                    "Skipping delivery of ordered [" + mQueueName + "] "
@@ -1852,6 +1898,7 @@ public final class BroadcastQueue {
        r.state = BroadcastRecord.APP_RECEIVE;
        r.curComponent = component;
        r.curReceiver = info.activityInfo;
        r.curFilteredExtras = filteredExtras;
        if (DEBUG_MU && r.callingUid > UserHandle.PER_USER_RANGE) {
            Slog.v(TAG_MU, "Updated broadcast record activity info for secondary user, "
                    + info.activityInfo + ", callingUid = " + r.callingUid + ", uid = "
+17 −3
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiFunction;

/**
 * An active intent broadcast.
@@ -114,6 +115,11 @@ final class BroadcastRecord extends Binder {
    @Nullable
    final IBinder mBackgroundActivityStartsToken;

    // Filter the intent extras by using the rules of the package visibility before broadcasting
    // the intent to the receiver.
    @Nullable
    final BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver;

    static final int IDLE = 0;
    static final int APP_RECEIVE = 1;
    static final int CALL_IN_RECEIVE = 2;
@@ -134,6 +140,7 @@ final class BroadcastRecord extends Binder {
    ProcessRecord curApp;       // hosting application of current receiver.
    ComponentName curComponent; // the receiver class that is currently running.
    ActivityInfo curReceiver;   // info about the receiver that is currently running.
    Bundle curFilteredExtras;   // the bundle that has been filtered by the package visibility rules

    boolean mIsReceiverAppRunning; // Was the receiver's app already running.

@@ -227,6 +234,9 @@ final class BroadcastRecord extends Binder {
                        pw.println(curReceiver.applicationInfo.sourceDir);
            }
        }
        if (curFilteredExtras != null) {
            pw.print(" filtered extras: "); pw.println(curFilteredExtras);
        }
        if (state != IDLE) {
            String stateStr = " (?)";
            switch (state) {
@@ -273,7 +283,8 @@ final class BroadcastRecord extends Binder {
            BroadcastOptions _options, List _receivers, IIntentReceiver _resultTo, int _resultCode,
            String _resultData, Bundle _resultExtras, boolean _serialized, boolean _sticky,
            boolean _initialSticky, int _userId, boolean allowBackgroundActivityStarts,
            @Nullable IBinder backgroundActivityStartsToken, boolean timeoutExempt) {
            @Nullable IBinder backgroundActivityStartsToken, boolean timeoutExempt,
            @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) {
        if (_intent == null) {
            throw new NullPointerException("Can't construct with a null intent");
        }
@@ -309,6 +320,7 @@ final class BroadcastRecord extends Binder {
        mBackgroundActivityStartsToken = backgroundActivityStartsToken;
        this.timeoutExempt = timeoutExempt;
        alarm = options != null && options.isAlarmBroadcast();
        this.filterExtrasForReceiver = filterExtrasForReceiver;
    }

    /**
@@ -362,6 +374,7 @@ final class BroadcastRecord extends Binder {
        mBackgroundActivityStartsToken = from.mBackgroundActivityStartsToken;
        timeoutExempt = from.timeoutExempt;
        alarm = from.alarm;
        filterExtrasForReceiver = from.filterExtrasForReceiver;
    }

    /**
@@ -397,7 +410,7 @@ final class BroadcastRecord extends Binder {
                requiredPermissions, excludedPermissions, excludedPackages, appOp, options,
                splitReceivers, resultTo, resultCode, resultData, resultExtras, ordered, sticky,
                initialSticky, userId, allowBackgroundActivityStarts,
                mBackgroundActivityStartsToken, timeoutExempt);
                mBackgroundActivityStartsToken, timeoutExempt, filterExtrasForReceiver);
        split.enqueueTime = this.enqueueTime;
        split.enqueueRealTime = this.enqueueRealTime;
        split.enqueueClockTime = this.enqueueClockTime;
@@ -476,7 +489,8 @@ final class BroadcastRecord extends Binder {
                    requiredPermissions, excludedPermissions, excludedPackages, appOp, options,
                    uid2receiverList.valueAt(i), null /* _resultTo */,
                    resultCode, resultData, resultExtras, ordered, sticky, initialSticky, userId,
                    allowBackgroundActivityStarts, mBackgroundActivityStartsToken, timeoutExempt);
                    allowBackgroundActivityStarts, mBackgroundActivityStartsToken, timeoutExempt,
                    filterExtrasForReceiver);
            br.enqueueTime = this.enqueueTime;
            br.enqueueRealTime = this.enqueueRealTime;
            br.enqueueClockTime = this.enqueueClockTime;
+76 −7
Original line number Diff line number Diff line
@@ -45,7 +45,9 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.IntArray;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;

@@ -54,6 +56,7 @@ import com.android.internal.util.ArrayUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.BiFunction;

/**
 * Helper class to send broadcasts for various situations.
@@ -80,6 +83,7 @@ public final class BroadcastHelper {
            final int flags, final String targetPkg, final IIntentReceiver finishedReceiver,
            final int[] userIds, int[] instantUserIds,
            @Nullable SparseArray<int[]> broadcastAllowList,
            @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver,
            @Nullable Bundle bOptions) {
        try {
            final IActivityManager am = ActivityManager.getService();
@@ -93,11 +97,13 @@ public final class BroadcastHelper {

            if (ArrayUtils.isEmpty(instantUserIds)) {
                doSendBroadcast(action, pkg, extras, flags, targetPkg, finishedReceiver,
                        resolvedUserIds, false /* isInstantApp */, broadcastAllowList, bOptions);
                        resolvedUserIds, false /* isInstantApp */, broadcastAllowList,
                        filterExtrasForReceiver, bOptions);
            } else {
                // send restricted broadcasts for instant apps
                doSendBroadcast(action, pkg, extras, flags, targetPkg, finishedReceiver,
                        instantUserIds, true /* isInstantApp */, null, bOptions);
                        instantUserIds, true /* isInstantApp */, null,
                        null /* filterExtrasForReceiver */, bOptions);
            }
        } catch (RemoteException ex) {
        }
@@ -113,6 +119,7 @@ public final class BroadcastHelper {
    public void doSendBroadcast(String action, String pkg, Bundle extras,
            int flags, String targetPkg, IIntentReceiver finishedReceiver,
            int[] userIds, boolean isInstantApp, @Nullable SparseArray<int[]> broadcastAllowList,
            @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver,
            @Nullable Bundle bOptions) {
        for (int userId : userIds) {
            final Intent intent = new Intent(action,
@@ -148,7 +155,7 @@ public final class BroadcastHelper {
                    intent, finishedReceiver, requiredPermissions,
                    finishedReceiver != null, userId,
                    broadcastAllowList == null ? null : broadcastAllowList.get(userId),
                    bOptions);
                    filterExtrasForReceiver, bOptions);
        }
    }

@@ -182,7 +189,8 @@ public final class BroadcastHelper {
                                    : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
                    sendPackageBroadcast(action, null /* pkg */, extras, 0 /* flags */,
                            null /* targetPkg */, null /* finishedReceiver */, new int[]{userId},
                            null /* instantUserIds */, allowList, null /* bOptions */);
                            null /* instantUserIds */, allowList,
                            null /* filterExtrasForReceiver */, null /* bOptions */);
                }
            }
        } catch (RemoteException ex) {
@@ -266,7 +274,8 @@ public final class BroadcastHelper {
        final int flags = !componentNames.contains(packageName)
                ? Intent.FLAG_RECEIVER_REGISTERED_ONLY : 0;
        sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, flags, null, null,
                userIds, instantUserIds, broadcastAllowList, null);
                userIds, instantUserIds, broadcastAllowList, null /* filterExtrasForReceiver */,
                null /* bOptions */);
    }

    public static void sendDeviceCustomizationReadyBroadcast() {
@@ -334,13 +343,14 @@ public final class BroadcastHelper {

        sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
                packageName, extras, 0, null, null, userIds, instantUserIds,
                broadcastAllowlist, null);
                broadcastAllowlist, null /* filterExtrasForReceiver */, null);
    }

    public void sendFirstLaunchBroadcast(String pkgName, String installerPkg,
            int[] userIds, int[] instantUserIds) {
        sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, pkgName, null, 0,
                installerPkg, null, userIds, instantUserIds, null /* broadcastAllowList */, null);
                installerPkg, null, userIds, instantUserIds, null /* broadcastAllowList */,
                null /* filterExtrasForReceiver */, null);
    }

    /**
@@ -383,4 +393,63 @@ public final class BroadcastHelper {

        return lists;
    }

    /**
     * Filter package names for the intent extras {@link Intent#EXTRA_CHANGED_PACKAGE_LIST} and
     * {@link Intent#EXTRA_CHANGED_UID_LIST} by using the rules of the package visibility.
     *
     * @param callingUid The uid that is going to access the intent extras.
     * @param extras The intent extras to filter
     * @return An extras that have been filtered, or {@code null} if the given uid is unable to
     * access all the packages in the extras.
     */
    @Nullable
    public static Bundle filterExtrasChangedPackageList(@NonNull Computer snapshot, int callingUid,
            @NonNull Bundle extras) {
        if (UserHandle.isCore(callingUid)) {
            // see all
            return extras;
        }
        final String[] pkgs = extras.getStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST);
        if (ArrayUtils.isEmpty(pkgs)) {
            return extras;
        }
        final int userId = extras.getInt(
                Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(callingUid));
        final int[] uids = extras.getIntArray(Intent.EXTRA_CHANGED_UID_LIST);
        final Pair<String[], int[]> filteredPkgs =
                filterPackages(snapshot, pkgs, uids, callingUid, userId);
        if (ArrayUtils.isEmpty(filteredPkgs.first)) {
            // caller is unable to access this intent
            return null;
        }
        final Bundle filteredExtras = new Bundle(extras);
        filteredExtras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, filteredPkgs.first);
        filteredExtras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, filteredPkgs.second);
        return filteredExtras;
    }

    @NonNull
    private static Pair<String[], int[]> filterPackages(@NonNull Computer snapshot,
            @NonNull String[] pkgs, @Nullable int[] uids, int callingUid, int userId) {
        final int pkgSize = pkgs.length;
        final int uidSize = !ArrayUtils.isEmpty(uids) ? uids.length : 0;

        final ArrayList<String> pkgList = new ArrayList<>(pkgSize);
        final IntArray uidList = uidSize > 0 ? new IntArray(uidSize) : null;
        for (int i = 0; i < pkgSize; i++) {
            final String packageName = pkgs[i];
            if (snapshot.shouldFilterApplication(
                    snapshot.getPackageStateInternal(packageName), callingUid, userId)) {
                continue;
            }
            pkgList.add(packageName);
            if (uidList != null && i < uidSize) {
                uidList.add(uids[i]);
            }
        }
        return new Pair<>(
                pkgList.size() > 0 ? pkgList.toArray(new String[pkgList.size()]) : null,
                uidList != null && uidList.size() > 0 ? uidList.toArray() : null);
    }
}
Loading