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

Commit 8e049518 authored by Peter Li's avatar Peter Li Committed by Android (Google) Code Review
Browse files

Merge "Apps that share the same UID should also receive the PACKAGE_CHANGED broadcast" into main

parents 36a582e2 4e903d6c
Loading
Loading
Loading
Loading
+27 −8
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.provider.DeviceConfig;
import android.stats.storage.StorageEnums;
import android.text.TextUtils;
import android.util.IntArray;
import android.util.Log;
import android.util.Pair;
@@ -355,7 +356,8 @@ public final class BroadcastHelper {
            @Nullable int[] userIds,
            @Nullable int[] instantUserIds,
            @Nullable SparseArray<int[]> broadcastAllowList,
            @NonNull AndroidPackage pkg) {
            @NonNull AndroidPackage pkg,
            @NonNull String[] sharedUidPackages) {
        final boolean isForWholeApp = componentNames.contains(packageName);
        if (isForWholeApp || !android.content.pm.Flags.reduceBroadcastsForComponentStateChanges()) {
            sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp, componentNames,
@@ -374,20 +376,36 @@ public final class BroadcastHelper {
        exportedComponentNames.removeAll(notExportedComponentNames);

        if (!notExportedComponentNames.isEmpty()) {
            // Limit sending of the PACKAGE_CHANGED broadcast to only the system and the
            // application itself when the component is not exported.
            // Limit sending of the PACKAGE_CHANGED broadcast to only the system, the application
            // itself and applications with the same UID when the component is not exported.

            // First, send the PACKAGE_CHANGED broadcast to the system.
            if (!TextUtils.equals(packageName, "android")) {
                sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp,
                        notExportedComponentNames, packageUid, reason, userIds, instantUserIds,
                        broadcastAllowList, "android" /* targetPackageName */,
                    new String[]{PERMISSION_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED});
                        new String[]{
                                PERMISSION_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED});
            }

            // Second, send the PACKAGE_CHANGED broadcast to the application itself.
            sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp,
                    notExportedComponentNames, packageUid, reason, userIds, instantUserIds,
                    broadcastAllowList, packageName /* targetPackageName */,
                    null /* requiredPermissions */);

            // Third, send the PACKAGE_CHANGED broadcast to the applications with the same UID.
            for (int i = 0; i < sharedUidPackages.length; i++) {
                final String sharedPackage = sharedUidPackages[i];
                if (TextUtils.equals(packageName, sharedPackage)) {
                    continue;
                }
                sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp,
                        notExportedComponentNames, packageUid, reason, userIds, instantUserIds,
                        broadcastAllowList, sharedPackage /* targetPackageName */,
                        null /* requiredPermissions */);
            }

        }

        if (!exportedComponentNames.isEmpty()) {
@@ -936,7 +954,8 @@ public final class BroadcastHelper {
                isInstantApp ? null : snapshot.getVisibilityAllowLists(packageName, userIds);
        mHandler.post(() -> sendPackageChangedBroadcastInternal(
                packageName, dontKillApp, componentNames, packageUid, reason, userIds,
                instantUserIds, broadcastAllowList, setting.getPkg()));
                instantUserIds, broadcastAllowList, setting.getPkg(),
                snapshot.getSharedUserPackagesForPackage(packageName, userId)));
        mPackageMonitorCallbackHelper.notifyPackageChanged(packageName, dontKillApp, componentNames,
                packageUid, reason, userIds, instantUserIds, broadcastAllowList, mHandler);
    }
+47 −4
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@@ -60,6 +61,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.ArrayList;
import java.util.List;

@AppModeFull
@AppModeNonSdkSandbox
@@ -124,7 +126,8 @@ public class BroadcastHelperTest {
    @Test
    public void changeNonExportedComponent_sendPackageChangedBroadcastToSystem_withPermission()
            throws Exception {
        changeComponentAndSendPackageChangedBroadcast(false /* changeExportedComponent */);
        changeComponentAndSendPackageChangedBroadcast(false /* changeExportedComponent */,
                new String[0] /* sharedPackages */);

        ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
        verify(mMockActivityManagerInternal).broadcastIntentWithCallback(
@@ -140,7 +143,8 @@ public class BroadcastHelperTest {
    @Test
    public void changeNonExportedComponent_sendPackageChangedBroadcastToApplicationItself()
            throws Exception {
        changeComponentAndSendPackageChangedBroadcast(false /* changeExportedComponent */);
        changeComponentAndSendPackageChangedBroadcast(false /* changeExportedComponent */,
                new String[0] /* sharedPackages */);

        ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
        verify(mMockActivityManagerInternal).broadcastIntentWithCallback(captor.capture(), eq(null),
@@ -150,9 +154,45 @@ public class BroadcastHelperTest {
        assertThat(intent.getPackage()).isEqualTo(PACKAGE_CHANGED_TEST_PACKAGE_NAME);
    }

    @RequiresFlagsEnabled(FLAG_REDUCE_BROADCASTS_FOR_COMPONENT_STATE_CHANGES)
    @Test
    public void changeNonExportedComponent_sendPackageChangedBroadcastToSharedUserIdApplications()
            throws Exception {
        changeComponentAndSendPackageChangedBroadcast(false /* changeExportedComponent */,
                new String[]{"shared.package"} /* sharedPackages */);

        ArgumentCaptor<Intent> captorIntent = ArgumentCaptor.forClass(Intent.class);
        ArgumentCaptor<String[]> captorRequiredPermissions = ArgumentCaptor.forClass(
                String[].class);
        verify(mMockActivityManagerInternal, times(3)).broadcastIntentWithCallback(
                captorIntent.capture(), eq(null), captorRequiredPermissions.capture(), anyInt(),
                eq(null), eq(null), eq(null));
        List<Intent> intents = captorIntent.getAllValues();
        List<String[]> requiredPermissions = captorRequiredPermissions.getAllValues();
        assertNotNull(intents);
        assertThat(intents.size()).isEqualTo(3);

        final Intent intent1 = intents.get(0);
        final String[] requiredPermission1 = requiredPermissions.get(0);
        assertThat(intent1.getPackage()).isEqualTo("android");
        assertThat(requiredPermission1).isEqualTo(
                new String[]{PERMISSION_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED});

        final Intent intent2 = intents.get(1);
        final String[] requiredPermission2 = requiredPermissions.get(1);
        assertThat(intent2.getPackage()).isEqualTo(PACKAGE_CHANGED_TEST_PACKAGE_NAME);
        assertThat(requiredPermission2).isNull();

        final Intent intent3 = intents.get(2);
        final String[] requiredPermission3 = requiredPermissions.get(2);
        assertThat(intent3.getPackage()).isEqualTo("shared.package");
        assertThat(requiredPermission3).isNull();
    }

    @Test
    public void changeExportedComponent_sendPackageChangedBroadcastToAll() throws Exception {
        changeComponentAndSendPackageChangedBroadcast(true /* changeExportedComponent */);
        changeComponentAndSendPackageChangedBroadcast(true /* changeExportedComponent */,
                new String[0] /* sharedPackages */);

        ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
        verify(mMockActivityManagerInternal).broadcastIntentWithCallback(captor.capture(), eq(null),
@@ -162,11 +202,14 @@ public class BroadcastHelperTest {
        assertNull(intent.getPackage());
    }

    private void changeComponentAndSendPackageChangedBroadcast(boolean changeExportedComponent) {
    private void changeComponentAndSendPackageChangedBroadcast(boolean changeExportedComponent,
            String[] sharedPackages) {
        when(mMockSnapshot.getPackageStateInternal(eq(PACKAGE_CHANGED_TEST_PACKAGE_NAME),
                anyInt())).thenReturn(mMockPackageStateInternal);
        when(mMockSnapshot.isInstantAppInternal(any(), anyInt(), anyInt())).thenReturn(false);
        when(mMockSnapshot.getVisibilityAllowLists(any(), any())).thenReturn(null);
        when(mMockSnapshot.getSharedUserPackagesForPackage(eq(PACKAGE_CHANGED_TEST_PACKAGE_NAME),
                anyInt())).thenReturn(sharedPackages);
        when(mMockPackageStateInternal.getPkg()).thenReturn(mMockAndroidPackageInternal);

        when(mMockParsedActivity.getClassName()).thenReturn(