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

Commit dad192db authored by Sudheer Shanka's avatar Sudheer Shanka Committed by Android (Google) Code Review
Browse files

Merge "Limit the scope of receiver priorities to within a process." into main

parents cc218995 102e1422
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -593,7 +593,7 @@ class BroadcastController {
                            originalStickyCallingUid, BackgroundStartPrivileges.NONE,
                            originalStickyCallingUid, BackgroundStartPrivileges.NONE,
                            false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */,
                            false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */,
                            null /* filterExtrasForReceiver */,
                            null /* filterExtrasForReceiver */,
                            broadcast.originalCallingAppProcessState);
                            broadcast.originalCallingAppProcessState, mService.mPlatformCompat);
                    queue.enqueueBroadcastLocked(r);
                    queue.enqueueBroadcastLocked(r);
                }
                }
            }
            }
@@ -1631,7 +1631,7 @@ class BroadcastController {
                    receivers, resultToApp, resultTo, resultCode, resultData, resultExtras,
                    receivers, resultToApp, resultTo, resultCode, resultData, resultExtras,
                    ordered, sticky, false, userId,
                    ordered, sticky, false, userId,
                    backgroundStartPrivileges, timeoutExempt, filterExtrasForReceiver,
                    backgroundStartPrivileges, timeoutExempt, filterExtrasForReceiver,
                    callerAppProcessState);
                    callerAppProcessState, mService.mPlatformCompat);
            broadcastSentEventRecord.setBroadcastRecord(r);
            broadcastSentEventRecord.setBroadcastRecord(r);


            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);
            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);
+125 −24
Original line number Original line Diff line number Diff line
@@ -42,6 +42,9 @@ import android.app.AppOpsManager;
import android.app.BackgroundStartPrivileges;
import android.app.BackgroundStartPrivileges;
import android.app.BroadcastOptions;
import android.app.BroadcastOptions;
import android.app.BroadcastOptions.DeliveryGroupPolicy;
import android.app.BroadcastOptions.DeliveryGroupPolicy;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.compat.annotation.Overridable;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.IIntentReceiver;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.Intent;
@@ -55,10 +58,12 @@ import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArrayMap;
import android.util.IntArray;
import android.util.IntArray;
import android.util.PrintWriterPrinter;
import android.util.PrintWriterPrinter;
import android.util.SparseBooleanArray;
import android.util.TimeUtils;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.util.proto.ProtoOutputStream;


import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.compat.PlatformCompat;


import dalvik.annotation.optimization.NeverCompile;
import dalvik.annotation.optimization.NeverCompile;


@@ -77,6 +82,16 @@ import java.util.function.BiFunction;
 * An active intent broadcast.
 * An active intent broadcast.
 */
 */
final class BroadcastRecord extends Binder {
final class BroadcastRecord extends Binder {
    /**
     * Limit the scope of the priority values to the process level. This means that priority values
     * will only influence the order of broadcast delivery within the same process.
     */
    @ChangeId
    @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.BASE)
    @Overridable
    @VisibleForTesting
    static final long CHANGE_LIMIT_PRIORITY_SCOPE = 371307720L;

    final @NonNull Intent intent;    // the original intent that generated us
    final @NonNull Intent intent;    // the original intent that generated us
    final @Nullable ComponentName targetComp; // original component name set on the intent
    final @Nullable ComponentName targetComp; // original component name set on the intent
    final @Nullable ProcessRecord callerApp; // process that sent this
    final @Nullable ProcessRecord callerApp; // process that sent this
@@ -417,13 +432,13 @@ final class BroadcastRecord extends Binder {
            @NonNull BackgroundStartPrivileges backgroundStartPrivileges,
            @NonNull BackgroundStartPrivileges backgroundStartPrivileges,
            boolean timeoutExempt,
            boolean timeoutExempt,
            @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver,
            @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver,
            int callerAppProcessState) {
            int callerAppProcessState, PlatformCompat platformCompat) {
        this(queue, intent, callerApp, callerPackage, callerFeatureId, callingPid,
        this(queue, intent, callerApp, callerPackage, callerFeatureId, callingPid,
                callingUid, callerInstantApp, resolvedType, requiredPermissions,
                callingUid, callerInstantApp, resolvedType, requiredPermissions,
                excludedPermissions, excludedPackages, appOp, options, receivers, resultToApp,
                excludedPermissions, excludedPackages, appOp, options, receivers, resultToApp,
                resultTo, resultCode, resultData, resultExtras, serialized, sticky,
                resultTo, resultCode, resultData, resultExtras, serialized, sticky,
                initialSticky, userId, -1, backgroundStartPrivileges, timeoutExempt,
                initialSticky, userId, -1, backgroundStartPrivileges, timeoutExempt,
                filterExtrasForReceiver, callerAppProcessState);
                filterExtrasForReceiver, callerAppProcessState, platformCompat);
    }
    }


    BroadcastRecord(BroadcastQueue _queue,
    BroadcastRecord(BroadcastQueue _queue,
@@ -439,7 +454,7 @@ final class BroadcastRecord extends Binder {
            @NonNull BackgroundStartPrivileges backgroundStartPrivileges,
            @NonNull BackgroundStartPrivileges backgroundStartPrivileges,
            boolean timeoutExempt,
            boolean timeoutExempt,
            @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver,
            @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver,
            int callerAppProcessState) {
            int callerAppProcessState, PlatformCompat platformCompat) {
        if (_intent == null) {
        if (_intent == null) {
            throw new NullPointerException("Can't construct with a null intent");
            throw new NullPointerException("Can't construct with a null intent");
        }
        }
@@ -466,7 +481,8 @@ final class BroadcastRecord extends Binder {
        urgent = calculateUrgent(_intent, _options);
        urgent = calculateUrgent(_intent, _options);
        deferUntilActive = calculateDeferUntilActive(_callingUid,
        deferUntilActive = calculateDeferUntilActive(_callingUid,
                _options, _resultTo, _serialized, urgent);
                _options, _resultTo, _serialized, urgent);
        blockedUntilBeyondCount = calculateBlockedUntilBeyondCount(receivers, _serialized);
        blockedUntilBeyondCount = calculateBlockedUntilBeyondCount(
                receivers, _serialized, platformCompat);
        scheduledTime = new long[delivery.length];
        scheduledTime = new long[delivery.length];
        terminalTime = new long[delivery.length];
        terminalTime = new long[delivery.length];
        resultToApp = _resultToApp;
        resultToApp = _resultToApp;
@@ -730,7 +746,8 @@ final class BroadcastRecord extends Binder {
    }
    }


    /**
    /**
     * Determine if the result of {@link #calculateBlockedUntilBeyondCount(List, boolean)}
     * Determine if the result of
     * {@link #calculateBlockedUntilBeyondCount(List, boolean, PlatformCompat)}
     * has prioritized tranches of receivers.
     * has prioritized tranches of receivers.
     */
     */
    @VisibleForTesting
    @VisibleForTesting
@@ -754,19 +771,80 @@ final class BroadcastRecord extends Binder {
     */
     */
    @VisibleForTesting
    @VisibleForTesting
    static @NonNull int[] calculateBlockedUntilBeyondCount(
    static @NonNull int[] calculateBlockedUntilBeyondCount(
            @NonNull List<Object> receivers, boolean ordered) {
            @NonNull List<Object> receivers, boolean ordered, PlatformCompat platformCompat) {
        final int N = receivers.size();
        final int N = receivers.size();
        final int[] blockedUntilBeyondCount = new int[N];
        final int[] blockedUntilBeyondCount = new int[N];
        int lastPriority = 0;
        int lastPriorityIndex = 0;
        for (int i = 0; i < N; i++) {
        if (ordered) {
        if (ordered) {
            // When sending an ordered broadcast, we need to block this
            // When sending an ordered broadcast, we need to block this
            // receiver until all previous receivers have terminated
            // receiver until all previous receivers have terminated
            for (int i = 0; i < N; i++) {
                blockedUntilBeyondCount[i] = i;
                blockedUntilBeyondCount[i] = i;
            }
        } else {
            if (Flags.limitPriorityScope()) {
                final boolean[] changeEnabled = calculateChangeStateForReceivers(
                        receivers, CHANGE_LIMIT_PRIORITY_SCOPE, platformCompat);

                // Priority of the previous tranche
                int lastTranchePriority = 0;
                // Priority of the current tranche
                int currentTranchePriority = 0;
                // Index of the last receiver in the previous tranche
                int lastTranchePriorityIndex = -1;
                // Index of the last receiver with change disabled in the previous tranche
                int lastTrancheChangeDisabledIndex = -1;
                // Index of the last receiver with change disabled in the current tranche
                int currentTrancheChangeDisabledIndex = -1;

                for (int i = 0; i < N; i++) {
                    final int thisPriority = getReceiverPriority(receivers.get(i));
                    if (i == 0) {
                        currentTranchePriority = thisPriority;
                        if (!changeEnabled[i]) {
                            currentTrancheChangeDisabledIndex = i;
                        }
                        continue;
                    }

                    // Check if a new priority tranche has started
                    if (thisPriority != currentTranchePriority) {
                        // Update tranche boundaries and reset the disabled index.
                        if (currentTrancheChangeDisabledIndex != -1) {
                            lastTrancheChangeDisabledIndex = currentTrancheChangeDisabledIndex;
                        }
                        lastTranchePriority = currentTranchePriority;
                        lastTranchePriorityIndex = i - 1;
                        currentTranchePriority = thisPriority;
                        currentTrancheChangeDisabledIndex = -1;
                    }
                    if (!changeEnabled[i]) {
                        currentTrancheChangeDisabledIndex = i;

                        // Since the change is disabled, block the current receiver until the
                        // last receiver in the previous tranche.
                        blockedUntilBeyondCount[i] = lastTranchePriorityIndex + 1;
                    } else if (thisPriority != lastTranchePriority) {
                        // If the changeId was disabled for an earlier receiver and the current
                        // receiver has a different priority, block the current receiver
                        // until that earlier receiver.
                        if (lastTrancheChangeDisabledIndex != -1) {
                            blockedUntilBeyondCount[i] = lastTrancheChangeDisabledIndex + 1;
                        }
                    }
                }
                // If the entire list is in the same priority tranche or no receivers had
                // changeId disabled, mark as -1 to indicate that none of them need to wait
                if (N > 0 && (lastTranchePriorityIndex == -1
                        || (lastTrancheChangeDisabledIndex == -1
                                && currentTrancheChangeDisabledIndex == -1))) {
                    Arrays.fill(blockedUntilBeyondCount, -1);
                }
            } else {
            } else {
                // When sending a prioritized broadcast, we only need to wait
                // When sending a prioritized broadcast, we only need to wait
                // for the previous tranche of receivers to be terminated
                // for the previous tranche of receivers to be terminated
                int lastPriority = 0;
                int lastPriorityIndex = 0;
                for (int i = 0; i < N; i++) {
                    final int thisPriority = getReceiverPriority(receivers.get(i));
                    final int thisPriority = getReceiverPriority(receivers.get(i));
                    if ((i == 0) || (thisPriority != lastPriority)) {
                    if ((i == 0) || (thisPriority != lastPriority)) {
                        lastPriority = thisPriority;
                        lastPriority = thisPriority;
@@ -776,15 +854,38 @@ final class BroadcastRecord extends Binder {
                        blockedUntilBeyondCount[i] = lastPriorityIndex;
                        blockedUntilBeyondCount[i] = lastPriorityIndex;
                    }
                    }
                }
                }
        }
                // If the entire list is in the same priority tranche, mark as -1 to
                // If the entire list is in the same priority tranche, mark as -1 to
                // indicate that none of them need to wait
                // indicate that none of them need to wait
                if (N > 0 && blockedUntilBeyondCount[N - 1] == 0) {
                if (N > 0 && blockedUntilBeyondCount[N - 1] == 0) {
                    Arrays.fill(blockedUntilBeyondCount, -1);
                    Arrays.fill(blockedUntilBeyondCount, -1);
                }
                }
            }
        }
        return blockedUntilBeyondCount;
        return blockedUntilBeyondCount;
    }
    }


    @VisibleForTesting
    static @NonNull boolean[] calculateChangeStateForReceivers(@NonNull List<Object> receivers,
            long changeId, PlatformCompat platformCompat) {
        final SparseBooleanArray changeStateForUids = new SparseBooleanArray();
        final int count = receivers.size();
        final boolean[] changeStateForReceivers = new boolean[count];
        for (int i = 0; i < count; ++i) {
            final int receiverUid = getReceiverUid(receivers.get(i));
            final boolean isChangeEnabled;
            final int idx = changeStateForUids.indexOfKey(receiverUid);
            if (idx >= 0) {
                isChangeEnabled = changeStateForUids.valueAt(idx);
            } else {
                isChangeEnabled = platformCompat.isChangeEnabledByUidInternalNoLogging(
                        changeId, receiverUid);
                changeStateForUids.put(receiverUid, isChangeEnabled);
            }
            changeStateForReceivers[i] = isChangeEnabled;
        }
        return changeStateForReceivers;
    }

    static int getReceiverUid(@NonNull Object receiver) {
    static int getReceiverUid(@NonNull Object receiver) {
        if (receiver instanceof BroadcastFilter) {
        if (receiver instanceof BroadcastFilter) {
            return ((BroadcastFilter) receiver).owningUid;
            return ((BroadcastFilter) receiver).owningUid;
+8 −0
Original line number Original line Diff line number Diff line
@@ -8,3 +8,11 @@ flag {
    is_fixed_read_only: true
    is_fixed_read_only: true
    bug: "369487976"
    bug: "369487976"
}
}

flag {
    name: "limit_priority_scope"
    namespace: "backstage_power"
    description: "Limit the scope of receiver priorities to within a process"
    is_fixed_read_only: true
    bug: "369487976"
}
 No newline at end of file
+1 −0
Original line number Original line Diff line number Diff line
@@ -134,6 +134,7 @@ android_ravenwood_test {
        "androidx.annotation_annotation",
        "androidx.annotation_annotation",
        "androidx.test.rules",
        "androidx.test.rules",
        "services.core",
        "services.core",
        "servicestests-utils-mockito-extended",
    ],
    ],
    srcs: [
    srcs: [
        "src/com/android/server/am/BroadcastRecordTest.java",
        "src/com/android/server/am/BroadcastRecordTest.java",
+11 −0
Original line number Original line Diff line number Diff line
@@ -41,6 +41,7 @@ import android.os.TestLooperManager;
import android.os.UserHandle;
import android.os.UserHandle;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.provider.Settings;
import android.util.SparseArray;
import android.util.SparseArray;


@@ -97,6 +98,9 @@ public abstract class BaseBroadcastQueueTest {
            .spyStatic(ProcessList.class)
            .spyStatic(ProcessList.class)
            .build();
            .build();



    @Rule
    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
    @Rule
    @Rule
    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();


@@ -112,6 +116,8 @@ public abstract class BaseBroadcastQueueTest {
    AlarmManagerInternal mAlarmManagerInt;
    AlarmManagerInternal mAlarmManagerInt;
    @Mock
    @Mock
    ProcessList mProcessList;
    ProcessList mProcessList;
    @Mock
    PlatformCompat mPlatformCompat;


    @Mock
    @Mock
    AppStartInfoTracker mAppStartInfoTracker;
    AppStartInfoTracker mAppStartInfoTracker;
@@ -178,6 +184,11 @@ public abstract class BaseBroadcastQueueTest {
        doReturn(false).when(mSkipPolicy).disallowBackgroundStart(any());
        doReturn(false).when(mSkipPolicy).disallowBackgroundStart(any());


        doReturn(mAppStartInfoTracker).when(mProcessList).getAppStartInfoTracker();
        doReturn(mAppStartInfoTracker).when(mProcessList).getAppStartInfoTracker();

        doReturn(true).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
                eq(BroadcastFilter.CHANGE_RESTRICT_PRIORITY_VALUES), anyInt());
        doReturn(true).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
                eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), anyInt());
    }
    }


    public void tearDown() throws Exception {
    public void tearDown() throws Exception {
Loading