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

Commit 570984fe authored by Sudheer Shanka's avatar Sudheer Shanka
Browse files

Avoid resolving data type when dispatching sticky broadcasts.

We can use the type that is used for initially dispatching
these broadcasts.

Bug: 323817802
Test: atest tests/app/src/android/app/cts/ForceStopTest.java
Test: atest services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
Change-Id: I1c1bbc85d6c8e5f891f7107844462932bb1cd16d
parent a7a47f65
Loading
Loading
Loading
Loading
+17 −5
Original line number Diff line number Diff line
@@ -1192,14 +1192,17 @@ public class ActivityManagerService extends IActivityManager.Stub
        public int originalCallingUid;
        /** The snapshot process state of the app who sent this broadcast */
        public int originalCallingAppProcessState;
        public String resolvedDataType;
        public static StickyBroadcast create(Intent intent, boolean deferUntilActive,
                int originalCallingUid, int originalCallingAppProcessState) {
                int originalCallingUid, int originalCallingAppProcessState,
                String resolvedDataType) {
            final StickyBroadcast b = new StickyBroadcast();
            b.intent = intent;
            b.deferUntilActive = deferUntilActive;
            b.originalCallingUid = originalCallingUid;
            b.originalCallingAppProcessState = originalCallingAppProcessState;
            b.resolvedDataType = resolvedDataType;
            return b;
        }
@@ -1207,7 +1210,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        public String toString() {
            return "{intent=" + intent + ", defer=" + deferUntilActive + ", originalCallingUid="
                    + originalCallingUid + ", originalCallingAppProcessState="
                    + originalCallingAppProcessState + "}";
                    + originalCallingAppProcessState + ", type=" + resolvedDataType + "}";
        }
    }
@@ -14528,7 +14531,16 @@ public class ActivityManagerService extends IActivityManager.Stub
                // provider that needs to lock mProviderMap in ActivityThread
                // and also it may need to wait application response, so we
                // cannot lock ActivityManagerService here.
                if (filter.match(resolver, intent, true, TAG) >= 0) {
                final int match;
                if (Flags.avoidResolvingType()) {
                    match = filter.match(intent.getAction(), broadcast.resolvedDataType,
                        intent.getScheme(), intent.getData(), intent.getCategories(),
                        TAG, false /* supportsWildcards */, null /* ignoreActions */,
                        intent.getExtras());
                } else {
                    match = filter.match(resolver, intent, true, TAG);
                }
                if (match >= 0) {
                    if (allSticky == null) {
                        allSticky = new ArrayList<>();
                    }
@@ -15542,13 +15554,13 @@ public class ActivityManagerService extends IActivityManager.Stub
                    if (intent.filterEquals(list.get(i).intent)) {
                        // This sticky already exists, replace it.
                        list.set(i, StickyBroadcast.create(new Intent(intent), deferUntilActive,
                                callingUid, callerAppProcessState));
                                callingUid, callerAppProcessState, resolvedType));
                        break;
                    }
                }
                if (i >= stickiesCount) {
                    list.add(StickyBroadcast.create(new Intent(intent), deferUntilActive,
                            callingUid, callerAppProcessState));
                            callingUid, callerAppProcessState, resolvedType));
                }
            }
        }
+11 −0
Original line number Diff line number Diff line
@@ -75,3 +75,14 @@ flag {
    description: "Log the excessive incoming binder proxies into statsd"
    bug: "298263955"
}

flag {
    namespace: "backstage_power"
    name: "avoid_resolving_type"
    description: "Avoid resolving data type for sticky broadcasts"
    bug: "323817802"
    is_fixed_read_only: true
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}
+90 −12
Original line number Diff line number Diff line
@@ -29,6 +29,8 @@ import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
import static android.os.PowerExemptionManager.REASON_DENIED;
import static android.content.ContentResolver.SCHEME_CONTENT;
import static android.os.UserHandle.USER_ALL;
import static android.util.DebugUtils.valueToString;

import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
@@ -39,6 +41,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSess
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static com.android.server.am.ActivityManagerInternalTest.CustomThread;
import static com.android.server.am.ActivityManagerService.Injector;
import static com.android.server.am.Flags.FLAG_AVOID_RESOLVING_TYPE;
import static com.android.server.am.ProcessList.NETWORK_STATE_BLOCK;
import static com.android.server.am.ProcessList.NETWORK_STATE_NO_CHANGE;
import static com.android.server.am.ProcessList.NETWORK_STATE_UNBLOCK;
@@ -66,6 +69,9 @@ import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
@@ -83,14 +89,18 @@ import android.app.Notification;
import android.app.NotificationChannel;
import android.app.SyncNotedAppOp;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ServiceInfo;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
@@ -181,11 +191,15 @@ public class ActivityManagerServiceTest {
    private static final String APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS = ":isSdkSandboxNext";
    private static final int TEST_UID = 11111;
    private static final int TEST_PID = 22222;
    private static final String TEST_PACKAGE = "com.test.package";
    private static final int USER_ID = 666;

    private static final long TEST_PROC_STATE_SEQ1 = 555;
    private static final long TEST_PROC_STATE_SEQ2 = 556;

    private static final String TEST_AUTHORITY = "test_authority";
    private static final String TEST_MIME_TYPE = "application/test_type";

    private static final int[] UID_RECORD_CHANGES = {
        UidRecord.CHANGE_PROCSTATE,
        UidRecord.CHANGE_GONE,
@@ -214,7 +228,7 @@ public class ActivityManagerServiceTest {
    @Mock private PackageManagerInternal mPackageManagerInternal;
    @Mock private ActivityTaskManagerInternal mActivityTaskManagerInternal;
    @Mock private NotificationManagerInternal mNotificationManagerInternal;

    @Mock private ContentResolver mContentResolver;

    private TestInjector mInjector;
    private ActivityManagerService mAms;
@@ -246,7 +260,7 @@ public class ActivityManagerServiceTest {
        mHandlerThread = new HandlerThread(TAG);
        mHandlerThread.start();
        mHandler = new TestHandler(mHandlerThread.getLooper());
        mInjector = new TestInjector(mContext);
        mInjector = new TestInjector(new TestContext(mContext, mContentResolver));
        doAnswer(invocation -> {
            final int userId = invocation.getArgument(2);
            return userId;
@@ -495,20 +509,27 @@ public class ActivityManagerServiceTest {

    @SuppressWarnings("GuardedBy")
    private UidRecord addUidRecord(int uid) {
        return addUidRecord(uid, "");
    }

    @SuppressWarnings("GuardedBy")
    private UidRecord addUidRecord(int uid, String packageName) {
        final UidRecord uidRec = new UidRecord(uid, mAms);
        uidRec.procStateSeqWaitingForNetwork = 1;
        uidRec.hasInternetPermission = true;
        mAms.mProcessList.mActiveUids.put(uid, uidRec);

        ApplicationInfo info = new ApplicationInfo();
        info.packageName = "";
        info.packageName = packageName;
        info.processName = packageName;
        info.uid = uid;

        final ProcessRecord appRec = new ProcessRecord(mAms, info, TAG, uid);
        final ProcessRecord appRec = new ProcessRecord(mAms, info, info.processName, uid);
        final ProcessStatsService tracker = mAms.mProcessStats;
        final IApplicationThread appThread = mock(IApplicationThread.class);
        doReturn(mock(IBinder.class)).when(appThread).asBinder();
        appRec.makeActive(appThread, tracker);
        mAms.mProcessList.addProcessNameLocked(appRec);
        mAms.mProcessList.getLruProcessesLSP().add(appRec);

        return uidRec;
@@ -877,31 +898,71 @@ public class ActivityManagerServiceTest {

        broadcastIntent(intent1, null, true);
        assertStickyBroadcasts(mAms.getStickyBroadcastsForTest(TEST_ACTION1, TEST_USER),
                StickyBroadcast.create(intent1, false, Process.myUid(), PROCESS_STATE_UNKNOWN));
                StickyBroadcast.create(intent1, false, Process.myUid(), PROCESS_STATE_UNKNOWN,
                        null));
        assertNull(mAms.getStickyBroadcastsForTest(TEST_ACTION2, TEST_USER));
        assertNull(mAms.getStickyBroadcastsForTest(TEST_ACTION3, TEST_USER));

        broadcastIntent(intent2, options.toBundle(), true);
        assertStickyBroadcasts(mAms.getStickyBroadcastsForTest(TEST_ACTION1, TEST_USER),
                StickyBroadcast.create(intent1, false, Process.myUid(), PROCESS_STATE_UNKNOWN));
                StickyBroadcast.create(intent1, false, Process.myUid(), PROCESS_STATE_UNKNOWN,
                        null));
        assertStickyBroadcasts(mAms.getStickyBroadcastsForTest(TEST_ACTION2, TEST_USER),
                StickyBroadcast.create(intent2, true, Process.myUid(), PROCESS_STATE_UNKNOWN));
                StickyBroadcast.create(intent2, true, Process.myUid(), PROCESS_STATE_UNKNOWN,
                        null));
        assertNull(mAms.getStickyBroadcastsForTest(TEST_ACTION3, TEST_USER));

        broadcastIntent(intent3, null, true);
        assertStickyBroadcasts(mAms.getStickyBroadcastsForTest(TEST_ACTION1, TEST_USER),
                StickyBroadcast.create(intent1, false, Process.myUid(), PROCESS_STATE_UNKNOWN));
                StickyBroadcast.create(intent1, false, Process.myUid(), PROCESS_STATE_UNKNOWN,
                        null));
        assertStickyBroadcasts(mAms.getStickyBroadcastsForTest(TEST_ACTION2, TEST_USER),
                StickyBroadcast.create(intent2, true, Process.myUid(), PROCESS_STATE_UNKNOWN));
                StickyBroadcast.create(intent2, true, Process.myUid(), PROCESS_STATE_UNKNOWN,
                        null));
        assertStickyBroadcasts(mAms.getStickyBroadcastsForTest(TEST_ACTION3, TEST_USER),
                StickyBroadcast.create(intent3, false, Process.myUid(), PROCESS_STATE_UNKNOWN));
                StickyBroadcast.create(intent3, false, Process.myUid(), PROCESS_STATE_UNKNOWN,
                        null));
    }

    @RequiresFlagsEnabled(FLAG_AVOID_RESOLVING_TYPE)
    @Test
    @SuppressWarnings("GuardedBy")
    public void testBroadcastStickyIntent_verifyTypeNotResolved() throws Exception {
        final Intent intent = new Intent(TEST_ACTION1);
        final Uri uri = new Uri.Builder()
                .scheme(SCHEME_CONTENT)
                .authority(TEST_AUTHORITY)
                .path("green")
                .build();
        intent.setData(uri);
        broadcastIntent(intent, null, true, TEST_MIME_TYPE, USER_ALL);
        assertStickyBroadcasts(mAms.getStickyBroadcastsForTest(TEST_ACTION1, USER_ALL),
                StickyBroadcast.create(intent, false, Process.myUid(), PROCESS_STATE_UNKNOWN,
                        TEST_MIME_TYPE));
        when(mContentResolver.getType(uri)).thenReturn(TEST_MIME_TYPE);

        addUidRecord(TEST_UID, TEST_PACKAGE);
        final ProcessRecord procRecord = mAms.getProcessRecordLocked(TEST_PACKAGE, TEST_UID);
        final IntentFilter intentFilter = new IntentFilter(TEST_ACTION1);
        intentFilter.addDataType(TEST_MIME_TYPE);
        final Intent resultIntent = mAms.registerReceiverWithFeature(procRecord.getThread(),
                TEST_PACKAGE, null, null, null, intentFilter, null, TEST_USER,
                Context.RECEIVER_EXPORTED);
        assertNotNull(resultIntent);
        verify(mContentResolver, never()).getType(any());
    }

    @SuppressWarnings("GuardedBy")
    private void broadcastIntent(Intent intent, Bundle options, boolean sticky) {
        final int res = mAms.broadcastIntentLocked(null, null, null, intent, null, null, 0,
        broadcastIntent(intent, options, sticky, null, TEST_USER);
    }

    @SuppressWarnings("GuardedBy")
    private void broadcastIntent(Intent intent, Bundle options, boolean sticky,
            String resolvedType, int userId) {
        final int res = mAms.broadcastIntentLocked(null, null, null, intent, resolvedType, null, 0,
                null, null, null, null, null, 0, options, false, sticky,
                Process.myPid(), Process.myUid(), Process.myUid(), Process.myPid(), TEST_USER);
                Process.myPid(), Process.myUid(), Process.myUid(), Process.myPid(), userId);
        assertEquals(ActivityManager.BROADCAST_SUCCESS, res);
    }

@@ -930,6 +991,9 @@ public class ActivityManagerServiceTest {
        if (a.originalCallingUid != b.originalCallingUid) {
            return false;
        }
        if (!Objects.equals(a.resolvedDataType, b.resolvedDataType)) {
            return false;
        }
        return true;
    }

@@ -1460,6 +1524,20 @@ public class ActivityManagerServiceTest {
        }
    }

    private static class TestContext extends ContextWrapper {
        private final ContentResolver mContentResolver;

        TestContext(Context context, ContentResolver contentResolver) {
            super(context);
            mContentResolver = contentResolver;
        }

        @Override
        public ContentResolver getContentResolver() {
            return mContentResolver;
        }
    }

    // TODO: [b/302724778] Remove manual JNI load
    static {
        System.loadLibrary("mockingservicestestjni");