Merge "Make sure stickies get resent from the same UID." into udc-dev
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 658e664..544828a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1175,17 +1175,21 @@
     static final class StickyBroadcast {
         public Intent intent;
         public boolean deferUntilActive;
+        public int originalCallingUid;
 
-        public static StickyBroadcast create(Intent intent, boolean deferUntilActive) {
+        public static StickyBroadcast create(Intent intent, boolean deferUntilActive,
+                int originalCallingUid) {
             final StickyBroadcast b = new StickyBroadcast();
             b.intent = intent;
             b.deferUntilActive = deferUntilActive;
+            b.originalCallingUid = originalCallingUid;
             return b;
         }
 
         @Override
         public String toString() {
-            return "{intent=" + intent + ", defer=" + deferUntilActive + "}";
+            return "{intent=" + intent + ", defer=" + deferUntilActive + ", originalCallingUid="
+                    + originalCallingUid + "}";
         }
     }
 
@@ -11119,6 +11123,9 @@
                                 pw.print(" [D]");
                             }
                             pw.println();
+                            pw.print("      originalCallingUid: ");
+                            pw.println(broadcasts.get(i).originalCallingUid);
+                            pw.println();
                             Bundle bundle = intent.getExtras();
                             if (bundle != null) {
                                 pw.print("      extras: ");
@@ -14008,16 +14015,25 @@
             if (allSticky != null) {
                 ArrayList receivers = new ArrayList();
                 receivers.add(bf);
+                sticky = null;
 
                 final int stickyCount = allSticky.size();
                 for (int i = 0; i < stickyCount; i++) {
                     final StickyBroadcast broadcast = allSticky.get(i);
+                    final int originalStickyCallingUid = allSticky.get(i).originalCallingUid;
+                    // TODO(b/281889567): consider using checkComponentPermission instead of
+                    //  canAccessUnexportedComponents
+                    if (sticky == null && (exported || originalStickyCallingUid == callingUid
+                            || ActivityManager.canAccessUnexportedComponents(
+                            originalStickyCallingUid))) {
+                        sticky = broadcast.intent;
+                    }
                     BroadcastQueue queue = broadcastQueueForIntent(broadcast.intent);
                     BroadcastRecord r = new BroadcastRecord(queue, broadcast.intent, null,
                             null, null, -1, -1, false, null, null, null, null, OP_NONE,
                             BroadcastOptions.makeWithDeferUntilActive(broadcast.deferUntilActive),
                             receivers, null, null, 0, null, null, false, true, true, -1,
-                            BackgroundStartPrivileges.NONE,
+                            originalStickyCallingUid, BackgroundStartPrivileges.NONE,
                             false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */,
                             null /* filterExtrasForReceiver */);
                     queue.enqueueBroadcastLocked(r);
@@ -14895,12 +14911,13 @@
             for (i = 0; i < stickiesCount; i++) {
                 if (intent.filterEquals(list.get(i).intent)) {
                     // This sticky already exists, replace it.
-                    list.set(i, StickyBroadcast.create(new Intent(intent), deferUntilActive));
+                    list.set(i, StickyBroadcast.create(new Intent(intent), deferUntilActive,
+                            callingUid));
                     break;
                 }
             }
             if (i >= stickiesCount) {
-                list.add(StickyBroadcast.create(new Intent(intent), deferUntilActive));
+                list.add(StickyBroadcast.create(new Intent(intent), deferUntilActive, callingUid));
             }
         }
 
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index a9274408..a402db9 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -79,6 +79,9 @@
     final @Nullable String callerFeatureId; // which feature in the package sent this
     final int callingPid;   // the pid of who sent this
     final int callingUid;   // the uid of who sent this
+
+    final int originalStickyCallingUid;
+            // if this is a sticky broadcast, the Uid of the original sender
     final boolean callerInstantApp; // caller is an Instant App?
     final boolean callerInstrumented; // caller is being instrumented?
     final boolean ordered;  // serialize the send to receivers?
@@ -330,7 +333,8 @@
             pw.print(prefix); pw.print("resultAbort="); pw.print(resultAbort);
                     pw.print(" ordered="); pw.print(ordered);
                     pw.print(" sticky="); pw.print(sticky);
-                    pw.print(" initialSticky="); pw.println(initialSticky);
+                    pw.print(" initialSticky="); pw.print(initialSticky);
+                    pw.print(" originalStickyCallingUid="); pw.println(originalStickyCallingUid);
         }
         if (nextReceiver != 0) {
             pw.print(prefix); pw.print("nextReceiver="); pw.println(nextReceiver);
@@ -399,6 +403,27 @@
         }
     }
 
+    BroadcastRecord(BroadcastQueue queue,
+            Intent intent, ProcessRecord callerApp, String callerPackage,
+            @Nullable String callerFeatureId, int callingPid, int callingUid,
+            boolean callerInstantApp, String resolvedType,
+            String[] requiredPermissions, String[] excludedPermissions,
+            String[] excludedPackages, int appOp,
+            BroadcastOptions options, List receivers,
+            ProcessRecord resultToApp, IIntentReceiver resultTo, int resultCode,
+            String resultData, Bundle resultExtras, boolean serialized, boolean sticky,
+            boolean initialSticky, int userId,
+            @NonNull BackgroundStartPrivileges backgroundStartPrivileges,
+            boolean timeoutExempt,
+            @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) {
+        this(queue, intent, callerApp, callerPackage, callerFeatureId, callingPid,
+                callingUid, callerInstantApp, resolvedType, requiredPermissions,
+                excludedPermissions, excludedPackages, appOp, options, receivers, resultToApp,
+                resultTo, resultCode, resultData, resultExtras, serialized, sticky,
+                initialSticky, userId, -1, backgroundStartPrivileges, timeoutExempt,
+                filterExtrasForReceiver);
+    }
+
     BroadcastRecord(BroadcastQueue _queue,
             Intent _intent, ProcessRecord _callerApp, String _callerPackage,
             @Nullable String _callerFeatureId, int _callingPid, int _callingUid,
@@ -408,7 +433,7 @@
             BroadcastOptions _options, List _receivers,
             ProcessRecord _resultToApp, IIntentReceiver _resultTo, int _resultCode,
             String _resultData, Bundle _resultExtras, boolean _serialized, boolean _sticky,
-            boolean _initialSticky, int _userId,
+            boolean _initialSticky, int _userId, int originalStickyCallingUid,
             @NonNull BackgroundStartPrivileges backgroundStartPrivileges,
             boolean timeoutExempt,
             @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) {
@@ -460,6 +485,7 @@
         interactive = options != null && options.isInteractive();
         shareIdentity = options != null && options.isShareIdentityEnabled();
         this.filterExtrasForReceiver = filterExtrasForReceiver;
+        this.originalStickyCallingUid = originalStickyCallingUid;
     }
 
     /**
@@ -524,6 +550,7 @@
         shareIdentity = from.shareIdentity;
         urgent = from.urgent;
         filterExtrasForReceiver = from.filterExtrasForReceiver;
+        originalStickyCallingUid = from.originalStickyCallingUid;
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/BroadcastSkipPolicy.java b/services/core/java/com/android/server/am/BroadcastSkipPolicy.java
index 6718319..5f918cf 100644
--- a/services/core/java/com/android/server/am/BroadcastSkipPolicy.java
+++ b/services/core/java/com/android/server/am/BroadcastSkipPolicy.java
@@ -563,14 +563,15 @@
 
         // Ensure that broadcasts are only sent to other apps if they are explicitly marked as
         // exported, or are System level broadcasts
+        final int originalCallingUid = r.sticky ? r.originalStickyCallingUid : r.callingUid;
         if (!filter.exported && checkComponentPermission(null, r.callingPid,
-                r.callingUid, filter.receiverList.uid, filter.exported)
+                originalCallingUid, filter.receiverList.uid, filter.exported)
                 != PackageManager.PERMISSION_GRANTED) {
             return "Exported Denial: sending "
                     + r.intent.toString()
                     + ", action: " + r.intent.getAction()
                     + " from " + r.callerPackage
-                    + " (uid=" + r.callingUid + ")"
+                    + " (uid=" + originalCallingUid + ")"
                     + " due to receiver " + filter.receiverList.app
                     + " (uid " + filter.receiverList.uid + ")"
                     + " not specifying RECEIVER_EXPORTED";
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index f82d246..bfe7d7f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -648,24 +648,24 @@
 
         broadcastIntent(intent1, null, true);
         assertStickyBroadcasts(mAms.getStickyBroadcasts(TEST_ACTION1, TEST_USER),
-                StickyBroadcast.create(intent1, false));
+                StickyBroadcast.create(intent1, false, Process.myUid()));
         assertNull(mAms.getStickyBroadcasts(TEST_ACTION2, TEST_USER));
         assertNull(mAms.getStickyBroadcasts(TEST_ACTION3, TEST_USER));
 
         broadcastIntent(intent2, options.toBundle(), true);
         assertStickyBroadcasts(mAms.getStickyBroadcasts(TEST_ACTION1, TEST_USER),
-                StickyBroadcast.create(intent1, false));
+                StickyBroadcast.create(intent1, false, Process.myUid()));
         assertStickyBroadcasts(mAms.getStickyBroadcasts(TEST_ACTION2, TEST_USER),
-                StickyBroadcast.create(intent2, true));
+                StickyBroadcast.create(intent2, true, Process.myUid()));
         assertNull(mAms.getStickyBroadcasts(TEST_ACTION3, TEST_USER));
 
         broadcastIntent(intent3, null, true);
         assertStickyBroadcasts(mAms.getStickyBroadcasts(TEST_ACTION1, TEST_USER),
-                StickyBroadcast.create(intent1, false));
+                StickyBroadcast.create(intent1, false, Process.myUid()));
         assertStickyBroadcasts(mAms.getStickyBroadcasts(TEST_ACTION2, TEST_USER),
-                StickyBroadcast.create(intent2, true));
+                StickyBroadcast.create(intent2, true, Process.myUid()));
         assertStickyBroadcasts(mAms.getStickyBroadcasts(TEST_ACTION3, TEST_USER),
-                StickyBroadcast.create(intent3, false));
+                StickyBroadcast.create(intent3, false, Process.myUid()));
     }
 
     @SuppressWarnings("GuardedBy")
@@ -698,6 +698,9 @@
         if (a.deferUntilActive != b.deferUntilActive) {
             return false;
         }
+        if (a.originalCallingUid != b.originalCallingUid) {
+            return false;
+        }
         return true;
     }