Skip broadcasting to a receiver if the receiver seems to be dead

If an application that has a broadcast receiver is killed
during broadcasting, thread variable of ProcessRecord becomes null
so that IIntentReceiver#performReceive() is called
in BroadcastQueue#performReceiveLocked(). But if binder driver has not
noticed the death of the application yet, it can't throw
DeadObjectException. After that, binder driver notices. But it can't
notify DeadObjectException to the caller because performReceive() is
async call. So broadcasting keeps on waiting for finishing
performReceive() until timeout.

This change checks the death of the application before calling
performReceive() and skips broadcasting to the receiver
if the application has already died.

Change-Id: Ifa02b8b1a7e7b6fd314de90fedff5b7a5326825d
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index bfb667f..ea15653 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -415,11 +415,16 @@
             Intent intent, int resultCode, String data, Bundle extras,
             boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
         // Send the intent to the receiver asynchronously using one-way binder calls.
-        if (app != null && app.thread != null) {
-            // If we have an app thread, do the call through that so it is
-            // correctly ordered with other one-way calls.
-            app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
-                    data, extras, ordered, sticky, sendingUser, app.repProcState);
+        if (app != null) {
+            if (app.thread != null) {
+                // If we have an app thread, do the call through that so it is
+                // correctly ordered with other one-way calls.
+                app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
+                        data, extras, ordered, sticky, sendingUser, app.repProcState);
+            } else {
+                // Application has died. Receiver doesn't exist.
+                throw new RemoteException("app.thread must not be null");
+            }
         } else {
             receiver.performReceive(intent, resultCode, data, extras, ordered,
                     sticky, sendingUser);
@@ -661,6 +666,7 @@
                             // (local and remote) isn't kept in the mBroadcastHistory.
                             r.resultTo = null;
                         } catch (RemoteException e) {
+                            r.resultTo = null;
                             Slog.w(TAG, "Failure ["
                                     + mQueueName + "] sending broadcast result of "
                                     + r.intent, e);