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

Commit a0752490 authored by Anton Potapov's avatar Anton Potapov Committed by Android (Google) Code Review
Browse files

Merge "Don't rethrow DeadObjectException when communicate through the Binder" into main

parents b1ac293f abc66677
Loading
Loading
Loading
Loading
+25 −4
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -285,6 +286,7 @@ public abstract class ControlsProviderService extends Service {
        private IControlsSubscriber mCs;
        private boolean mEnforceStateless;
        private Context mContext;
        private SubscriptionAdapter mSubscription;

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

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

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

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

        public void onComplete() {
            try {
                mCs.onComplete(mToken);
                mSubscription = null;
            } 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();
            }
        }
+45 −11
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -36,6 +37,7 @@ import android.graphics.Bitmap;
import android.graphics.drawable.Icon;
import android.os.Binder;
import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.IBinder;
import android.os.RemoteException;
import android.service.controls.actions.CommandAction;
@@ -53,6 +55,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -307,6 +310,18 @@ public class ControlProviderServiceTest {
                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
     * the control obtained by the subscriber
@@ -359,6 +374,7 @@ public class ControlProviderServiceTest {
        }

        private List<Control> mControls;
        private FakeSubscription mSubscription;

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

        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) {
            int i = 0;
            for (Control c : mControls) {
                        if (i++ < n) s.onNext(c);
                if (i++ < n) mSubscriber.onNext(c);
                else break;
            }
                    s.onComplete();
            mSubscriber.onComplete();
        }
                public void cancel() {}
            };

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