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

Commit 03fd8e0b authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add timeout for multipart SMS sending code path." into sc-dev

parents 59f2be92 1e6887f4
Loading
Loading
Loading
Loading
+92 −46
Original line number Diff line number Diff line
@@ -355,45 +355,60 @@ public abstract class SMSDispatcher extends Handler {
     */
    protected abstract class SmsSender extends Handler {
        private static final int EVENT_TIMEOUT = 1;
        protected final SmsTracker mTracker;
        // Initialized in sendSmsByCarrierApp
        protected volatile SmsSenderCallback mSenderCallback;
        protected volatile CarrierMessagingCallback mSenderCallback;
        protected final CarrierMessagingServiceWrapper mCarrierMessagingServiceWrapper =
                new CarrierMessagingServiceWrapper();
        private String mCarrierPackageName;

        protected SmsSender(SmsTracker tracker) {
        protected SmsSender() {
            super(Looper.getMainLooper());
            mTracker = tracker;
        }

        /**
         * Bind to carrierPackageName to send message through it
         */
        public void sendSmsByCarrierApp(String carrierPackageName,
                                        SmsSenderCallback senderCallback) {
                CarrierMessagingCallback senderCallback) {
            mCarrierPackageName = carrierPackageName;
            mSenderCallback = senderCallback;
            if (!mCarrierMessagingServiceWrapper.bindToCarrierMessagingService(
                    mContext, carrierPackageName, runnable -> runnable.run(),
                    ()->onServiceReady())) {
                Rlog.e(TAG, "bindService() for carrier messaging service failed");
                mSenderCallback.onSendSmsComplete(
                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
                        0 /* messageRef */);
                onSendComplete(CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK);
            } else {
                Rlog.d(TAG, "bindService() for carrier messaging service succeeded");
                sendMessageDelayed(obtainMessage(EVENT_TIMEOUT), mCarrierMessagingTimeout);
            }
        }

        /**
         * Callback received from mCarrierPackageName on binding to it is done
         */
        public abstract void onServiceReady();

        /**
         * Method to call message send callback with passed in result and default parameters
         */
        public abstract void onSendComplete(@CarrierMessagingService.SendResult int result);

        /**
         * Used to get the SmsTracker for single part messages
         */
        public abstract SmsTracker getSmsTracker();

        /**
         * Used to get the SmsTrackers for multi part messages
         */
        public abstract SmsTracker[] getSmsTrackers();

        @Override
        public void handleMessage(Message msg) {
            if (msg.what == EVENT_TIMEOUT) {
                logWithLocalLog("handleMessage: did not receive response from "
                        + mCarrierPackageName + " for " + mCarrierMessagingTimeout + " ms");
                mSenderCallback.onSendSmsComplete(
                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
                        0 /* messageRef */);
                onSendComplete(CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK);
            } else {
                logWithLocalLog("handleMessage: received unexpected message " + msg.what);
            }
@@ -413,8 +428,10 @@ public abstract class SMSDispatcher extends Handler {
     * Use the carrier messaging service to send a text SMS.
     */
    protected final class TextSmsSender extends SmsSender {
        private final SmsTracker mTracker;
        public TextSmsSender(SmsTracker tracker) {
            super(tracker);
            super();
            mTracker = tracker;
        }

        @Override
@@ -435,24 +452,38 @@ public abstract class SMSDispatcher extends Handler {
                            mSenderCallback);
                } catch (RuntimeException e) {
                    Rlog.e(TAG, "Exception sending the SMS: " + e.getMessage());
                    mSenderCallback.onSendSmsComplete(
                            CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
                            0 /* messageRef */);
                    onSendComplete(CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK);
                }
            } else {
                mSenderCallback.onSendSmsComplete(
                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
                        0 /* messageRef */);
                onSendComplete(CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK);
            }
        }

        @Override
        public void onSendComplete(int result) {
            mSenderCallback.onSendSmsComplete(result, 0 /* messageRef */);
        }

        @Override
        public SmsTracker getSmsTracker() {
            return mTracker;
        }

        @Override
        public SmsTracker[] getSmsTrackers() {
            Rlog.e(TAG, "getSmsTrackers: Unexpected call for TextSmsSender");
            return null;
        }
    }

    /**
     * Use the carrier messaging service to send a data SMS.
     */
    protected final class DataSmsSender extends SmsSender {
        private final SmsTracker mTracker;
        public DataSmsSender(SmsTracker tracker) {
            super(tracker);
            super();
            mTracker = tracker;
        }

        @Override
@@ -476,16 +507,28 @@ public abstract class SMSDispatcher extends Handler {
                } catch (RuntimeException e) {
                    Rlog.e(TAG, "Exception sending the SMS: " + e
                            + " " + SmsController.formatCrossStackMessageId(mTracker.mMessageId));
                    mSenderCallback.onSendSmsComplete(
                            CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
                            0 /* messageRef */);
                    onSendComplete(CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK);
                }
            } else {
                mSenderCallback.onSendSmsComplete(
                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
                        0 /* messageRef */);
                onSendComplete(CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK);
            }
        }

        @Override
        public void onSendComplete(int result) {
            mSenderCallback.onSendSmsComplete(result, 0 /* messageRef */);
        }

        @Override
        public SmsTracker getSmsTracker() {
            return mTracker;
        }

        @Override
        public SmsTracker[] getSmsTrackers() {
            Rlog.e(TAG, "getSmsTrackers: Unexpected call for DataSmsSender");
            return null;
        }
    }

    /**
@@ -507,7 +550,7 @@ public abstract class SMSDispatcher extends Handler {
            final long identity = Binder.clearCallingIdentity();
            try {
                mSmsSender.mCarrierMessagingServiceWrapper.disconnect();
                processSendSmsResponse(mSmsSender.mTracker, result, messageRef);
                processSendSmsResponse(mSmsSender.getSmsTracker(), result, messageRef);
                mSmsSender.removeTimeout();
            } finally {
                Binder.restoreCallingIdentity(identity);
@@ -579,15 +622,12 @@ public abstract class SMSDispatcher extends Handler {
    /**
     * Use the carrier messaging service to send a multipart text SMS.
     */
    private final class MultipartSmsSender {
    private final class MultipartSmsSender extends SmsSender {
        private final List<String> mParts;
        public final SmsTracker[] mTrackers;
        // Initialized in sendSmsByCarrierApp
        private volatile MultipartSmsSenderCallback mSenderCallback;
        private final CarrierMessagingServiceWrapper mCarrierMessagingServiceWrapper =
                new CarrierMessagingServiceWrapper();

        MultipartSmsSender(ArrayList<String> parts, SmsTracker[] trackers) {
            super();
            mParts = parts;
            mTrackers = trackers;
        }
@@ -595,20 +635,11 @@ public abstract class SMSDispatcher extends Handler {
        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
        void sendSmsByCarrierApp(String carrierPackageName,
                                 MultipartSmsSenderCallback senderCallback) {
            mSenderCallback = senderCallback;
            if (!mCarrierMessagingServiceWrapper.bindToCarrierMessagingService(
                    mContext, carrierPackageName, runnable -> runnable.run(),
                    ()->onServiceReady())) {
                Rlog.e(TAG, "bindService() for carrier messaging service failed");
                mSenderCallback.onSendMultipartSmsComplete(
                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
                        null /* messageRefs */);
            } else {
                Rlog.d(TAG, "bindService() for carrier messaging service succeeded");
            }
            super.sendSmsByCarrierApp(carrierPackageName, senderCallback);
        }

        private void onServiceReady() {
        @Override
        public void onServiceReady() {
            boolean statusReportRequested = false;
            for (SmsTracker tracker : mTrackers) {
                if (tracker.mDeliveryIntent != null) {
@@ -629,10 +660,24 @@ public abstract class SMSDispatcher extends Handler {
                        mSenderCallback);
            } catch (RuntimeException e) {
                Rlog.e(TAG, "Exception sending the SMS: " + e);
                mSenderCallback.onSendMultipartSmsComplete(
                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
                        null /* messageRefs */);
                onSendComplete(CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK);
            }
        }

        @Override
        public void onSendComplete(int result) {
            mSenderCallback.onSendMultipartSmsComplete(result, null /* messageRefs */);
        }

        @Override
        public SmsTracker getSmsTracker() {
            Rlog.e(TAG, "getSmsTracker: Unexpected call for MultipartSmsSender");
            return null;
        }

        @Override
        public SmsTracker[] getSmsTrackers() {
            return mTrackers;
        }
    }

@@ -657,6 +702,7 @@ public abstract class SMSDispatcher extends Handler {
         */
        @Override
        public void onSendMultipartSmsComplete(int result, int[] messageRefs) {
            mSmsSender.removeTimeout();
            mSmsSender.mCarrierMessagingServiceWrapper.disconnect();

            if (mSmsSender.mTrackers == null) {
+2 −1
Original line number Diff line number Diff line
@@ -1146,7 +1146,8 @@ public class SimulatedCommands extends BaseCommands
     */
    @Override
    public void sendSMSExpectMore (String smscPDU, String pdu, Message result) {
        unimplemented(result);
        SimulatedCommandsVerifier.getInstance().sendSMSExpectMore(smscPDU, pdu, result);
        resultSuccess(result, new SmsResponse(0 /*messageRef*/, null, SmsResponse.NO_ERROR_CODE));
    }

    @Override
+93 −0
Original line number Diff line number Diff line
@@ -347,6 +347,7 @@ public class GsmSmsDispatcherTest extends TelephonyTest {
            throws RemoteException {
        when(stub.queryLocalInterface(anyString())).thenReturn(stub);
        when(stub.asBinder()).thenReturn(stub);
        // for single part
        doAnswer(new Answer<Void>() {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
@@ -360,6 +361,21 @@ public class GsmSmsDispatcherTest extends TelephonyTest {
        }).when(stub).sendTextSms(
                anyString(), anyInt(), anyString(), anyInt(),
                any(ICarrierMessagingCallback.class));

        // for multi part
        doAnswer(new Answer<Void>() {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                Object[] args = invocation.getArguments();
                ICarrierMessagingCallback callback = (ICarrierMessagingCallback) args[4];
                if (callOnFilterComplete) {
                    callback.onSendMultipartSmsComplete(result, null);
                }
                return null;
            }
        }).when(stub).sendMultipartTextSms(
                any(), anyInt(), anyString(), anyInt(),
                any(ICarrierMessagingCallback.class));
    }

    @Test
@@ -417,4 +433,81 @@ public class GsmSmsDispatcherTest extends TelephonyTest {
        processAllMessages();
        verify(mSimulatedCommandsVerifier).sendSMS(anyString(), anyString(), any(Message.class));
    }

    private void sendMultipartTextSms(boolean withSentIntents) {
        // initiate parameters for a multipart sms
        ArrayList<String> parts = new ArrayList<>();
        parts.add("segment1");
        parts.add("segment2");

        ArrayList<PendingIntent> sentIntents = new ArrayList<>();
        PendingIntent sentIntent1 = PendingIntent.getBroadcast(TestApplication.getAppContext(), 0,
                new Intent(TEST_INTENT), PendingIntent.FLAG_MUTABLE);
        PendingIntent sentIntent2 = PendingIntent.getBroadcast(TestApplication.getAppContext(), 0,
                new Intent(TEST_INTENT), PendingIntent.FLAG_MUTABLE);
        sentIntents.add(sentIntent1);
        sentIntents.add(sentIntent2);

        mGsmSmsDispatcher.sendMultipartText("6501002000" /*destAddr*/, "222" /*scAddr*/, parts,
                withSentIntents ? sentIntents : null, null, null, null, false, -1, false, -1, 0L);
    }

    @Test
    @SmallTest
    public void testSendMultipartSmsByCarrierApp() throws Exception {
        mockCarrierApp();
        mockCarrierAppStubResults(CarrierMessagingService.SEND_STATUS_OK,
                mICarrierAppMessagingService, true);
        registerTestIntentReceiver();

        // send SMS and check sentIntent
        mReceivedTestIntent = false;
        sendMultipartTextSms(true);
        processAllMessages();
        synchronized (mLock) {
            if (!mReceivedTestIntent) {
                // long wait since sometimes broadcasts can take a long time if the system is loaded
                mLock.wait(60000);
            }
            assertEquals(true, mReceivedTestIntent);
            int resultCode = mTestReceiver.getResultCode();
            assertTrue("Unexpected result code: " + resultCode,
                    resultCode == SmsManager.RESULT_ERROR_NONE || resultCode == Activity.RESULT_OK);
            verify(mSimulatedCommandsVerifier, times(0)).sendSMS(anyString(), anyString(),
                    any(Message.class));
        }
    }

    @Test
    @SmallTest
    public void testSendMultipartSmsByCarrierAppNoResponse() throws Exception {
        mockCarrierApp();
        // do not mock result, instead reduce the timeout for test
        mGsmSmsDispatcher.mCarrierMessagingTimeout = 100;

        sendMultipartTextSms(false);

        // wait for timeout
        waitForMs(150);
        verify(mSimulatedCommandsVerifier).sendSMSExpectMore(anyString(), anyString(),
                any(Message.class));
        verify(mSimulatedCommandsVerifier).sendSMS(anyString(), anyString(),
                any(Message.class));
    }

    @Test
    @SmallTest
    public void testSendMultipartSmsByCarrierAppBindingFailed() throws Exception {
        mContextFixture.mockBindingFailureForPackage(CARRIER_APP_PACKAGE_NAME);
        // mock presence of carrier app, but do not create a mock service to make binding fail
        mockUiccWithCarrierApp();

        sendMultipartTextSms(false);

        processAllMessages();
        verify(mSimulatedCommandsVerifier).sendSMSExpectMore(anyString(), anyString(),
                any(Message.class));
        verify(mSimulatedCommandsVerifier).sendSMS(anyString(), anyString(),
                any(Message.class));
    }
}