Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9b06ac92 authored by riddle_hsu's avatar riddle_hsu Committed by Steve Kondik
Browse files

Avoid ANR by previous dead receiver.

Assue a process has a registered receiver for ordered
broadcast B. And there is a B enqueued. Before deliver
B, the process process is died and restart with the same
ProcessRecord (it will happen when the process is persistent
process or start by "Exception when sending broadcast").

Now it is the turn to deliver B. Because the ProcessRecord
is reuse, it will not meet "app.thread must not be null".
Then the previous will still deliver to the new process.
And there will have DeadObjectException in the new process
but does not call finishReceiver that results ANR.

android.os.DeadObjectException
at android.os.BinderProxy.transactNative
at android.os.BinderProxy.transact
at android.content.IIntentReceiver$Stub$Proxy.performReceive
at android.app.ActivityThread$ApplicationThread.scheduleRegisteredReceiver

Because the IIntentReceiver is not belong to the new process,
it will be BinderProxy so we can use Binder.isProxy to check.

Another way is to clean related record in broadcast queue
when process died but it should have more cost.

Change-Id: I345d7f0134d31795cbf17c8c84c1fb6ab9f0be21
parent ea69b566
Loading
Loading
Loading
Loading
+19 −3
Original line number Diff line number Diff line
@@ -896,9 +896,25 @@ public final class ActivityThread {
        public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
                int resultCode, String dataStr, Bundle extras, boolean ordered,
                boolean sticky, int sendingUser, int processState) throws RemoteException {
            RemoteException remoteException = null;
            if (!Binder.isProxy(receiver)) {
                updateProcessState(processState, false);
                try {
                    receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                            sticky, sendingUser);
                    return;
                } catch (RemoteException e) {
                    remoteException = e;
                }
            }
            if (ordered) {
                Slog.w(TAG, receiver + " is no longer alive");
                ActivityManagerNative.getDefault().finishReceiver(receiver.asBinder(),
                        resultCode, dataStr, extras, true, intent.getFlags());
                if (remoteException != null) {
                    throw remoteException;
                }
            }
        }

        @Override