Loading core/res/AndroidManifest.xml +5 −1 Original line number Diff line number Diff line Loading @@ -8535,10 +8535,14 @@ @hide --> <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: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 android:tag="GeofencingService" android:label="@string/geofencing_service"/> <!-- Attribution for Country Detector. --> Loading services/core/java/com/android/server/pm/BroadcastHelper.java +100 −6 Original line number Diff line number Diff line Loading @@ -64,6 +64,9 @@ import android.util.Pair; import android.util.Slog; 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.FrameworkStatsLog; import com.android.server.pm.pkg.AndroidPackage; Loading @@ -80,6 +83,8 @@ import java.util.function.BiFunction; */ public final class BroadcastHelper { 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 ActivityManagerInternal mAmInternal; Loading Loading @@ -291,6 +296,57 @@ public final class BroadcastHelper { 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, boolean dontKillApp, @NonNull ArrayList<String> componentNames, Loading @@ -298,10 +354,48 @@ public final class BroadcastHelper { @Nullable String reason, @Nullable int[] userIds, @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, packageUid, reason, userIds, instantUserIds, broadcastAllowList, 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, Loading Loading @@ -830,7 +924,7 @@ public final class BroadcastHelper { @NonNull String reason) { PackageStateInternal setting = snapshot.getPackageStateInternal(packageName, Process.SYSTEM_UID); if (setting == null) { if (setting == null || setting.getPkg() == null) { return; } final int userId = UserHandle.getUserId(packageUid); Loading @@ -842,7 +936,7 @@ public final class BroadcastHelper { isInstantApp ? null : snapshot.getVisibilityAllowLists(packageName, userIds); mHandler.post(() -> sendPackageChangedBroadcastInternal( packageName, dontKillApp, componentNames, packageUid, reason, userIds, instantUserIds, broadcastAllowList)); instantUserIds, broadcastAllowList, setting.getPkg())); mPackageMonitorCallbackHelper.notifyPackageChanged(packageName, dontKillApp, componentNames, packageUid, reason, userIds, instantUserIds, broadcastAllowList, mHandler); } Loading Loading
core/res/AndroidManifest.xml +5 −1 Original line number Diff line number Diff line Loading @@ -8535,10 +8535,14 @@ @hide --> <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: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 android:tag="GeofencingService" android:label="@string/geofencing_service"/> <!-- Attribution for Country Detector. --> Loading
services/core/java/com/android/server/pm/BroadcastHelper.java +100 −6 Original line number Diff line number Diff line Loading @@ -64,6 +64,9 @@ import android.util.Pair; import android.util.Slog; 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.FrameworkStatsLog; import com.android.server.pm.pkg.AndroidPackage; Loading @@ -80,6 +83,8 @@ import java.util.function.BiFunction; */ public final class BroadcastHelper { 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 ActivityManagerInternal mAmInternal; Loading Loading @@ -291,6 +296,57 @@ public final class BroadcastHelper { 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, boolean dontKillApp, @NonNull ArrayList<String> componentNames, Loading @@ -298,10 +354,48 @@ public final class BroadcastHelper { @Nullable String reason, @Nullable int[] userIds, @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, packageUid, reason, userIds, instantUserIds, broadcastAllowList, 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, Loading Loading @@ -830,7 +924,7 @@ public final class BroadcastHelper { @NonNull String reason) { PackageStateInternal setting = snapshot.getPackageStateInternal(packageName, Process.SYSTEM_UID); if (setting == null) { if (setting == null || setting.getPkg() == null) { return; } final int userId = UserHandle.getUserId(packageUid); Loading @@ -842,7 +936,7 @@ public final class BroadcastHelper { isInstantApp ? null : snapshot.getVisibilityAllowLists(packageName, userIds); mHandler.post(() -> sendPackageChangedBroadcastInternal( packageName, dontKillApp, componentNames, packageUid, reason, userIds, instantUserIds, broadcastAllowList)); instantUserIds, broadcastAllowList, setting.getPkg())); mPackageMonitorCallbackHelper.notifyPackageChanged(packageName, dontKillApp, componentNames, packageUid, reason, userIds, instantUserIds, broadcastAllowList, mHandler); } Loading