diff options
| author | 2024-10-27 01:17:45 +0000 | |
|---|---|---|
| committer | 2024-10-27 18:44:29 +0000 | |
| commit | 62513b64e8b9e9c9c71b43aa9af7ec2cd0b18f88 (patch) | |
| tree | d9e38f0752db6ab0c5a0c63f89118322af1c13af | |
| parent | f8ea5bcc0546b65f0e3a4d4436db2f84c772fcbe (diff) | |
Limit priority values used with receiver registrations.
The priority values are limited to within the range
(SYSTEM_HIGH_PRIORITY, SYSTEM_LOW_PRIORITY).
Bug: 371309185
Test: atest services/tests/mockingservicestests/src/com/android/server/am/BroadcastFilterTest.java
Flag: com.android.server.am.restrict_priority_values
Change-Id: I5e98d3f5e592be08ac2076d7860e2d171cf04a92
5 files changed, 278 insertions, 5 deletions
diff --git a/services/core/java/com/android/server/am/BroadcastController.java b/services/core/java/com/android/server/am/BroadcastController.java index a00cac6aba4f..71ddf05eb692 100644 --- a/services/core/java/com/android/server/am/BroadcastController.java +++ b/services/core/java/com/android/server/am/BroadcastController.java @@ -554,7 +554,7 @@ class BroadcastController { } BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId, receiverId, permission, callingUid, userId, instantApp, visibleToInstantApps, - exported); + exported, mService.mPlatformCompat); if (rl.containsFilter(filter)) { Slog.w(TAG, "Receiver with filter " + filter + " already registered for pid " + rl.pid diff --git a/services/core/java/com/android/server/am/BroadcastFilter.java b/services/core/java/com/android/server/am/BroadcastFilter.java index adb2392a8484..f016590b6539 100644 --- a/services/core/java/com/android/server/am/BroadcastFilter.java +++ b/services/core/java/com/android/server/am/BroadcastFilter.java @@ -17,16 +17,33 @@ package com.android.server.am; import android.annotation.Nullable; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; +import android.compat.annotation.Overridable; import android.content.IntentFilter; +import android.os.UserHandle; import android.util.PrintWriterPrinter; import android.util.Printer; import android.util.proto.ProtoOutputStream; +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.compat.PlatformCompat; + import dalvik.annotation.optimization.NeverCompile; import java.io.PrintWriter; public final class BroadcastFilter extends IntentFilter { + /** + * Limit priority values defined by non-system apps to + * ({@link IntentFilter#SYSTEM_LOW_PRIORITY}, {@link IntentFilter#SYSTEM_HIGH_PRIORITY}). + */ + @ChangeId + @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.BASE) + @Overridable + @VisibleForTesting + static final long CHANGE_RESTRICT_PRIORITY_VALUES = 371309185L; + // Back-pointer to the list this filter is in. final ReceiverList receiverList; final String packageName; @@ -38,11 +55,12 @@ public final class BroadcastFilter extends IntentFilter { final boolean instantApp; final boolean visibleToInstantApp; public final boolean exported; + final int initialPriority; BroadcastFilter(IntentFilter _filter, ReceiverList _receiverList, String _packageName, String _featureId, String _receiverId, String _requiredPermission, int _owningUid, int _userId, boolean _instantApp, boolean _visibleToInstantApp, - boolean _exported) { + boolean _exported, PlatformCompat platformCompat) { super(_filter); receiverList = _receiverList; packageName = _packageName; @@ -54,6 +72,8 @@ public final class BroadcastFilter extends IntentFilter { instantApp = _instantApp; visibleToInstantApp = _visibleToInstantApp; exported = _exported; + initialPriority = getPriority(); + setPriority(calculateAdjustedPriority(owningUid, initialPriority, platformCompat)); } public @Nullable String getReceiverClassName() { @@ -100,6 +120,29 @@ public final class BroadcastFilter extends IntentFilter { if (requiredPermission != null) { pw.print(prefix); pw.print("requiredPermission="); pw.println(requiredPermission); } + if (initialPriority != getPriority()) { + pw.print(prefix); pw.print("initialPriority="); pw.println(initialPriority); + } + } + + @VisibleForTesting + static int calculateAdjustedPriority(int owningUid, int priority, + PlatformCompat platformCompat) { + if (!Flags.restrictPriorityValues()) { + return priority; + } + if (!platformCompat.isChangeEnabledByUidInternalNoLogging( + CHANGE_RESTRICT_PRIORITY_VALUES, owningUid)) { + return priority; + } + if (!UserHandle.isCore(owningUid)) { + if (priority >= SYSTEM_HIGH_PRIORITY) { + return SYSTEM_HIGH_PRIORITY - 1; + } else if (priority <= SYSTEM_LOW_PRIORITY) { + return SYSTEM_LOW_PRIORITY + 1; + } + } + return priority; } public String toString() { diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig index d67fea09f945..d680712676cd 100644 --- a/services/core/java/com/android/server/am/flags.aconfig +++ b/services/core/java/com/android/server/am/flags.aconfig @@ -233,3 +233,11 @@ flag { description: "Assign cached oom_score_adj in tiers." bug: "369893532" } + +flag { + name: "restrict_priority_values" + namespace: "backstage_power" + description: "Restrict priority values defined by non-system apps" + is_fixed_read_only: true + bug: "369487976" +} diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java index 586191702578..d602660597ff 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java @@ -23,6 +23,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import android.annotation.NonNull; @@ -52,11 +53,11 @@ import com.android.server.AlarmManagerInternal; import com.android.server.DropBoxManagerInternal; import com.android.server.LocalServices; import com.android.server.appop.AppOpsService; +import com.android.server.compat.PlatformCompat; import com.android.server.wm.ActivityTaskManagerService; import org.junit.Rule; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.io.File; @@ -164,7 +165,7 @@ public abstract class BaseBroadcastQueueTest { realAms.mActivityTaskManager = new ActivityTaskManagerService(mContext); realAms.mActivityTaskManager.initialize(null, null, mContext.getMainLooper()); realAms.mAtmInternal = spy(realAms.mActivityTaskManager.getAtmInternal()); - realAms.mOomAdjuster.mCachedAppOptimizer = Mockito.mock(CachedAppOptimizer.class); + realAms.mOomAdjuster.mCachedAppOptimizer = mock(CachedAppOptimizer.class); realAms.mOomAdjuster = spy(realAms.mOomAdjuster); ExtendedMockito.doNothing().when(() -> ProcessList.setOomAdj(anyInt(), anyInt(), anyInt())); realAms.mPackageManagerInt = mPackageManagerInt; @@ -286,7 +287,8 @@ public abstract class BaseBroadcastQueueTest { filter.setPriority(priority); final BroadcastFilter res = new BroadcastFilter(filter, receiverList, receiverList.app.info.packageName, null, null, null, receiverList.uid, - receiverList.userId, false, false, true); + receiverList.userId, false, false, true, + mock(PlatformCompat.class)); receiverList.add(res); return res; } diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastFilterTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastFilterTest.java new file mode 100644 index 000000000000..e977a7d46f30 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastFilterTest.java @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.am; + +import static android.content.IntentFilter.SYSTEM_HIGH_PRIORITY; +import static android.content.IntentFilter.SYSTEM_LOW_PRIORITY; + +import static com.google.common.truth.Truth.assertWithMessage; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; + +import android.os.Process; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; +import android.util.Pair; + +import androidx.test.filters.SmallTest; + +import com.android.server.compat.PlatformCompat; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +public class BroadcastFilterTest { + private static final int TEST_APP_UID = Process.FIRST_APPLICATION_UID + 42; + + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + @Mock + PlatformCompat mPlatformCompat; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + @EnableFlags(Flags.FLAG_RESTRICT_PRIORITY_VALUES) + public void testCalculateAdjustedPriority() { + doReturn(true).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( + eq(BroadcastFilter.CHANGE_RESTRICT_PRIORITY_VALUES), anyInt()); + + { + // Pairs of {initial-priority, expected-adjusted-priority} + final Pair<Integer, Integer>[] priorities = new Pair[] { + Pair.create(SYSTEM_HIGH_PRIORITY, SYSTEM_HIGH_PRIORITY), + Pair.create(SYSTEM_LOW_PRIORITY, SYSTEM_LOW_PRIORITY), + Pair.create(SYSTEM_HIGH_PRIORITY + 1, SYSTEM_HIGH_PRIORITY + 1), + Pair.create(SYSTEM_LOW_PRIORITY - 1, SYSTEM_LOW_PRIORITY - 1), + Pair.create(SYSTEM_HIGH_PRIORITY - 2, SYSTEM_HIGH_PRIORITY - 2), + Pair.create(SYSTEM_LOW_PRIORITY + 2, SYSTEM_LOW_PRIORITY + 2) + }; + for (Pair<Integer, Integer> priorityPair : priorities) { + assertAdjustedPriorityForSystemUid(priorityPair.first, priorityPair.second); + } + } + + { + // Pairs of {initial-priority, expected-adjusted-priority} + final Pair<Integer, Integer>[] priorities = new Pair[] { + Pair.create(SYSTEM_HIGH_PRIORITY, SYSTEM_HIGH_PRIORITY - 1), + Pair.create(SYSTEM_LOW_PRIORITY, SYSTEM_LOW_PRIORITY + 1), + Pair.create(SYSTEM_HIGH_PRIORITY + 1, SYSTEM_HIGH_PRIORITY - 1), + Pair.create(SYSTEM_LOW_PRIORITY - 1, SYSTEM_LOW_PRIORITY + 1), + Pair.create(SYSTEM_HIGH_PRIORITY - 2, SYSTEM_HIGH_PRIORITY - 2), + Pair.create(SYSTEM_LOW_PRIORITY + 2, SYSTEM_LOW_PRIORITY + 2) + }; + for (Pair<Integer, Integer> priorityPair : priorities) { + assertAdjustedPriorityForAppUid(priorityPair.first, priorityPair.second); + } + } + } + + @Test + @EnableFlags(Flags.FLAG_RESTRICT_PRIORITY_VALUES) + public void testCalculateAdjustedPriority_withChangeIdDisabled() { + doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( + eq(BroadcastFilter.CHANGE_RESTRICT_PRIORITY_VALUES), anyInt()); + + { + // Pairs of {initial-priority, expected-adjusted-priority} + final Pair<Integer, Integer>[] priorities = new Pair[] { + Pair.create(SYSTEM_HIGH_PRIORITY, SYSTEM_HIGH_PRIORITY), + Pair.create(SYSTEM_LOW_PRIORITY, SYSTEM_LOW_PRIORITY), + Pair.create(SYSTEM_HIGH_PRIORITY + 1, SYSTEM_HIGH_PRIORITY + 1), + Pair.create(SYSTEM_LOW_PRIORITY - 1, SYSTEM_LOW_PRIORITY - 1), + Pair.create(SYSTEM_HIGH_PRIORITY - 2, SYSTEM_HIGH_PRIORITY - 2), + Pair.create(SYSTEM_LOW_PRIORITY + 2, SYSTEM_LOW_PRIORITY + 2) + }; + for (Pair<Integer, Integer> priorityPair : priorities) { + assertAdjustedPriorityForSystemUid(priorityPair.first, priorityPair.second); + } + } + + { + // Pairs of {initial-priority, expected-adjusted-priority} + final Pair<Integer, Integer>[] priorities = new Pair[] { + Pair.create(SYSTEM_HIGH_PRIORITY, SYSTEM_HIGH_PRIORITY), + Pair.create(SYSTEM_LOW_PRIORITY, SYSTEM_LOW_PRIORITY), + Pair.create(SYSTEM_HIGH_PRIORITY + 1, SYSTEM_HIGH_PRIORITY + 1), + Pair.create(SYSTEM_LOW_PRIORITY - 1, SYSTEM_LOW_PRIORITY - 1), + Pair.create(SYSTEM_HIGH_PRIORITY - 2, SYSTEM_HIGH_PRIORITY - 2), + Pair.create(SYSTEM_LOW_PRIORITY + 2, SYSTEM_LOW_PRIORITY + 2) + }; + for (Pair<Integer, Integer> priorityPair : priorities) { + assertAdjustedPriorityForAppUid(priorityPair.first, priorityPair.second); + } + } + } + + @Test + @DisableFlags(Flags.FLAG_RESTRICT_PRIORITY_VALUES) + public void testCalculateAdjustedPriority_withFlagDisabled() { + doReturn(true).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( + eq(BroadcastFilter.CHANGE_RESTRICT_PRIORITY_VALUES), anyInt()); + + { + // Pairs of {initial-priority, expected-adjusted-priority} + final Pair<Integer, Integer>[] priorities = new Pair[] { + Pair.create(SYSTEM_HIGH_PRIORITY, SYSTEM_HIGH_PRIORITY), + Pair.create(SYSTEM_LOW_PRIORITY, SYSTEM_LOW_PRIORITY), + Pair.create(SYSTEM_HIGH_PRIORITY + 1, SYSTEM_HIGH_PRIORITY + 1), + Pair.create(SYSTEM_LOW_PRIORITY - 1, SYSTEM_LOW_PRIORITY - 1), + Pair.create(SYSTEM_HIGH_PRIORITY - 2, SYSTEM_HIGH_PRIORITY - 2), + Pair.create(SYSTEM_LOW_PRIORITY + 2, SYSTEM_LOW_PRIORITY + 2) + }; + for (Pair<Integer, Integer> priorityPair : priorities) { + assertAdjustedPriorityForSystemUid(priorityPair.first, priorityPair.second); + } + } + + { + // Pairs of {initial-priority, expected-adjusted-priority} + final Pair<Integer, Integer>[] priorities = new Pair[] { + Pair.create(SYSTEM_HIGH_PRIORITY, SYSTEM_HIGH_PRIORITY), + Pair.create(SYSTEM_LOW_PRIORITY, SYSTEM_LOW_PRIORITY), + Pair.create(SYSTEM_HIGH_PRIORITY + 1, SYSTEM_HIGH_PRIORITY + 1), + Pair.create(SYSTEM_LOW_PRIORITY - 1, SYSTEM_LOW_PRIORITY - 1), + Pair.create(SYSTEM_HIGH_PRIORITY - 2, SYSTEM_HIGH_PRIORITY - 2), + Pair.create(SYSTEM_LOW_PRIORITY + 2, SYSTEM_LOW_PRIORITY + 2) + }; + for (Pair<Integer, Integer> priorityPair : priorities) { + assertAdjustedPriorityForAppUid(priorityPair.first, priorityPair.second); + } + } + } + + @Test + @DisableFlags(Flags.FLAG_RESTRICT_PRIORITY_VALUES) + public void testCalculateAdjustedPriority_withFlagDisabled_withChangeIdDisabled() { + doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( + eq(BroadcastFilter.CHANGE_RESTRICT_PRIORITY_VALUES), anyInt()); + + { + // Pairs of {initial-priority, expected-adjusted-priority} + final Pair<Integer, Integer>[] priorities = new Pair[] { + Pair.create(SYSTEM_HIGH_PRIORITY, SYSTEM_HIGH_PRIORITY), + Pair.create(SYSTEM_LOW_PRIORITY, SYSTEM_LOW_PRIORITY), + Pair.create(SYSTEM_HIGH_PRIORITY + 1, SYSTEM_HIGH_PRIORITY + 1), + Pair.create(SYSTEM_LOW_PRIORITY - 1, SYSTEM_LOW_PRIORITY - 1), + Pair.create(SYSTEM_HIGH_PRIORITY - 2, SYSTEM_HIGH_PRIORITY - 2), + Pair.create(SYSTEM_LOW_PRIORITY + 2, SYSTEM_LOW_PRIORITY + 2) + }; + for (Pair<Integer, Integer> priorityPair : priorities) { + assertAdjustedPriorityForSystemUid(priorityPair.first, priorityPair.second); + } + } + + { + // Pairs of {initial-priority, expected-adjusted-priority} + final Pair<Integer, Integer>[] priorities = new Pair[] { + Pair.create(SYSTEM_HIGH_PRIORITY, SYSTEM_HIGH_PRIORITY), + Pair.create(SYSTEM_LOW_PRIORITY, SYSTEM_LOW_PRIORITY), + Pair.create(SYSTEM_HIGH_PRIORITY + 1, SYSTEM_HIGH_PRIORITY + 1), + Pair.create(SYSTEM_LOW_PRIORITY - 1, SYSTEM_LOW_PRIORITY - 1), + Pair.create(SYSTEM_HIGH_PRIORITY - 2, SYSTEM_HIGH_PRIORITY - 2), + Pair.create(SYSTEM_LOW_PRIORITY + 2, SYSTEM_LOW_PRIORITY + 2) + }; + for (Pair<Integer, Integer> priorityPair : priorities) { + assertAdjustedPriorityForAppUid(priorityPair.first, priorityPair.second); + } + } + } + + private void assertAdjustedPriorityForSystemUid(int priority, int expectedAdjustedPriority) { + assertAdjustedPriority(Process.SYSTEM_UID, priority, expectedAdjustedPriority); + } + + private void assertAdjustedPriorityForAppUid(int priority, int expectedAdjustedPriority) { + assertAdjustedPriority(TEST_APP_UID, priority, expectedAdjustedPriority); + } + + private void assertAdjustedPriority(int owningUid, int priority, int expectedAdjustedPriority) { + final String errorMsg = String.format("owner=%d; actualPriority=%d; expectedPriority=%d", + owningUid, priority, expectedAdjustedPriority); + assertWithMessage(errorMsg).that(BroadcastFilter.calculateAdjustedPriority( + owningUid, priority, mPlatformCompat)).isEqualTo(expectedAdjustedPriority); + } +} |