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

Commit c234eec8 authored by lpeter's avatar lpeter
Browse files

Limit sending of the PACKAGE_CHANGED broadcast

Limit sending of the PACKAGE_CHANGED broadcast to only the system
and the application itself when the component is not exported.

Flag: android.content.pm.reduce_broadcasts_for_component_state_changes

Bug: 292261144
Test: atest PackageChangeBroadcastTest
Change-Id: If64e9f214e8346d5b5c6607f562e39ef23e4ff27
parent d3e0fbc2
Loading
Loading
Loading
Loading
+5 −1
Original line number Original line Diff line number Diff line
@@ -8535,10 +8535,14 @@
        @hide
        @hide
    -->
    -->
    <permission
    <permission
        android:name="android.permission.RECEIVE_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED"
        android:name="android.permission.INTERNAL_RECEIVE_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED"
        android:protectionLevel="internal"
        android:protectionLevel="internal"
        android:featureFlag="android.content.pm.reduce_broadcasts_for_component_state_changes"/>
        android:featureFlag="android.content.pm.reduce_broadcasts_for_component_state_changes"/>


    <uses-permission
        android:name="android.permission.INTERNAL_RECEIVE_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED"
        android:featureFlag="android.content.pm.reduce_broadcasts_for_component_state_changes"/>

    <!-- Attribution for Geofencing service. -->
    <!-- Attribution for Geofencing service. -->
    <attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
    <attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
    <!-- Attribution for Country Detector. -->
    <!-- Attribution for Country Detector. -->
+100 −6
Original line number Original line Diff line number Diff line
@@ -64,6 +64,9 @@ import android.util.Pair;
import android.util.Slog;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseArray;


import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.component.ParsedProvider;
import com.android.internal.pm.pkg.component.ParsedService;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.AndroidPackage;
@@ -80,6 +83,8 @@ import java.util.function.BiFunction;
 */
 */
public final class BroadcastHelper {
public final class BroadcastHelper {
    private static final boolean DEBUG_BROADCASTS = false;
    private static final boolean DEBUG_BROADCASTS = false;
    private static final String PERMISSION_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED =
            "android.permission.INTERNAL_RECEIVE_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED";


    private final UserManagerInternal mUmInternal;
    private final UserManagerInternal mUmInternal;
    private final ActivityManagerInternal mAmInternal;
    private final ActivityManagerInternal mAmInternal;
@@ -291,6 +296,57 @@ public final class BroadcastHelper {
        return bOptions;
        return bOptions;
    }
    }


    private ArrayList<String> getAllNotExportedComponents(@NonNull AndroidPackage pkg,
            @NonNull ArrayList<String> inputComponentNames) {
        final ArrayList<String> outputNotExportedComponentNames = new ArrayList<>();
        int remainingComponentCount = inputComponentNames.size();
        for (ParsedActivity component : pkg.getReceivers()) {
            if (inputComponentNames.contains(component.getClassName())) {
                if (!component.isExported()) {
                    outputNotExportedComponentNames.add(component.getClassName());
                }
                remainingComponentCount--;
                if (remainingComponentCount <= 0) {
                    return outputNotExportedComponentNames;
                }
            }
        }
        for (ParsedProvider component : pkg.getProviders()) {
            if (inputComponentNames.contains(component.getClassName())) {
                if (!component.isExported()) {
                    outputNotExportedComponentNames.add(component.getClassName());
                }
                remainingComponentCount--;
                if (remainingComponentCount <= 0) {
                    return outputNotExportedComponentNames;
                }
            }
        }
        for (ParsedService component : pkg.getServices()) {
            if (inputComponentNames.contains(component.getClassName())) {
                if (!component.isExported()) {
                    outputNotExportedComponentNames.add(component.getClassName());
                }
                remainingComponentCount--;
                if (remainingComponentCount <= 0) {
                    return outputNotExportedComponentNames;
                }
            }
        }
        for (ParsedActivity component : pkg.getActivities()) {
            if (inputComponentNames.contains(component.getClassName())) {
                if (!component.isExported()) {
                    outputNotExportedComponentNames.add(component.getClassName());
                }
                remainingComponentCount--;
                if (remainingComponentCount <= 0) {
                    return outputNotExportedComponentNames;
                }
            }
        }
        return outputNotExportedComponentNames;
    }

    private void sendPackageChangedBroadcastInternal(@NonNull String packageName,
    private void sendPackageChangedBroadcastInternal(@NonNull String packageName,
            boolean dontKillApp,
            boolean dontKillApp,
            @NonNull ArrayList<String> componentNames,
            @NonNull ArrayList<String> componentNames,
@@ -298,10 +354,48 @@ public final class BroadcastHelper {
            @Nullable String reason,
            @Nullable String reason,
            @Nullable int[] userIds,
            @Nullable int[] userIds,
            @Nullable int[] instantUserIds,
            @Nullable int[] instantUserIds,
            @Nullable SparseArray<int[]> broadcastAllowList) {
            @Nullable SparseArray<int[]> broadcastAllowList,
            @NonNull AndroidPackage pkg) {
        final boolean isForWholeApp = componentNames.contains(packageName);
        if (isForWholeApp || !android.content.pm.Flags.reduceBroadcastsForComponentStateChanges()) {
            sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp, componentNames,
            sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp, componentNames,
                    packageUid, reason, userIds, instantUserIds, broadcastAllowList,
                    packageUid, reason, userIds, instantUserIds, broadcastAllowList,
                    null /* targetPackageName */, null /* requiredPermissions */);
                    null /* targetPackageName */, null /* requiredPermissions */);
            return;
        }
        // Currently only these four components of activity, receiver, provider and service are
        // considered to send only the broadcast to the system and the application itself when the
        // component is not exported. In order to avoid losing to send the broadcast for other
        // components, it gets the not exported components for these four components of activity,
        // receiver, provider and service and the others are considered the exported components.
        final ArrayList<String> notExportedComponentNames = getAllNotExportedComponents(pkg,
                componentNames);
        final ArrayList<String> exportedComponentNames = (ArrayList<String>) componentNames.clone();
        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.

            // First, send the PACKAGE_CHANGED broadcast to the system.
            sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp,
                    notExportedComponentNames, packageUid, reason, userIds, instantUserIds,
                    broadcastAllowList, "android" /* targetPackageName */,
                    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 */);
        }

        if (!exportedComponentNames.isEmpty()) {
            sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp,
                    exportedComponentNames, packageUid, reason, userIds, instantUserIds,
                    broadcastAllowList, null /* targetPackageName */,
                    null /* requiredPermissions */);
        }
    }
    }


    private void sendPackageChangedBroadcastWithPermissions(@NonNull String packageName,
    private void sendPackageChangedBroadcastWithPermissions(@NonNull String packageName,
@@ -830,7 +924,7 @@ public final class BroadcastHelper {
                                     @NonNull String reason) {
                                     @NonNull String reason) {
        PackageStateInternal setting = snapshot.getPackageStateInternal(packageName,
        PackageStateInternal setting = snapshot.getPackageStateInternal(packageName,
                Process.SYSTEM_UID);
                Process.SYSTEM_UID);
        if (setting == null) {
        if (setting == null || setting.getPkg() == null) {
            return;
            return;
        }
        }
        final int userId = UserHandle.getUserId(packageUid);
        final int userId = UserHandle.getUserId(packageUid);
@@ -842,7 +936,7 @@ public final class BroadcastHelper {
                isInstantApp ? null : snapshot.getVisibilityAllowLists(packageName, userIds);
                isInstantApp ? null : snapshot.getVisibilityAllowLists(packageName, userIds);
        mHandler.post(() -> sendPackageChangedBroadcastInternal(
        mHandler.post(() -> sendPackageChangedBroadcastInternal(
                packageName, dontKillApp, componentNames, packageUid, reason, userIds,
                packageName, dontKillApp, componentNames, packageUid, reason, userIds,
                instantUserIds, broadcastAllowList));
                instantUserIds, broadcastAllowList, setting.getPkg()));
        mPackageMonitorCallbackHelper.notifyPackageChanged(packageName, dontKillApp, componentNames,
        mPackageMonitorCallbackHelper.notifyPackageChanged(packageName, dontKillApp, componentNames,
                packageUid, reason, userIds, instantUserIds, broadcastAllowList, mHandler);
                packageUid, reason, userIds, instantUserIds, broadcastAllowList, mHandler);
    }
    }