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

Commit abc66677 authored by Anton Potapov's avatar Anton Potapov
Browse files

Don't rethrow DeadObjectException when communicate through the Binder

Test: atest ControlProviderServiceTest
Fixes: 273336209
Change-Id: I9424ad78ac54f261b8650bb41a204144a32c07cc
parent 513dea53
Loading
Loading
Loading
Loading
+25 −4
Original line number Original line Diff line number Diff line
@@ -25,6 +25,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.content.Intent;
import android.os.Bundle;
import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder;
import android.os.Looper;
import android.os.Looper;
@@ -285,6 +286,7 @@ public abstract class ControlsProviderService extends Service {
        private IControlsSubscriber mCs;
        private IControlsSubscriber mCs;
        private boolean mEnforceStateless;
        private boolean mEnforceStateless;
        private Context mContext;
        private Context mContext;
        private SubscriptionAdapter mSubscription;


        SubscriberProxy(boolean enforceStateless, IBinder token, IControlsSubscriber cs) {
        SubscriberProxy(boolean enforceStateless, IBinder token, IControlsSubscriber cs) {
            mEnforceStateless = enforceStateless;
            mEnforceStateless = enforceStateless;
@@ -300,11 +302,14 @@ public abstract class ControlsProviderService extends Service {


        public void onSubscribe(Subscription subscription) {
        public void onSubscribe(Subscription subscription) {
            try {
            try {
                mCs.onSubscribe(mToken, new SubscriptionAdapter(subscription));
                SubscriptionAdapter subscriptionAdapter = new SubscriptionAdapter(subscription);
                mCs.onSubscribe(mToken, subscriptionAdapter);
                mSubscription = subscriptionAdapter;
            } catch (RemoteException ex) {
            } catch (RemoteException ex) {
                ex.rethrowAsRuntimeException();
                handleRemoteException(ex);
            }
            }
        }
        }

        public void onNext(@NonNull Control control) {
        public void onNext(@NonNull Control control) {
            Preconditions.checkNotNull(control);
            Preconditions.checkNotNull(control);
            try {
            try {
@@ -318,20 +323,36 @@ public abstract class ControlsProviderService extends Service {
                }
                }
                mCs.onNext(mToken, control);
                mCs.onNext(mToken, control);
            } catch (RemoteException ex) {
            } catch (RemoteException ex) {
                ex.rethrowAsRuntimeException();
                handleRemoteException(ex);
            }
            }
        }
        }

        public void onError(Throwable t) {
        public void onError(Throwable t) {
            try {
            try {
                mCs.onError(mToken, t.toString());
                mCs.onError(mToken, t.toString());
                mSubscription = null;
            } catch (RemoteException ex) {
            } catch (RemoteException ex) {
                ex.rethrowAsRuntimeException();
                handleRemoteException(ex);
            }
            }
        }
        }

        public void onComplete() {
        public void onComplete() {
            try {
            try {
                mCs.onComplete(mToken);
                mCs.onComplete(mToken);
                mSubscription = null;
            } catch (RemoteException ex) {
            } catch (RemoteException ex) {
                handleRemoteException(ex);
            }
        }

        private void handleRemoteException(RemoteException ex) {
            if (ex instanceof DeadObjectException) {
                // System UI crashed or is restarting. There is no need to rethrow this
                SubscriptionAdapter subscriptionAdapter = mSubscription;
                if (subscriptionAdapter != null) {
                    subscriptionAdapter.cancel();
                }
            } else {
                ex.rethrowAsRuntimeException();
                ex.rethrowAsRuntimeException();
            }
            }
        }
        }
+45 −11
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.when;
@@ -36,6 +37,7 @@ import android.graphics.Bitmap;
import android.graphics.drawable.Icon;
import android.graphics.drawable.Icon;
import android.os.Binder;
import android.os.Binder;
import android.os.Bundle;
import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.IBinder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.RemoteException;
import android.service.controls.actions.CommandAction;
import android.service.controls.actions.CommandAction;
@@ -53,6 +55,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.mockito.Captor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoAnnotations;
@@ -307,6 +310,18 @@ public class ControlProviderServiceTest {
                intent.getParcelableExtra(ControlsProviderService.EXTRA_CONTROL)));
                intent.getParcelableExtra(ControlsProviderService.EXTRA_CONTROL)));
    }
    }


    @Test
    public void testOnNextDoesntRethrowDeadObjectException() throws RemoteException {
        doAnswer(invocation -> {
            throw new DeadObjectException();
        }).when(mSubscriber).onNext(ArgumentMatchers.any(), ArgumentMatchers.any());
        Control control = new Control.StatelessBuilder("TEST_ID", mPendingIntent).build();

        sendControlGetControl(control);

        assertTrue(mControlsProviderService.mSubscription.mIsCancelled);
    }

    /**
    /**
     * Sends the control through the publisher in {@code mControlsProviderService}, returning
     * Sends the control through the publisher in {@code mControlsProviderService}, returning
     * the control obtained by the subscriber
     * the control obtained by the subscriber
@@ -359,6 +374,7 @@ public class ControlProviderServiceTest {
        }
        }


        private List<Control> mControls;
        private List<Control> mControls;
        private FakeSubscription mSubscription;


        public void setControls(List<Control> controls) {
        public void setControls(List<Control> controls) {
            mControls = controls;
            mControls = controls;
@@ -398,17 +414,35 @@ public class ControlProviderServiceTest {
        }
        }


        private Subscription createSubscription(Subscriber s, List<Control> controls) {
        private Subscription createSubscription(Subscriber s, List<Control> controls) {
            return new Subscription() {
            FakeSubscription subscription = new FakeSubscription(s, controls);
            mSubscription = subscription;
            return subscription;
        }
    }

    private static final class FakeSubscription implements Subscription {

        private final Subscriber mSubscriber;
        private final List<Control> mControls;

        private boolean mIsCancelled = false;

        FakeSubscription(Subscriber s, List<Control> controls) {
            mSubscriber = s;
            mControls = controls;
        }

        public void request(long n) {
        public void request(long n) {
            int i = 0;
            int i = 0;
            for (Control c : mControls) {
            for (Control c : mControls) {
                        if (i++ < n) s.onNext(c);
                if (i++ < n) mSubscriber.onNext(c);
                else break;
                else break;
            }
            }
                    s.onComplete();
            mSubscriber.onComplete();
        }
        }
                public void cancel() {}

            };
        public void cancel() {
            mIsCancelled = true;
        }
        }
    }
    }
}
}