Fix issue #2166755: BroadcastReceiver trying to return result during a non-ordered broadcast

Tell the broadcast receiver whether it is getting an initial sticky value,
so it will be quiet about attempts to do ordered broadcast stuff.

Note that the original bug being reported was not actually a crash, just
an error log.  So all we are doing here is making the log quieter.

Change-Id: Iaf1b718d82093ec1197142410a64feff47eb3859
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index b4ac159..2cd223f 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -653,7 +653,7 @@
                     mStrongRef = strong ? rd : null;
                 }
                 public void performReceive(Intent intent, int resultCode,
-                        String data, Bundle extras, boolean ordered) {
+                        String data, Bundle extras, boolean ordered, boolean sticky) {
                     ReceiverDispatcher rd = mDispatcher.get();
                     if (DEBUG_BROADCAST) {
                         int seq = intent.getIntExtra("seq", -1);
@@ -661,7 +661,8 @@
                                 + " to " + rd);
                     }
                     if (rd != null) {
-                        rd.performReceive(intent, resultCode, data, extras, ordered);
+                        rd.performReceive(intent, resultCode, data, extras,
+                                ordered, sticky);
                     }
                 }
             }
@@ -681,6 +682,7 @@
                 private String mCurData;
                 private Bundle mCurMap;
                 private boolean mCurOrdered;
+                private boolean mCurSticky;
 
                 public void run() {
                     BroadcastReceiver receiver = mReceiver;
@@ -706,6 +708,7 @@
                         receiver.setResult(mCurCode, mCurData, mCurMap);
                         receiver.clearAbortBroadcast();
                         receiver.setOrderedHint(mCurOrdered);
+                        receiver.setInitialStickyHint(mCurSticky);
                         receiver.onReceive(mContext, intent);
                     } catch (Exception e) {
                         if (mRegistered && mCurOrdered) {
@@ -788,7 +791,7 @@
             }
 
             public void performReceive(Intent intent, int resultCode,
-                    String data, Bundle extras, boolean ordered) {
+                    String data, Bundle extras, boolean ordered, boolean sticky) {
                 if (DEBUG_BROADCAST) {
                     int seq = intent.getIntExtra("seq", -1);
                     Log.i(TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq
@@ -800,6 +803,7 @@
                 args.mCurData = data;
                 args.mCurMap = extras;
                 args.mCurOrdered = ordered;
+                args.mCurSticky = sticky;
                 if (!mActivityThread.post(args)) {
                     if (mRegistered) {
                         IActivityManager mgr = ActivityManagerNative.getDefault();
@@ -1515,9 +1519,9 @@
         // correctly ordered, since these are one-way calls and the binder driver
         // applies transaction ordering per object for such calls.
         public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
-                int resultCode, String dataStr, Bundle extras, boolean ordered)
-                throws RemoteException {
-            receiver.performReceive(intent, resultCode, dataStr, extras, ordered);
+                int resultCode, String dataStr, Bundle extras, boolean ordered,
+                boolean sticky) throws RemoteException {
+            receiver.performReceive(intent, resultCode, dataStr, extras, ordered, sticky);
         }
 
         public void scheduleLowMemory() {
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 928981d..a772a8f 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -317,8 +317,9 @@
             String dataStr = data.readString();
             Bundle extras = data.readBundle();
             boolean ordered = data.readInt() != 0;
+            boolean sticky = data.readInt() != 0;
             scheduleRegisteredReceiver(receiver, intent,
-                    resultCode, dataStr, extras, ordered);
+                    resultCode, dataStr, extras, ordered, sticky);
             return true;
         }
 
@@ -716,7 +717,7 @@
     }
     
     public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
-            int resultCode, String dataStr, Bundle extras, boolean ordered)
+            int resultCode, String dataStr, Bundle extras, boolean ordered, boolean sticky)
             throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
@@ -726,6 +727,7 @@
         data.writeString(dataStr);
         data.writeBundle(extras);
         data.writeInt(ordered ? 1 : 0);
+        data.writeInt(sticky ? 1 : 0);
         mRemote.transact(SCHEDULE_REGISTERED_RECEIVER_TRANSACTION, data, null,
                 IBinder.FLAG_ONEWAY);
         data.recycle();
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 8dda898..89a52fd 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -91,7 +91,7 @@
     void dumpService(FileDescriptor fd, IBinder servicetoken, String[] args)
             throws RemoteException;
     void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
-            int resultCode, String data, Bundle extras, boolean ordered)
+            int resultCode, String data, Bundle extras, boolean ordered, boolean sticky)
             throws RemoteException;
     void scheduleLowMemory() throws RemoteException;
     void scheduleActivityConfigurationChanged(IBinder token) throws RemoteException;
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 18d9b92..be1dc4a 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -147,7 +147,7 @@
             mHandler = handler;
         }
         public void performReceive(Intent intent, int resultCode,
-                String data, Bundle extras, boolean serialized) {
+                String data, Bundle extras, boolean serialized, boolean sticky) {
             mIntent = intent;
             mResultCode = resultCode;
             mResultData = data;
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index b391c57d..b63d026 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -384,6 +384,24 @@
     }
     
     /**
+     * Returns true if the receiver is currently processing an ordered
+     * broadcast.
+     */
+    public final boolean isOrderedBroadcast() {
+        return mOrderedHint;
+    }
+    
+    /**
+     * Returns true if the receiver is currently processing the initial
+     * value of a sticky broadcast -- that is, the value that was last
+     * broadcast and is currently held in the sticky cache, so this is
+     * not directly the result of a broadcast right now.
+     */
+    public final boolean isInitialStickyBroadcast() {
+        return mInitialStickyHint;
+    }
+    
+    /**
      * For internal use, sets the hint about whether this BroadcastReceiver is
      * running in ordered mode.
      */
@@ -392,6 +410,14 @@
     }
     
     /**
+     * For internal use, sets the hint about whether this BroadcastReceiver is
+     * receiving the initial sticky broadcast value. @hide
+     */
+    public final void setInitialStickyHint(boolean isInitialSticky) {
+        mInitialStickyHint = isInitialSticky;
+    }
+    
+    /**
      * Control inclusion of debugging help for mismatched
      * calls to {@ Context#registerReceiver(BroadcastReceiver, IntentFilter)
      * Context.registerReceiver()}.
@@ -414,7 +440,10 @@
     }
     
     void checkSynchronousHint() {
-        if (mOrderedHint) {
+        // Note that we don't assert when receiving the initial sticky value,
+        // since that may have come from an ordered broadcast.  We'll catch
+        // them later when the real broadcast happens again.
+        if (mOrderedHint || mInitialStickyHint) {
             return;
         }
         RuntimeException e = new RuntimeException(
@@ -429,5 +458,6 @@
     private boolean mAbortBroadcast;
     private boolean mDebugUnregister;
     private boolean mOrderedHint;
+    private boolean mInitialStickyHint;
 }
 
diff --git a/core/java/android/content/IIntentReceiver.aidl b/core/java/android/content/IIntentReceiver.aidl
index 443db2d..6f2f7c4 100755
--- a/core/java/android/content/IIntentReceiver.aidl
+++ b/core/java/android/content/IIntentReceiver.aidl
@@ -28,6 +28,6 @@
  */
 oneway interface IIntentReceiver {
     void performReceive(in Intent intent, int resultCode,
-                        String data, in Bundle extras, boolean ordered);
+            String data, in Bundle extras, boolean ordered, boolean sticky);
 }
 
diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java
index c8f7aa9..e182021 100644
--- a/core/java/android/content/IntentSender.java
+++ b/core/java/android/content/IntentSender.java
@@ -113,7 +113,7 @@
             mHandler = handler;
         }
         public void performReceive(Intent intent, int resultCode,
-                String data, Bundle extras, boolean serialized) {
+                String data, Bundle extras, boolean serialized, boolean sticky) {
             mIntent = intent;
             mResultCode = resultCode;
             mResultData = data;