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

Commit b6c01756 authored by Hakjun Choi's avatar Hakjun Choi Committed by Thomas Nguyen
Browse files

Satellite demo mode : Simulated sending and receiving

Message sending/receive is considered successful when the device is towards satellite within a reasonable margin

Bug: 276058936
Test: atest DatagramDispatcherTest, DatagramReceiverTest
Test: cts/SatelliteManagerTest, SatelliteManagerTestOnMockService

Change-Id: Iaf91810a85f0ade3a8adf0d4963aeea1e21e3f79
parent a70f7264
Loading
Loading
Loading
Loading
+42 −17
Original line number Diff line number Diff line
@@ -18,15 +18,17 @@ package com.android.internal.telephony.satellite;

import android.annotation.NonNull;
import android.content.Context;
import android.os.Build;
import android.os.Looper;
import android.os.SystemProperties;
import android.telephony.Rlog;
import android.telephony.SubscriptionManager;
import android.telephony.satellite.ISatelliteDatagramCallback;
import android.telephony.satellite.SatelliteDatagram;
import android.telephony.satellite.SatelliteManager;

import com.android.internal.annotations.VisibleForTesting;

import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

/**
@@ -42,6 +44,9 @@ public class DatagramController {
    @NonNull private final DatagramReceiver mDatagramReceiver;
    public static final long MAX_DATAGRAM_ID = (long) Math.pow(2, 16);
    public static final int ROUNDING_UNIT = 10;
    public static final long SATELLITE_ALIGN_TIMEOUT = TimeUnit.SECONDS.toMillis(30);
    private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem";
    private static final boolean DEBUG = !"user".equals(Build.TYPE);

    /** Variables used to update onSendDatagramStateChanged(). */
    private int mSendSubId;
@@ -57,6 +62,7 @@ public class DatagramController {
    private int mReceiveErrorCode = SatelliteManager.SATELLITE_ERROR_NONE;
    private SatelliteDatagram mDemoModeDatagram;
    private boolean mIsDemoMode = false;
    private long mAlignTimeoutDuration = SATELLITE_ALIGN_TIMEOUT;

    /**
     * @return The singleton instance of DatagramController.
@@ -240,25 +246,18 @@ public class DatagramController {
     * @param state Current satellite modem state.
     */
    public void onSatelliteModemStateChanged(@SatelliteManager.SatelliteModemState int state) {
        if (state == SatelliteManager.SATELLITE_MODEM_STATE_OFF
                || state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE) {
            logd("onSatelliteModemStateChanged: cleaning up resources");
            cleanUpResources();
        }
        mDatagramDispatcher.onSatelliteModemStateChanged(state);
        mDatagramReceiver.onSatelliteModemStateChanged(state);
    }

    private void cleanUpResources() {
        if (mReceiveDatagramTransferState
                == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING) {
            updateReceiveStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
                    SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED,
                    mReceivePendingCount,
                    SatelliteManager.SATELLITE_REQUEST_ABORTED);
    void onDeviceAlignedWithSatellite(boolean isAligned) {
        mDatagramDispatcher.onDeviceAlignedWithSatellite(isAligned);
        mDatagramReceiver.onDeviceAlignedWithSatellite(isAligned);
    }
        updateReceiveStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
                SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, 0,
                SatelliteManager.SATELLITE_ERROR_NONE);

    boolean isReceivingDatagrams() {
        return (mReceiveDatagramTransferState
                == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING);
    }

    /**
@@ -294,6 +293,32 @@ public class DatagramController {
        }
    }

    long getSatelliteAlignedTimeoutDuration() {
        return mAlignTimeoutDuration;
    }

    /**
     * This API can be used by only CTS to update the timeout duration in milliseconds whether
     * the device is aligned with the satellite for demo mode
     *
     * @param timeoutMillis The timeout duration in millisecond.
     * @return {@code true} if the timeout duration is set successfully, {@code false} otherwise.
     */
    boolean setSatelliteDeviceAlignedTimeoutDuration(long timeoutMillis) {
        if (!isMockModemAllowed()) {
            loge("Updating align timeout duration is not allowed");
            return false;
        }

        logd("setSatelliteDeviceAlignedTimeoutDuration: timeoutMillis=" + timeoutMillis);
        mAlignTimeoutDuration = timeoutMillis;
        return true;
    }

    private boolean isMockModemAllowed() {
        return (DEBUG || SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false));
    }

    private void notifyDatagramTransferStateChangedToSessionController() {
        SatelliteSessionController sessionController = SatelliteSessionController.getInstance();
        if (sessionController == null) {
+94 −5
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ public class DatagramDispatcher extends Handler {

    private static final int CMD_SEND_SATELLITE_DATAGRAM = 1;
    private static final int EVENT_SEND_SATELLITE_DATAGRAM_DONE = 2;
    private static final int EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT = 3;

    @NonNull private static DatagramDispatcher sInstance;
    @NonNull private final Context mContext;
@@ -57,6 +58,8 @@ public class DatagramDispatcher extends Handler {
    @NonNull private final ControllerMetricsStats mControllerMetricsStats;

    private boolean mIsDemoMode = false;
    private boolean mIsAligned = false;
    private DatagramDispatcherHandlerRequest mSendSatelliteDatagramRequest = null;

    private static AtomicLong mNextDatagramId = new AtomicLong(0);

@@ -138,6 +141,7 @@ public class DatagramDispatcher extends Handler {
        public boolean needFullScreenPointingUI;
        public @NonNull Consumer<Integer> callback;
        public long datagramStartTime;
        public boolean skipCheckingSatelliteAligned = false;

        SendSatelliteDatagramArgument(int subId, long datagramId,
                @SatelliteManager.DatagramType int datagramType,
@@ -233,11 +237,22 @@ public class DatagramDispatcher extends Handler {
                int error = SatelliteServiceUtils.getSatelliteError(ar, "sendSatelliteDatagram");
                SendSatelliteDatagramArgument argument =
                        (SendSatelliteDatagramArgument) request.argument;

                synchronized (mLock) {
                    if (mIsDemoMode && (error == SatelliteManager.SATELLITE_ERROR_NONE)) {
                        if (argument.skipCheckingSatelliteAligned) {
                            logd("Satellite was already aligned. No need to check alignment again");
                        } else if (!mIsAligned) {
                            logd("Satellite is not aligned in demo mode, wait for the alignment.");
                            startSatelliteAlignedTimer(request);
                            break;
                        }
                    }

                    logd("EVENT_SEND_SATELLITE_DATAGRAM_DONE error: " + error);
                    // log metrics about the outgoing datagram
                    reportSendDatagramCompleted(argument, error);

                synchronized (mLock) {
                    mSendingDatagramInProgress = false;

                    // Remove current datagram from pending map.
@@ -288,6 +303,11 @@ public class DatagramDispatcher extends Handler {
                break;
            }

            case EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT: {
                handleEventSatelliteAlignedTimeout((DatagramDispatcherHandlerRequest) msg.obj);
                break;
            }

            default:
                logw("DatagramDispatcherHandler: unexpected message code: " + msg.what);
                break;
@@ -344,11 +364,74 @@ public class DatagramDispatcher extends Handler {
     *
     * @param isDemoMode {@code true} means demo mode is on, {@code false} otherwise.
     */
    @VisibleForTesting
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    protected void setDemoMode(boolean isDemoMode) {
        mIsDemoMode = isDemoMode;
    }

    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    protected void onDeviceAlignedWithSatellite(boolean isAligned) {
        if (mIsDemoMode) {
            synchronized (mLock) {
                mIsAligned = isAligned;
                if (isAligned) handleEventSatelliteAligned();
            }
        }
    }

    private void startSatelliteAlignedTimer(@NonNull DatagramDispatcherHandlerRequest request) {
        if (isSatelliteAlignedTimerStarted()) {
            logd("Satellite aligned timer was already started");
            return;
        }
        mSendSatelliteDatagramRequest = request;
        sendMessageDelayed(
                obtainMessage(EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT, request),
                getSatelliteAlignedTimeoutDuration());
    }

    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    protected long getSatelliteAlignedTimeoutDuration() {
        return mDatagramController.getSatelliteAlignedTimeoutDuration();
    }

    private void handleEventSatelliteAligned() {
        if (isSatelliteAlignedTimerStarted()) {
            stopSatelliteAlignedTimer();

            if (mSendSatelliteDatagramRequest == null) {
                loge("handleEventSatelliteAligned: mSendSatelliteDatagramRequest is null");
            } else {
                SendSatelliteDatagramArgument argument =
                        (SendSatelliteDatagramArgument) mSendSatelliteDatagramRequest.argument;
                argument.skipCheckingSatelliteAligned = true;
                Message message = obtainMessage(
                        EVENT_SEND_SATELLITE_DATAGRAM_DONE, mSendSatelliteDatagramRequest);
                mSendSatelliteDatagramRequest = null;
                AsyncResult.forMessage(message, null, null);
                message.sendToTarget();
            }
        }
    }

    private void handleEventSatelliteAlignedTimeout(
            @NonNull DatagramDispatcherHandlerRequest request) {
        SatelliteManager.SatelliteException exception =
                new SatelliteManager.SatelliteException(
                        SatelliteManager.SATELLITE_NOT_REACHABLE);
        Message message = obtainMessage(EVENT_SEND_SATELLITE_DATAGRAM_DONE, request);
        AsyncResult.forMessage(message, null, exception);
        message.sendToTarget();
    }

    private boolean isSatelliteAlignedTimerStarted() {
        return hasMessages(EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT);
    }

    private void stopSatelliteAlignedTimer() {
        removeMessages(EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT);
    }

    /**
     * Send pending satellite datagrams. Emergency datagrams are given priority over
     * non-emergency datagrams.
@@ -480,7 +563,8 @@ public class DatagramDispatcher extends Handler {
        synchronized (mLock) {
            mSendingDatagramInProgress = false;
            if (getPendingDatagramCount() > 0) {
                mDatagramController.updateSendStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
                mDatagramController.updateSendStatus(
                        SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
                        SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED,
                        getPendingDatagramCount(), SatelliteManager.SATELLITE_REQUEST_ABORTED);
            }
@@ -489,6 +573,11 @@ public class DatagramDispatcher extends Handler {
                    0, SatelliteManager.SATELLITE_ERROR_NONE);
            abortSendingPendingDatagrams(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
                    SatelliteManager.SATELLITE_REQUEST_ABORTED);

            stopSatelliteAlignedTimer();
            mIsDemoMode = false;
            mSendSatelliteDatagramRequest = null;
            mIsAligned = false;
        }
    }

+127 −5
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import android.os.Message;
import android.os.RemoteException;
import android.provider.Telephony;
import android.telephony.Rlog;
import android.telephony.SubscriptionManager;
import android.telephony.satellite.ISatelliteDatagramCallback;
import android.telephony.satellite.SatelliteDatagram;
import android.telephony.satellite.SatelliteManager;
@@ -62,6 +63,7 @@ public class DatagramReceiver extends Handler {

    private static final int CMD_POLL_PENDING_SATELLITE_DATAGRAMS = 1;
    private static final int EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE = 2;
    private static final int EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT = 3;

    /** Key used to read/write satellite datagramId in shared preferences. */
    private static final String SATELLITE_DATAGRAM_ID_KEY = "satellite_datagram_id_key";
@@ -77,6 +79,9 @@ public class DatagramReceiver extends Handler {

    private long mDatagramTransferStartTime = 0;
    private boolean mIsDemoMode = false;
    private boolean mIsAligned = false;
    private DatagramReceiverHandlerRequest mPollPendingSatelliteDatagramsRequest = null;
    private final Object mLock = new Object();

    /**
     * Map key: subId, value: SatelliteDatagramListenerHandler to notify registrants.
@@ -491,6 +496,11 @@ public class DatagramReceiver extends Handler {
                ((Consumer<Integer>) request.argument).accept(error);
                break;
            }

            case EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT: {
                handleEventSatelliteAlignedTimeout((DatagramReceiverHandlerRequest) msg.obj);
                break;
            }
        }
    }

@@ -577,21 +587,73 @@ public class DatagramReceiver extends Handler {
                SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING,
                mDatagramController.getReceivePendingCount(),
                SatelliteManager.SATELLITE_ERROR_NONE);

        mDatagramTransferStartTime = System.currentTimeMillis();
        Phone phone = SatelliteServiceUtils.getPhone();

        if (mIsDemoMode) {
            DatagramReceiverHandlerRequest request = new DatagramReceiverHandlerRequest(
                    callback, phone, subId);
            AsyncResult ar = new AsyncResult(request, SatelliteManager.SATELLITE_ERROR_NONE, null);
            Message msg = this.obtainMessage(EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE, ar);
            synchronized (mLock) {
                if (mIsAligned) {
                    Message msg = obtainMessage(EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE,
                            request);
                    AsyncResult.forMessage(msg, null, null);
                    msg.sendToTarget();
                } else {
                    startSatelliteAlignedTimer(request);
                }
            }
        } else {
            sendRequestAsync(CMD_POLL_PENDING_SATELLITE_DATAGRAMS, callback, phone, subId);
        }
    }

    /**
     * This function is used by {@link DatagramController} to notify {@link DatagramReceiver}
     * that satellite modem state has changed.
     *
     * @param state Current satellite modem state.
     */
    public void onSatelliteModemStateChanged(@SatelliteManager.SatelliteModemState int state) {
        if (state == SatelliteManager.SATELLITE_MODEM_STATE_OFF
                || state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE) {
            logd("onSatelliteModemStateChanged: cleaning up resources");
            cleanUpResources();
        }
    }

    private void cleanupDemoModeResources() {
        if (isSatelliteAlignedTimerStarted()) {
            stopSatelliteAlignedTimer();
            if (mPollPendingSatelliteDatagramsRequest == null) {
                loge("Satellite aligned timer was started "
                        + "but mPollPendingSatelliteDatagramsRequest is null");
            } else {
                Consumer<Integer> callback =
                        (Consumer<Integer>) mPollPendingSatelliteDatagramsRequest.argument;
                callback.accept(SatelliteManager.SATELLITE_REQUEST_ABORTED);
            }
        }
        mIsDemoMode = false;
        mPollPendingSatelliteDatagramsRequest = null;
        mIsAligned = false;
    }

    private void cleanUpResources() {
        synchronized (mLock) {
            if (mDatagramController.isReceivingDatagrams()) {
                mDatagramController.updateReceiveStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
                        SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED,
                        mDatagramController.getReceivePendingCount(),
                        SatelliteManager.SATELLITE_REQUEST_ABORTED);
            }
            mDatagramController.updateReceiveStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
                    SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, 0,
                    SatelliteManager.SATELLITE_ERROR_NONE);
            cleanupDemoModeResources();
        }
    }

    /**
     * Posts the specified command to be executed on the main thread and returns immediately.
     *
@@ -637,11 +699,71 @@ public class DatagramReceiver extends Handler {
     *
     * @param isDemoMode {@code true} means demo mode is on, {@code false} otherwise.
     */
    @VisibleForTesting
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    protected void setDemoMode(boolean isDemoMode) {
        mIsDemoMode = isDemoMode;
    }

    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    protected void onDeviceAlignedWithSatellite(boolean isAligned) {
        if (mIsDemoMode) {
            synchronized (mLock) {
                mIsAligned = isAligned;
                if (isAligned) handleEventSatelliteAligned();
            }
        }
    }

    private void startSatelliteAlignedTimer(DatagramReceiverHandlerRequest request) {
        if (isSatelliteAlignedTimerStarted()) {
            logd("Satellite aligned timer was already started");
            return;
        }
        mPollPendingSatelliteDatagramsRequest = request;
        sendMessageDelayed(
                obtainMessage(EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT, request),
                getSatelliteAlignedTimeoutDuration());
    }

    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    protected long getSatelliteAlignedTimeoutDuration() {
        return mDatagramController.getSatelliteAlignedTimeoutDuration();
    }

    private void handleEventSatelliteAligned() {
        if (isSatelliteAlignedTimerStarted()) {
            stopSatelliteAlignedTimer();

            if (mPollPendingSatelliteDatagramsRequest == null) {
                loge("handleSatelliteAlignedTimer: mPollPendingSatelliteDatagramsRequest is null");
            } else {
                Message message = obtainMessage(
                        EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE,
                        mPollPendingSatelliteDatagramsRequest);
                mPollPendingSatelliteDatagramsRequest = null;
                AsyncResult.forMessage(message, null, null);
                message.sendToTarget();
            }
        }
    }

    private void handleEventSatelliteAlignedTimeout(DatagramReceiverHandlerRequest request) {
        SatelliteManager.SatelliteException exception =
                new SatelliteManager.SatelliteException(
                        SatelliteManager.SATELLITE_NOT_REACHABLE);
        Message message = obtainMessage(EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE, request);
        AsyncResult.forMessage(message, null, exception);
        message.sendToTarget();
    }

    private boolean isSatelliteAlignedTimerStarted() {
        return hasMessages(EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT);
    }

    private void stopSatelliteAlignedTimer() {
        removeMessages(EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT);
    }

    /**
     * Destroys this DatagramDispatcher. Used for tearing down static resources during testing.
     */
+22 −1
Original line number Diff line number Diff line
@@ -702,7 +702,7 @@ public class SatelliteController extends Handler {
                    IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
                        @Override
                        public void accept(int result) {
                            loge("Failed to Disable Satellite Mode, Error: " + result);
                            logd("RequestSatelliteEnabled: result=" + result);
                        }
                    };
                    Phone phone = SatelliteServiceUtils.getPhone();
@@ -1441,6 +1441,16 @@ public class SatelliteController extends Handler {
        sendRequestAsync(CMD_GET_TIME_SATELLITE_NEXT_VISIBLE, result, phone);
    }

    /**
     * Inform whether the device is aligned with satellite for demo mode.
     *
     * @param subId The subId of the subscription.
     * @param isAligned {@true} means device is aligned with the satellite, otherwise {@false}.
     */
    public void onDeviceAlignedWithSatellite(@NonNull int subId, @NonNull boolean isAligned) {
        mDatagramController.onDeviceAlignedWithSatellite(isAligned);
    }

    /**
     * This API can be used by only CTS to update satellite vendor service package name.
     *
@@ -1492,6 +1502,17 @@ public class SatelliteController extends Handler {
        return mSatelliteSessionController.setSatelliteListeningTimeoutDuration(timeoutMillis);
    }

    /**
     * This API can be used by only CTS to update the timeout duration in milliseconds whether
     * the device is aligned with the satellite for demo mode
     *
     * @param timeoutMillis The timeout duration in millisecond.
     * @return {@code true} if the timeout duration is set successfully, {@code false} otherwise.
     */
    public boolean setSatelliteDeviceAlignedTimeoutDuration(long timeoutMillis) {
        return mDatagramController.setSatelliteDeviceAlignedTimeoutDuration(timeoutMillis);
    }

    /**
     * This API can be used by only CTS to update satellite gateway service package name.
     *
+66 −1

File changed.

Preview size limit exceeded, changes collapsed.

Loading