Merge changes from topic "reduce_broadcast_intent" into main

* changes:
  Add a new feature flag and a new permission
  Refactor BroadcastHelper to pass requiredPermissions parameter.
diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig
index 52d7333..5b38942 100644
--- a/core/java/android/content/pm/flags.aconfig
+++ b/core/java/android/content/pm/flags.aconfig
@@ -334,3 +334,11 @@
     bug: "364771256"
     is_fixed_read_only: true
 }
+
+flag {
+    name: "reduce_broadcasts_for_component_state_changes"
+    namespace: "package_manager_service"
+    description: "Feature flag to limit sending of the PACKAGE_CHANGED broadcast to only the system and the application itself during component state changes."
+    bug: "292261144"
+    is_fixed_read_only: true
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5693d66..5522aa0 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -8479,6 +8479,18 @@
         android:protectionLevel="internal"
         android:featureFlag="android.content.pm.verification_service" />
 
+    <!--
+        This permission allows the system to receive PACKAGE_CHANGED broadcasts when the component
+        state of a non-exported component has been changed.
+        <p>Not for use by third-party applications. </p>
+        <p>Protection level: internal
+        @hide
+    -->
+    <permission
+        android:name="android.permission.RECEIVE_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED"
+        android:protectionLevel="internal"
+        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. -->
diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java
index 369029ad..84a5f2b 100644
--- a/services/core/java/com/android/server/pm/BroadcastHelper.java
+++ b/services/core/java/com/android/server/pm/BroadcastHelper.java
@@ -80,11 +80,6 @@
  */
 public final class BroadcastHelper {
     private static final boolean DEBUG_BROADCASTS = false;
-    /**
-     * Permissions required in order to receive instant application lifecycle broadcasts.
-     */
-    private static final String[] INSTANT_APP_BROADCAST_PERMISSION =
-            new String[]{android.Manifest.permission.ACCESS_INSTANT_APPS};
 
     private final UserManagerInternal mUmInternal;
     private final ActivityManagerInternal mAmInternal;
@@ -115,7 +110,7 @@
         SparseArray<int[]> broadcastAllowList = new SparseArray<>();
         broadcastAllowList.put(userId, visibilityAllowList);
         broadcastIntent(intent, finishedReceiver, isInstantApp, userId, broadcastAllowList,
-                filterExtrasForReceiver, bOptions);
+                filterExtrasForReceiver, bOptions, null /* requiredPermissions */);
     }
 
     void sendPackageBroadcast(final String action, final String pkg, final Bundle extras,
@@ -123,7 +118,7 @@
             final int[] userIds, int[] instantUserIds,
             @Nullable SparseArray<int[]> broadcastAllowList,
             @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver,
-            @Nullable Bundle bOptions) {
+            @Nullable Bundle bOptions, @Nullable String[] requiredPermissions) {
         try {
             final IActivityManager am = ActivityManager.getService();
             if (am == null) return;
@@ -137,12 +132,12 @@
             if (ArrayUtils.isEmpty(instantUserIds)) {
                 doSendBroadcast(action, pkg, extras, flags, targetPkg, finishedReceiver,
                         resolvedUserIds, false /* isInstantApp */, broadcastAllowList,
-                        filterExtrasForReceiver, bOptions);
+                        filterExtrasForReceiver, bOptions, requiredPermissions);
             } else {
                 // send restricted broadcasts for instant apps
                 doSendBroadcast(action, pkg, extras, flags, targetPkg, finishedReceiver,
-                        instantUserIds, true /* isInstantApp */, null,
-                        null /* filterExtrasForReceiver */, bOptions);
+                        instantUserIds, true /* isInstantApp */, null /* broadcastAllowList */,
+                        null /* filterExtrasForReceiver */, bOptions, requiredPermissions);
             }
         } catch (RemoteException ex) {
         }
@@ -166,7 +161,8 @@
             boolean isInstantApp,
             @Nullable SparseArray<int[]> broadcastAllowList,
             @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver,
-            @Nullable Bundle bOptions) {
+            @Nullable Bundle bOptions,
+            @Nullable String[] requiredPermissions) {
         for (int userId : userIds) {
             final Intent intent = new Intent(action,
                     pkg != null ? Uri.fromParts(PACKAGE_SCHEME, pkg, null) : null);
@@ -189,17 +185,18 @@
             intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | flags);
             broadcastIntent(intent, finishedReceiver, isInstantApp, userId, broadcastAllowList,
-                    filterExtrasForReceiver, bOptions);
+                    filterExtrasForReceiver, bOptions, requiredPermissions);
         }
     }
 
-
     private void broadcastIntent(Intent intent, IIntentReceiver finishedReceiver,
             boolean isInstantApp, int userId, @Nullable SparseArray<int[]> broadcastAllowList,
             @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver,
-            @Nullable Bundle bOptions) {
-        final String[] requiredPermissions =
-                isInstantApp ? INSTANT_APP_BROADCAST_PERMISSION : null;
+            @Nullable Bundle bOptions, @Nullable String[] requiredPermissions) {
+        if (isInstantApp) {
+            requiredPermissions = ArrayUtils.appendElement(String.class, requiredPermissions,
+                    android.Manifest.permission.ACCESS_INSTANT_APPS);
+        }
         if (DEBUG_BROADCASTS) {
             RuntimeException here = new RuntimeException("here");
             here.fillInStackTrace();
@@ -234,7 +231,7 @@
                 null /* instantUserIds */, null /* broadcastAllowList */,
                 (callingUid, intentExtras) -> filterExtrasChangedPackageList(
                         snapshot, callingUid, intentExtras),
-                null /* bOptions */);
+                null /* bOptions */, null /* requiredPermissions */);
     }
 
     /**
@@ -294,14 +291,29 @@
         return bOptions;
     }
 
-    private void sendPackageChangedBroadcast(@NonNull String packageName,
-                                             boolean dontKillApp,
-                                             @NonNull ArrayList<String> componentNames,
-                                             int packageUid,
-                                             @Nullable String reason,
-                                             @Nullable int[] userIds,
-                                             @Nullable int[] instantUserIds,
-                                             @Nullable SparseArray<int[]> broadcastAllowList) {
+    private void sendPackageChangedBroadcastInternal(@NonNull String packageName,
+            boolean dontKillApp,
+            @NonNull ArrayList<String> componentNames,
+            int packageUid,
+            @Nullable String reason,
+            @Nullable int[] userIds,
+            @Nullable int[] instantUserIds,
+            @Nullable SparseArray<int[]> broadcastAllowList) {
+        sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp, componentNames,
+                packageUid, reason, userIds, instantUserIds, broadcastAllowList,
+                null /* targetPackageName */, null /* requiredPermissions */);
+    }
+
+    private void sendPackageChangedBroadcastWithPermissions(@NonNull String packageName,
+            boolean dontKillApp,
+            @NonNull ArrayList<String> componentNames,
+            int packageUid,
+            @Nullable String reason,
+            @Nullable int[] userIds,
+            @Nullable int[] instantUserIds,
+            @Nullable SparseArray<int[]> broadcastAllowList,
+            @Nullable String targetPackageName,
+            @Nullable String[] requiredPermissions) {
         if (DEBUG_INSTALL) {
             Log.v(TAG, "Sending package changed: package=" + packageName + " components="
                     + componentNames);
@@ -321,9 +333,10 @@
         // little component state change.
         final int flags = !componentNames.contains(packageName)
                 ? Intent.FLAG_RECEIVER_REGISTERED_ONLY : 0;
-        sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, flags, null, null,
-                userIds, instantUserIds, broadcastAllowList, null /* filterExtrasForReceiver */,
-                null /* bOptions */);
+        sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, flags,
+                targetPackageName, null /* finishedReceiver */, userIds, instantUserIds,
+                broadcastAllowList, null /* filterExtrasForReceiver */, null /* bOptions */,
+                requiredPermissions);
     }
 
     static void sendDeviceCustomizationReadyBroadcast() {
@@ -680,7 +693,8 @@
 
         sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
                 packageName, extras, 0, null, null, userIds, instantUserIds,
-                broadcastAllowlist, null /* filterExtrasForReceiver */, null);
+                broadcastAllowlist, null /* filterExtrasForReceiver */, null /* bOptions */,
+                null /* requiredPermissions */);
         // Send to PermissionController for all new users, even if it may not be running for some
         // users
         if (isPrivacySafetyLabelChangeNotificationsEnabled(mContext)) {
@@ -688,7 +702,8 @@
                     packageName, extras, 0,
                     mContext.getPackageManager().getPermissionControllerPackageName(),
                     null, userIds, instantUserIds,
-                    broadcastAllowlist, null /* filterExtrasForReceiver */, null);
+                    broadcastAllowlist, null /* filterExtrasForReceiver */, null /* bOptions */,
+                    null /* requiredPermissions */);
         }
     }
 
@@ -719,7 +734,8 @@
             int[] userIds, int[] instantUserIds) {
         sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, pkgName, null, 0,
                 installerPkg, null, userIds, instantUserIds, null /* broadcastAllowList */,
-                null /* filterExtrasForReceiver */, null);
+                null /* filterExtrasForReceiver */, null /* bOptions */,
+                null /* requiredPermissions */);
     }
 
     /**
@@ -824,7 +840,7 @@
         final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY;
         final SparseArray<int[]> broadcastAllowList =
                 isInstantApp ? null : snapshot.getVisibilityAllowLists(packageName, userIds);
-        mHandler.post(() -> sendPackageChangedBroadcast(
+        mHandler.post(() -> sendPackageChangedBroadcastInternal(
                 packageName, dontKillApp, componentNames, packageUid, reason, userIds,
                 instantUserIds, broadcastAllowList));
         mPackageMonitorCallbackHelper.notifyPackageChanged(packageName, dontKillApp, componentNames,
@@ -843,7 +859,7 @@
                                                @Nullable Bundle bOptions) {
         mHandler.post(() -> sendPackageBroadcast(action, pkg, extras, flags,
                 targetPkg, finishedReceiver, userIds, instantUserIds, broadcastAllowList,
-                null /* filterExtrasForReceiver */, bOptions));
+                null /* filterExtrasForReceiver */, bOptions, null /* requiredPermissions */));
         if (targetPkg == null) {
             // For some broadcast action, e.g. ACTION_PACKAGE_ADDED, this method will be called
             // many times to different targets, e.g. installer app, permission controller, other
@@ -1014,7 +1030,7 @@
                 extras, flags, null /* targetPkg */, null /* finishedReceiver */,
                 new int[]{userId}, null /* instantUserIds */, null /* broadcastAllowList */,
                 filterExtrasForReceiver,
-                options));
+                options, null /* requiredPermissions */));
         notifyPackageMonitor(intent, null /* pkg */, extras, new int[]{userId},
                 null /* instantUserIds */, null /* broadcastAllowList */, filterExtrasForReceiver);
     }
@@ -1046,9 +1062,12 @@
                 } else {
                     intentExtras = null;
                 }
-                doSendBroadcast(action, null, intentExtras,
-                        Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, packageName, null,
-                        targetUserIds, false, null, null, null);
+                doSendBroadcast(action, null /* pkg */, intentExtras,
+                        Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, packageName,
+                        null /* finishedReceiver */,
+                        targetUserIds, false /* isInstantApp */, null /* broadcastAllowList */,
+                        null /* filterExtrasForReceiver */, null /* bOptions */,
+                        null /* requiredPermissions */);
             }
         });
     }
@@ -1077,7 +1096,7 @@
                 null /* broadcastAllowList */,
                 (callingUid, intentExtras) -> filterExtrasChangedPackageList(
                         snapshot, callingUid, intentExtras),
-                null /* bOptions */));
+                null /* bOptions */, null /* requiredPermissions */));
     }
 
     void sendResourcesChangedBroadcastAndNotify(@NonNull Computer snapshot,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4557769..d78f122 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4709,10 +4709,11 @@
                 extras.putLong(Intent.EXTRA_TIME, SystemClock.elapsedRealtime());
                 mHandler.post(() -> {
                     mBroadcastHelper.sendPackageBroadcast(Intent.ACTION_PACKAGE_UNSTOPPED,
-                            packageName, extras,
-                            Intent.FLAG_RECEIVER_REGISTERED_ONLY, null, null,
-                            userIds, null, broadcastAllowList, null,
-                            null);
+                            packageName, extras, Intent.FLAG_RECEIVER_REGISTERED_ONLY,
+                            null /* targetPkg */, null /* finishedReceiver */, userIds,
+                            null /* instantUserIds */, broadcastAllowList,
+                            null /* filterExtrasForReceiver */, null /* bOptions */,
+                            null /* requiredPermissions */);
                 });
                 mPackageMonitorCallbackHelper.notifyPackageMonitor(Intent.ACTION_PACKAGE_UNSTOPPED,
                         packageName, extras, userIds, null /* instantUserIds */,
@@ -7169,17 +7170,17 @@
                 // Sent async using the PM handler, to maintain ordering with PACKAGE_UNSTOPPED
                 mHandler.post(() -> {
                     mBroadcastHelper.sendPackageBroadcast(Intent.ACTION_PACKAGE_RESTARTED,
-                            packageName, extras,
-                            flags, null, null,
-                            userIds, null, broadcastAllowList, null,
-                            null);
+                            packageName, extras, flags, null /* targetPkg */,
+                            null /* finishedReceiver */, userIds, null /* instantUserIds */,
+                            broadcastAllowList, null /* filterExtrasForReceiver */,
+                            null /* bOptions */, null /* requiredPermissions */);
                 });
             } else {
                 mBroadcastHelper.sendPackageBroadcast(Intent.ACTION_PACKAGE_RESTARTED,
-                        packageName, extras,
-                        flags, null, null,
-                        userIds, null, broadcastAllowList, null,
-                        null);
+                        packageName, extras, flags, null /* targetPkg */,
+                        null /* finishedReceiver */, userIds, null /* instantUserIds */,
+                        broadcastAllowList, null /* filterExtrasForReceiver */, null /* bOptions */,
+                        null /* requiredPermissions */);
             }
             mPackageMonitorCallbackHelper.notifyPackageMonitor(Intent.ACTION_PACKAGE_RESTARTED,
                     packageName, extras, userIds, null /* instantUserIds */,
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/DistractingPackageHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/DistractingPackageHelperTest.kt
index e131a98..de029e0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/DistractingPackageHelperTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/DistractingPackageHelperTest.kt
@@ -185,7 +185,8 @@
         verify(pms, never()).scheduleWritePackageRestrictions(eq(TEST_USER_ID))
         verify(broadcastHelper, never()).sendPackageBroadcast(eq(
                 Intent.ACTION_DISTRACTING_PACKAGES_CHANGED), nullable(), nullable(), anyInt(),
-                nullable(), nullable(), any(), nullable(), nullable(), nullable(), nullable())
+                nullable(), nullable(), any(), nullable(), nullable(), nullable(), nullable(),
+                nullable())
 
         distractingPackageHelper.removeDistractingPackageRestrictions(pms.snapshotComputer(),
                 arrayOfNulls(0), TEST_USER_ID)