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

Commit 0ab9daeb authored by Thomas Nguyen's avatar Thomas Nguyen
Browse files

Retry polling for pending datagrams in demo mode

Bug: 329733358
Test: DatagramControllerTest, DatagramDispatcherTest
Manually send datagram in demo mode

Change-Id: I30c4e6c991e7d9ce831299e12281eec3c51c503a
parent 984430a0
Loading
Loading
Loading
Loading
+38 −10
Original line number Diff line number Diff line
@@ -16,10 +16,13 @@

package com.android.internal.telephony.satellite;

import static android.telephony.SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE;
import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED;
import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING;
import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_IDLE;
import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_OFF;
import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;

import android.annotation.NonNull;
import android.content.Context;
@@ -72,7 +75,7 @@ public class DatagramController {
    private int mSendSubId;
    @GuardedBy("mLock")
    private @SatelliteManager.SatelliteDatagramTransferState int mSendDatagramTransferState =
            SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE;
            SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE;
    @GuardedBy("mLock")
    private int mSendPendingCount = 0;
    @GuardedBy("mLock")
@@ -82,7 +85,7 @@ public class DatagramController {
    private int mReceiveSubId;
    @GuardedBy("mLock")
    private @SatelliteManager.SatelliteDatagramTransferState int mReceiveDatagramTransferState =
            SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE;
            SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE;
    @GuardedBy("mLock")
    private int mReceivePendingCount = 0;
    @GuardedBy("mLock")
@@ -132,7 +135,7 @@ public class DatagramController {
     *                              about datagram transfer state changes.
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    protected DatagramController(@NonNull Context context, @NonNull Looper  looper,
    public DatagramController(@NonNull Context context, @NonNull Looper  looper,
            @NonNull PointingAppController pointingAppController) {
        mContext = context;
        mPointingAppController = pointingAppController;
@@ -188,6 +191,7 @@ public class DatagramController {
     * @param callback The callback to get {@link SatelliteManager.SatelliteResult} of the request.
     */
    public void pollPendingSatelliteDatagrams(int subId, @NonNull Consumer<Integer> callback) {
        logd("pollPendingSatelliteDatagrams");
        mDatagramReceiver.pollPendingSatelliteDatagrams(subId, callback);
    }

@@ -213,7 +217,6 @@ public class DatagramController {
    public void sendSatelliteDatagram(int subId, @SatelliteManager.DatagramType int datagramType,
            @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI,
            @NonNull Consumer<Integer> callback) {
        pushDemoModeDatagram(datagramType, datagram);
        mDatagramDispatcher.sendSatelliteDatagram(subId, datagramType, datagram,
                needFullScreenPointingUI, callback);
    }
@@ -239,10 +242,10 @@ public class DatagramController {
            mSendDatagramTransferState = datagramTransferState;
            mSendPendingCount = sendPendingCount;
            mSendErrorCode = errorCode;

            notifyDatagramTransferStateChangedToSessionController();
            mPointingAppController.updateSendDatagramTransferState(mSendSubId,
                    mSendDatagramTransferState, mSendPendingCount, mSendErrorCode);
            retryPollPendingDatagramsInDemoMode();
        }
    }

@@ -271,6 +274,7 @@ public class DatagramController {
            notifyDatagramTransferStateChangedToSessionController();
            mPointingAppController.updateReceiveDatagramTransferState(mReceiveSubId,
                    mReceiveDatagramTransferState, mReceivePendingCount, mReceiveErrorCode);
            retryPollPendingDatagramsInDemoMode();
        }

        if (isPollingInIdleState()) {
@@ -300,9 +304,16 @@ public class DatagramController {
        mDatagramReceiver.onSatelliteModemStateChanged(state);
    }

    void setDeviceAlignedWithSatellite(boolean isAligned) {
    /**
     * Set whether the device is aligned with the satellite.
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public void setDeviceAlignedWithSatellite(boolean isAligned) {
        mDatagramDispatcher.setDeviceAlignedWithSatellite(isAligned);
        mDatagramReceiver.setDeviceAlignedWithSatellite(isAligned);
        if (isAligned) {
            retryPollPendingDatagramsInDemoMode();
        }
    }

    @VisibleForTesting
@@ -332,14 +343,14 @@ public class DatagramController {
    public boolean isSendingInIdleState() {
        synchronized (mLock) {
            return (mSendDatagramTransferState
                    == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE);
                    == SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE);
        }
    }

    public boolean isPollingInIdleState() {
        synchronized (mLock) {
            return (mReceiveDatagramTransferState
                    == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE);
                    == SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE);
        }
    }

@@ -380,8 +391,8 @@ public class DatagramController {
     * @param datagramType datagram type, only DATAGRAM_TYPE_SOS_MESSAGE will be saved
     * @param datagram datagram The last datagram saved when sendSatelliteDatagramForDemo is called
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    protected void pushDemoModeDatagram(@SatelliteManager.DatagramType int datagramType,
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public void pushDemoModeDatagram(@SatelliteManager.DatagramType int datagramType,
            SatelliteDatagram datagram) {
        if (mIsDemoMode && datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE) {
            synchronized (mLock) {
@@ -484,6 +495,23 @@ public class DatagramController {
        mDatagramDispatcher.setShouldSendDatagramToModemInDemoMode(shouldSendToModemInDemoMode);
    }

    private void retryPollPendingDatagramsInDemoMode() {
        synchronized (mLock) {
            if (mIsDemoMode && isSendingInIdleState() && isPollingInIdleState()
                    && !mDemoModeDatagramList.isEmpty()) {
                Consumer<Integer> internalCallback = new Consumer<Integer>() {
                    @Override
                    public void accept(Integer result) {
                        if (result != SATELLITE_RESULT_SUCCESS) {
                            logd("retryPollPendingDatagramsInDemoMode result: " + result);
                        }
                    }
                };
                pollPendingSatelliteDatagrams(DEFAULT_SUBSCRIPTION_ID, internalCallback);
            }
        }
    }

    private static void logd(@NonNull String log) {
        Rlog.d(TAG, log);
    }
+49 −27
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.internal.telephony.satellite;

import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED;
import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_MODEM_TIMEOUT;
import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE;
import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;

import static com.android.internal.telephony.satellite.DatagramController.ROUNDING_UNIT;
@@ -62,7 +63,7 @@ public class DatagramDispatcher extends Handler {
    private static final int EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT = 4;
    private static final int EVENT_WAIT_FOR_DATAGRAM_SENDING_RESPONSE_TIMED_OUT = 5;
    private static final int EVENT_ABORT_SENDING_SATELLITE_DATAGRAMS_DONE = 6;
    private static final int CMD_POLL_PENDING_SATELLITE_DATAGRAMS = 7;
    private static final int EVENT_WAIT_FOR_SIMULATED_POLL_DATAGRAMS_DELAY_TIMED_OUT = 7;
    private static final Long TIMEOUT_DATAGRAM_DELAY_IN_DEMO_MODE = TimeUnit.SECONDS.toMillis(10);
    @NonNull private static DatagramDispatcher sInstance;
    @NonNull private final Context mContext;
@@ -238,7 +239,8 @@ public class DatagramDispatcher extends Handler {
                            break;
                        }
                    }
                    logd("EVENT_SEND_SATELLITE_DATAGRAM_DONE error: " + error);
                    logd("EVENT_SEND_SATELLITE_DATAGRAM_DONE error: " + error
                            + ", mIsDemoMode=" + mIsDemoMode);

                    /*
                     * The response should be ignored if either of the following hold
@@ -271,11 +273,7 @@ public class DatagramDispatcher extends Handler {
                                getPendingDatagramCount(), error);
                        mControllerMetricsStats.reportOutgoingDatagramSuccessCount(
                                argument.datagramType);
                        if (mIsDemoMode) {
                            sendMessageDelayed(
                                    obtainMessage(CMD_POLL_PENDING_SATELLITE_DATAGRAMS, request),
                                    getDemoTimeoutDuration());
                        }
                        startWaitForSimulatedPollDatagramsDelayTimer(request);
                        if (getPendingDatagramCount() > 0) {
                            // Send response for current datagram
                            argument.callback.accept(error);
@@ -323,13 +321,10 @@ public class DatagramDispatcher extends Handler {
                handleEventDatagramWaitForConnectedStateTimedOut();
                break;

            case CMD_POLL_PENDING_SATELLITE_DATAGRAMS:
                if (mIsDemoMode) {
            case EVENT_WAIT_FOR_SIMULATED_POLL_DATAGRAMS_DELAY_TIMED_OUT:
                request = (DatagramDispatcherHandlerRequest) msg.obj;
                    SendSatelliteDatagramArgument argument =
                            (SendSatelliteDatagramArgument) request.argument;
                    pollPendingSatelliteDatagrams(argument.subId);
                }
                handleEventWaitForSimulatedPollDatagramsDelayTimedOut(
                        (SendSatelliteDatagramArgument) request.argument);
                break;

            default:
@@ -413,8 +408,11 @@ public class DatagramDispatcher extends Handler {
        logd("setDemoMode: mIsDemoMode=" + mIsDemoMode);
    }

    /**
     * Set whether the device is aligned with the satellite.
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    protected void setDeviceAlignedWithSatellite(boolean isAligned) {
    public void setDeviceAlignedWithSatellite(boolean isAligned) {
        synchronized (mLock) {
            mIsAligned = isAligned;
            logd("setDeviceAlignedWithSatellite: " + mIsAligned);
@@ -464,7 +462,7 @@ public class DatagramDispatcher extends Handler {
        mSendSatelliteDatagramRequest = null;
        SatelliteManager.SatelliteException exception =
                new SatelliteManager.SatelliteException(
                        SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE);
                        SATELLITE_RESULT_NOT_REACHABLE);
        Message message = obtainMessage(EVENT_SEND_SATELLITE_DATAGRAM_DONE, request);
        AsyncResult.forMessage(message, null, exception);
        message.sendToTarget();
@@ -646,6 +644,7 @@ public class DatagramDispatcher extends Handler {
        stopSatelliteAlignedTimer();
        stopDatagramWaitForConnectedStateTimer();
        stopWaitForDatagramSendingResponseTimer();
        stopWaitForSimulatedPollDatagramsDelayTimer();
        mIsDemoMode = false;
        mSendSatelliteDatagramRequest = null;
        mIsAligned = false;
@@ -703,12 +702,12 @@ public class DatagramDispatcher extends Handler {
            mDatagramController.updateSendStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
                    SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED,
                    getPendingDatagramCount(),
                    SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE);
                    SATELLITE_RESULT_NOT_REACHABLE);
            mDatagramController.updateSendStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
                    SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
                    0, SatelliteManager.SATELLITE_RESULT_SUCCESS);
            abortSendingPendingDatagrams(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
                    SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE);
                    SATELLITE_RESULT_NOT_REACHABLE);
        }
    }

@@ -811,15 +810,38 @@ public class DatagramDispatcher extends Handler {
        }
    }

    private void pollPendingSatelliteDatagrams(int subId) {
        logd("pollPendingSatelliteDatagrams");
    private void startWaitForSimulatedPollDatagramsDelayTimer(
            @NonNull DatagramDispatcherHandlerRequest request) {
        if (mIsDemoMode) {
            logd("startWaitForSimulatedPollDatagramsDelayTimer");
            sendMessageDelayed(
                    obtainMessage(EVENT_WAIT_FOR_SIMULATED_POLL_DATAGRAMS_DELAY_TIMED_OUT, request),
                    getDemoTimeoutDuration());
        } else {
            logd("Should not start WaitForSimulatedPollDatagramsDelayTimer in non-demo mode");
        }
    }

    private void stopWaitForSimulatedPollDatagramsDelayTimer() {
        removeMessages(EVENT_WAIT_FOR_SIMULATED_POLL_DATAGRAMS_DELAY_TIMED_OUT);
    }

    private void handleEventWaitForSimulatedPollDatagramsDelayTimedOut(
            @NonNull SendSatelliteDatagramArgument argument) {
        if (mIsDemoMode) {
            logd("handleEventWaitForSimulatedPollDatagramsDelayTimedOut");
            mDatagramController.pushDemoModeDatagram(argument.datagramType, argument.datagram);
            Consumer<Integer> internalCallback = new Consumer<Integer>() {
                @Override
                public void accept(Integer result) {
                    logd("pollPendingSatelliteDatagrams result: " + result);
                }
            };
        mDatagramController.pollPendingSatelliteDatagrams(subId, internalCallback);
            mDatagramController.pollPendingSatelliteDatagrams(argument.subId, internalCallback);
        } else {
            logd("Unexpected EVENT_WAIT_FOR_SIMULATED_POLL_DATAGRAMS_DELAY_TIMED_OUT in "
                    + "non-demo mode");
        }
    }

    long getDemoTimeoutDuration() {
+1 −1
Original line number Diff line number Diff line
@@ -743,7 +743,7 @@ public class DatagramReceiver extends Handler {
    }

    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    protected void setDeviceAlignedWithSatellite(boolean isAligned) {
    public void setDeviceAlignedWithSatellite(boolean isAligned) {
        synchronized (mLock) {
            mIsAligned = isAligned;
            logd("setDeviceAlignedWithSatellite: " + mIsAligned);
+189 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.telephony.satellite;

import static android.telephony.satellite.SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE;
import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE;
import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING;
import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING;
import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.os.Looper;
import android.telephony.satellite.SatelliteDatagram;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;

import com.android.internal.telephony.TelephonyTest;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.function.Consumer;

@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class DatagramControllerTest extends TelephonyTest {
    private static final String TAG = "DatagramControllerTest";

    private DatagramController mDatagramControllerUT;

    @Mock private DatagramReceiver mMockDatagramReceiver;
    @Mock private DatagramDispatcher mMockDatagramDispatcher;
    @Mock private PointingAppController mMockPointingAppController;
    @Mock private SatelliteSessionController mMockSatelliteSessionController;

    private static final int SUB_ID = 0;

    @Before
    public void setUp() throws Exception {
        super.setUp(getClass().getSimpleName());
        MockitoAnnotations.initMocks(this);
        logd(TAG + " Setup!");

        replaceInstance(DatagramDispatcher.class, "sInstance", null,
                mMockDatagramDispatcher);
        replaceInstance(DatagramReceiver.class, "sInstance", null,
                mMockDatagramReceiver);
        replaceInstance(SatelliteSessionController.class, "sInstance", null,
                mMockSatelliteSessionController);
        when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
        mDatagramControllerUT = new DatagramController(
                mContext, Looper.myLooper(), mMockPointingAppController);

        // Move both send and receive to IDLE state
        mDatagramControllerUT.updateSendStatus(SUB_ID, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
                0, SATELLITE_RESULT_SUCCESS);
        mDatagramControllerUT.updateReceiveStatus(SUB_ID, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
                0, SATELLITE_RESULT_SUCCESS);
        pushDemoModeSosDatagram();
    }

    @After
    public void tearDown() throws Exception {
        logd(TAG + " tearDown");
        super.tearDown();
    }

    @Test
    public void testUpdateSendStatus() throws Exception {
        testUpdateSendStatus(true, SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING);
        testUpdateSendStatus(true, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE);
        testUpdateSendStatus(false, SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING);
    }

    @Test
    public void testUpdateReceiveStatus() throws Exception {
        testUpdateReceiveStatus(true, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING);
        testUpdateReceiveStatus(true, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE);
        testUpdateReceiveStatus(false, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING);
    }

    @Test
    public void testSetDeviceAlignedWithSatellite() throws Exception {
        testSetDeviceAlignedWithSatellite(true);
        testSetDeviceAlignedWithSatellite(false);
    }

    private void testUpdateSendStatus(boolean isDemoMode, int sendState) {
        mDatagramControllerUT.setDemoMode(isDemoMode);
        clearAllInvocations();

        int sendPendingCount = 1;
        int errorCode = SATELLITE_RESULT_SUCCESS;
        mDatagramControllerUT.updateSendStatus(SUB_ID, sendState, sendPendingCount, errorCode);

        verify(mMockSatelliteSessionController)
                .onDatagramTransferStateChanged(eq(sendState), anyInt());
        verify(mMockPointingAppController).updateSendDatagramTransferState(
                eq(SUB_ID), eq(sendState), eq(sendPendingCount), eq(errorCode));

        if (isDemoMode) {
            if (sendState == SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE) {
                verify(mMockDatagramReceiver).pollPendingSatelliteDatagrams(
                        anyInt(), any(Consumer.class));
            }
        } else {
            verify(mMockDatagramReceiver, never()).pollPendingSatelliteDatagrams(
                    anyInt(), any(Consumer.class));
        }
    }

    private void testUpdateReceiveStatus(boolean isDemoMode, int receiveState) {
        mDatagramControllerUT.setDemoMode(isDemoMode);
        clearAllInvocations();

        int receivePendingCount = 1;
        int errorCode = SATELLITE_RESULT_SUCCESS;
        mDatagramControllerUT.updateReceiveStatus(
                SUB_ID, receiveState, receivePendingCount, errorCode);

        verify(mMockSatelliteSessionController)
                .onDatagramTransferStateChanged(anyInt(), eq(receiveState));
        verify(mMockPointingAppController).updateReceiveDatagramTransferState(
                eq(SUB_ID), eq(receiveState), eq(receivePendingCount), eq(errorCode));

        if (isDemoMode && receiveState == SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE) {
            verify(mMockDatagramReceiver).pollPendingSatelliteDatagrams(
                    anyInt(), any(Consumer.class));
        } else {
            verify(mMockDatagramReceiver, never()).pollPendingSatelliteDatagrams(
                    anyInt(), any(Consumer.class));
        }
    }

    private void testSetDeviceAlignedWithSatellite(boolean isAligned) {
        mDatagramControllerUT.setDemoMode(true);
        clearAllInvocations();

        mDatagramControllerUT.setDeviceAlignedWithSatellite(isAligned);
        verify(mMockDatagramDispatcher).setDeviceAlignedWithSatellite(eq(isAligned));
        verify(mMockDatagramReceiver).setDeviceAlignedWithSatellite(eq(isAligned));
        if (isAligned) {
            verify(mMockDatagramReceiver).pollPendingSatelliteDatagrams(
                    anyInt(), any(Consumer.class));
        } else {
            verify(mMockDatagramReceiver, never()).pollPendingSatelliteDatagrams(
                    anyInt(), any(Consumer.class));
        }
    }

    private void clearAllInvocations() {
        clearInvocations(mMockSatelliteSessionController);
        clearInvocations(mMockPointingAppController);
        clearInvocations(mMockDatagramReceiver);
        clearInvocations(mMockDatagramDispatcher);
    }

    private void pushDemoModeSosDatagram() {
        String testMessage = "This is a test datagram message";
        SatelliteDatagram datagram = new SatelliteDatagram(testMessage.getBytes());
        mDatagramControllerUT.setDemoMode(true);
        mDatagramControllerUT.pushDemoModeDatagram(DATAGRAM_TYPE_SOS_MESSAGE, datagram);
    }
}
Loading