Loading src/java/com/android/internal/telephony/satellite/DatagramController.java +40 −4 Original line number Diff line number Diff line Loading @@ -16,6 +16,9 @@ package com.android.internal.telephony.satellite; import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED; import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING; import android.annotation.NonNull; import android.content.Context; import android.os.Build; Loading Loading @@ -46,6 +49,8 @@ public class DatagramController { 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); public static final long DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMEOUT = TimeUnit.SECONDS.toMillis(60); private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem"; private static final boolean DEBUG = !"user".equals(Build.TYPE); Loading Loading @@ -74,6 +79,10 @@ public class DatagramController { private SatelliteDatagram mDemoModeDatagram; private boolean mIsDemoMode = false; private long mAlignTimeoutDuration = SATELLITE_ALIGN_TIMEOUT; private long mDatagramWaitTimeForConnectedState = DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMEOUT; @GuardedBy("mLock") @SatelliteManager.SatelliteModemState private int mSatelltieModemState = SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN; /** * @return The singleton instance of DatagramController. Loading Loading @@ -267,6 +276,9 @@ public class DatagramController { * @param state Current satellite modem state. */ public void onSatelliteModemStateChanged(@SatelliteManager.SatelliteModemState int state) { synchronized (mLock) { mSatelltieModemState = state; } mDatagramDispatcher.onSatelliteModemStateChanged(state); mDatagramReceiver.onSatelliteModemStateChanged(state); } Loading @@ -284,17 +296,35 @@ public class DatagramController { } } /** * Check if Telephony needs to wait for the modem satellite connected to a satellite network * before transferring datagrams via satellite. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public boolean needsWaitingForSatelliteConnected() { synchronized (mLock) { if (SatelliteController.getInstance().isSatelliteAttachRequired() && mSatelltieModemState != SATELLITE_MODEM_STATE_CONNECTED && mSatelltieModemState != SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING) { return true; } return false; } } public boolean isSendingInIdleState() { synchronized (mLock) { return mSendDatagramTransferState == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE; return (mSendDatagramTransferState == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE) && (mDatagramDispatcher.getPendingDatagramCount() == 0); } } public boolean isPollingInIdleState() { synchronized (mLock) { return mReceiveDatagramTransferState == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE; return (mReceiveDatagramTransferState == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE) && !mDatagramReceiver.isPollingPending(); } } Loading Loading @@ -336,6 +366,11 @@ public class DatagramController { return mAlignTimeoutDuration; } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public long getDatagramWaitTimeForConnectedState() { return mDatagramWaitTimeForConnectedState; } /** * 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 Loading @@ -351,6 +386,7 @@ public class DatagramController { logd("setSatelliteDeviceAlignedTimeoutDuration: timeoutMillis=" + timeoutMillis); mAlignTimeoutDuration = timeoutMillis; mDatagramWaitTimeForConnectedState = timeoutMillis; return true; } Loading src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java +53 −5 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.internal.telephony.satellite; import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED; import static com.android.internal.telephony.satellite.DatagramController.ROUNDING_UNIT; import android.annotation.NonNull; Loading Loading @@ -51,6 +53,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; private static final int EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT = 4; @NonNull private static DatagramDispatcher sInstance; @NonNull private final Context mContext; Loading Loading @@ -308,6 +311,10 @@ public class DatagramDispatcher extends Handler { break; } case EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT: handleEventDatagramWaitForConnectedStateTimedOut(); break; default: logw("DatagramDispatcherHandler: unexpected message code: " + msg.what); break; Loading Loading @@ -350,8 +357,13 @@ public class DatagramDispatcher extends Handler { mPendingNonEmergencyDatagramsMap.put(datagramId, datagramArgs); } // Modem can be busy receiving datagrams, so send datagram only when modem is not busy. if (!mSendingDatagramInProgress && mDatagramController.isPollingInIdleState()) { if (mDatagramController.needsWaitingForSatelliteConnected()) { logd("sendSatelliteDatagram: wait for satellite connected"); SatelliteSessionController.getInstance().onSatelliteDatagramsTransferRequested(); startDatagramWaitForConnectedStateTimer(); } else if (!mSendingDatagramInProgress && mDatagramController.isPollingInIdleState()) { // Modem can be busy receiving datagrams, so send datagram only when modem is // not busy. mSendingDatagramInProgress = true; datagramArgs.setDatagramStartTime(); mDatagramController.updateSendStatus(subId, Loading Loading @@ -525,10 +537,11 @@ public class DatagramDispatcher extends Handler { * Return pending datagram count * @return pending datagram count */ @GuardedBy("mLock") private int getPendingDatagramCount() { public int getPendingDatagramCount() { synchronized (mLock) { return mPendingEmergencyDatagramsMap.size() + mPendingNonEmergencyDatagramsMap.size(); } } /** * Posts the specified command to be executed on the main thread and returns immediately. Loading Loading @@ -579,6 +592,12 @@ public class DatagramDispatcher extends Handler { } else if (state == SatelliteManager.SATELLITE_MODEM_STATE_IDLE) { sendPendingDatagrams(); } if (state == SATELLITE_MODEM_STATE_CONNECTED && isDatagramWaitForConnectedStateTimerStarted()) { stopDatagramWaitForConnectedStateTimer(); sendPendingDatagrams(); } } } Loading @@ -598,11 +617,40 @@ public class DatagramDispatcher extends Handler { SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED); stopSatelliteAlignedTimer(); stopDatagramWaitForConnectedStateTimer(); mIsDemoMode = false; mSendSatelliteDatagramRequest = null; mIsAligned = false; } private void startDatagramWaitForConnectedStateTimer() { if (isDatagramWaitForConnectedStateTimerStarted()) { logd("DatagramWaitForConnectedStateTimer is already started"); return; } sendMessageDelayed(obtainMessage( EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT), mDatagramController.getDatagramWaitTimeForConnectedState()); } private void stopDatagramWaitForConnectedStateTimer() { removeMessages(EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT); } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public boolean isDatagramWaitForConnectedStateTimerStarted() { return hasMessages(EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT); } private void handleEventDatagramWaitForConnectedStateTimedOut() { logw("Timed out to wait for satellite connected before sending datagrams"); synchronized (mLock) { abortSendingPendingDatagrams(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE); SatelliteSessionController.getInstance().onDatagramWaitForConnectedStateTimerTimedOut(); } } private static void logd(@NonNull String log) { Rlog.d(TAG, log); } Loading src/java/com/android/internal/telephony/satellite/DatagramReceiver.java +116 −11 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.internal.telephony.satellite; import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED; import static com.android.internal.telephony.satellite.DatagramController.ROUNDING_UNIT; import android.annotation.NonNull; Loading Loading @@ -65,6 +67,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; private static final int EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT = 4; /** Key used to read/write satellite datagramId in shared preferences. */ private static final String SATELLITE_DATAGRAM_ID_KEY = "satellite_datagram_id_key"; Loading @@ -82,7 +85,10 @@ public class DatagramReceiver extends Handler { private boolean mIsDemoMode = false; @GuardedBy("mLock") private boolean mIsAligned = false; private DatagramReceiverHandlerRequest mPollPendingSatelliteDatagramsRequest = null; @Nullable private DatagramReceiverHandlerRequest mDemoPollPendingSatelliteDatagramsRequest = null; @Nullable private DatagramReceiverHandlerRequest mPendingPollSatelliteDatagramsRequest = null; private final Object mLock = new Object(); /** Loading Loading @@ -497,6 +503,14 @@ public class DatagramReceiver extends Handler { handleEventSatelliteAlignedTimeout((DatagramReceiverHandlerRequest) msg.obj); break; } case EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT: handleEventDatagramWaitForConnectedStateTimedOut(); break; default: logw("DatagramDispatcherHandler: unexpected message code: " + msg.what); break; } } Loading Loading @@ -585,10 +599,38 @@ public class DatagramReceiver extends Handler { callback.accept(SatelliteManager.SATELLITE_RESULT_MODEM_BUSY); return; } pollPendingSatelliteDatagramsInternal(subId, callback); } /** * Check if DatagramReceiver is waiting for satellite modem connected to a satellite network * before pushing down the poll request to modem. */ public boolean isPollingPending() { synchronized (mLock) { return (mPendingPollSatelliteDatagramsRequest != null); } } private void handleSatelliteConnectedEvent() { synchronized (mLock) { if (isDatagramWaitForConnectedStateTimerStarted()) { stopDatagramWaitForConnectedStateTimer(); if (mPendingPollSatelliteDatagramsRequest == null) { loge("handleSatelliteConnectedEvent: mPendingPollSatelliteDatagramsRequest is" + " null"); return; } Consumer<Integer> callback = (Consumer<Integer>) mPendingPollSatelliteDatagramsRequest.argument; pollPendingSatelliteDatagramsInternal( mPendingPollSatelliteDatagramsRequest.subId, callback); mPendingPollSatelliteDatagramsRequest = null; } } } private void pollPendingSatelliteDatagramsInternal(int subId, @NonNull Consumer<Integer> callback) { if (!mDatagramController.isSendingInIdleState()) { Loading @@ -598,6 +640,17 @@ public class DatagramReceiver extends Handler { return; } if (mDatagramController.needsWaitingForSatelliteConnected()) { logd("pollPendingSatelliteDatagrams: wait for satellite connected"); synchronized (mLock) { mPendingPollSatelliteDatagramsRequest = new DatagramReceiverHandlerRequest( callback, SatelliteServiceUtils.getPhone(), subId); SatelliteSessionController.getInstance().onSatelliteDatagramsTransferRequested(); startDatagramWaitForConnectedStateTimer(); } return; } mDatagramController.updateReceiveStatus(subId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING, mDatagramController.getReceivePendingCount(), Loading Loading @@ -635,6 +688,8 @@ public class DatagramReceiver extends Handler { || state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE) { logd("onSatelliteModemStateChanged: cleaning up resources"); cleanUpResources(); } else if (state == SATELLITE_MODEM_STATE_CONNECTED) { handleSatelliteConnectedEvent(); } } } Loading @@ -643,22 +698,31 @@ public class DatagramReceiver extends Handler { private void cleanupDemoModeResources() { if (isSatelliteAlignedTimerStarted()) { stopSatelliteAlignedTimer(); if (mPollPendingSatelliteDatagramsRequest == null) { if (mDemoPollPendingSatelliteDatagramsRequest == null) { loge("Satellite aligned timer was started " + "but mPollPendingSatelliteDatagramsRequest is null"); + "but mDemoPollPendingSatelliteDatagramsRequest is null"); } else { Consumer<Integer> callback = (Consumer<Integer>) mPollPendingSatelliteDatagramsRequest.argument; (Consumer<Integer>) mDemoPollPendingSatelliteDatagramsRequest.argument; callback.accept(SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED); } } mIsDemoMode = false; mPollPendingSatelliteDatagramsRequest = null; mDemoPollPendingSatelliteDatagramsRequest = null; mIsAligned = false; } @GuardedBy("mLock") private void cleanUpResources() { synchronized (mLock) { if (mPendingPollSatelliteDatagramsRequest != null) { Consumer<Integer> callback = (Consumer<Integer>) mPendingPollSatelliteDatagramsRequest.argument; callback.accept(SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED); mPendingPollSatelliteDatagramsRequest = null; } stopDatagramWaitForConnectedStateTimer(); } if (mDatagramController.isReceivingDatagrams()) { mDatagramController.updateReceiveStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED, Loading Loading @@ -736,7 +800,7 @@ public class DatagramReceiver extends Handler { logd("Satellite aligned timer was already started"); return; } mPollPendingSatelliteDatagramsRequest = request; mDemoPollPendingSatelliteDatagramsRequest = request; sendMessageDelayed( obtainMessage(EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT, request), getSatelliteAlignedTimeoutDuration()); Loading @@ -751,13 +815,14 @@ public class DatagramReceiver extends Handler { if (isSatelliteAlignedTimerStarted()) { stopSatelliteAlignedTimer(); if (mPollPendingSatelliteDatagramsRequest == null) { loge("handleSatelliteAlignedTimer: mPollPendingSatelliteDatagramsRequest is null"); if (mDemoPollPendingSatelliteDatagramsRequest == null) { loge("handleSatelliteAlignedTimer: mDemoPollPendingSatelliteDatagramsRequest " + "is null"); } else { Message message = obtainMessage( EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE, mPollPendingSatelliteDatagramsRequest); mPollPendingSatelliteDatagramsRequest = null; mDemoPollPendingSatelliteDatagramsRequest); mDemoPollPendingSatelliteDatagramsRequest = null; AsyncResult.forMessage(message, null, null); message.sendToTarget(); } Loading @@ -781,6 +846,42 @@ public class DatagramReceiver extends Handler { removeMessages(EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT); } private void startDatagramWaitForConnectedStateTimer() { if (isDatagramWaitForConnectedStateTimerStarted()) { logd("DatagramWaitForConnectedStateTimer is already started"); return; } sendMessageDelayed(obtainMessage( EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT), mDatagramController.getDatagramWaitTimeForConnectedState()); } private void stopDatagramWaitForConnectedStateTimer() { removeMessages(EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT); } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public boolean isDatagramWaitForConnectedStateTimerStarted() { return hasMessages(EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT); } private void handleEventDatagramWaitForConnectedStateTimedOut() { synchronized (mLock) { if (mPendingPollSatelliteDatagramsRequest == null) { logw("handleEventDatagramWaitForConnectedStateTimedOut: " + "mPendingPollSatelliteDatagramsRequest is null"); return; } logw("Timed out to wait for satellite connected before polling datagrams"); Consumer<Integer> callback = (Consumer<Integer>) mPendingPollSatelliteDatagramsRequest.argument; callback.accept(SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE); mPendingPollSatelliteDatagramsRequest = null; SatelliteSessionController.getInstance().onDatagramWaitForConnectedStateTimerTimedOut(); } } /** * Destroys this DatagramDispatcher. Used for tearing down static resources during testing. */ Loading @@ -796,4 +897,8 @@ public class DatagramReceiver extends Handler { private static void loge(@NonNull String log) { Rlog.e(TAG, log); } private static void logw(@NonNull String log) { Rlog.w(TAG, log); } } src/java/com/android/internal/telephony/satellite/SatelliteController.java +39 −3 Original line number Diff line number Diff line Loading @@ -71,6 +71,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.IIntegerConsumer; import com.android.internal.telephony.Phone; import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats; import com.android.internal.telephony.satellite.metrics.ProvisionMetricsStats; import com.android.internal.telephony.satellite.metrics.SessionMetricsStats; Loading Loading @@ -242,6 +243,7 @@ public class SatelliteController extends Handler { * {@code true} for enabled and {@code false} for disabled. */ @NonNull private final Map<Integer, Boolean> mIsSatelliteAttachEnabledForCarrierArrayPerSub = new HashMap<>(); @NonNull private final FeatureFlags mFeatureFlags; /** * @return The singleton instance of SatelliteController. */ Loading @@ -255,12 +257,13 @@ public class SatelliteController extends Handler { /** * Create the SatelliteController singleton instance. * @param context The Context to use to create the SatelliteController. * @param featureFlags The feature flag. */ public static void make(@NonNull Context context) { public static void make(@NonNull Context context, @NonNull FeatureFlags featureFlags) { if (sInstance == null) { HandlerThread satelliteThread = new HandlerThread(TAG); satelliteThread.start(); sInstance = new SatelliteController(context, satelliteThread.getLooper()); sInstance = new SatelliteController(context, satelliteThread.getLooper(), featureFlags); } } Loading @@ -270,12 +273,15 @@ public class SatelliteController extends Handler { * * @param context The Context for the SatelliteController. * @param looper The looper for the handler. It does not run on main thread. * @param featureFlags The feature flag. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public SatelliteController(@NonNull Context context, @NonNull Looper looper) { public SatelliteController( @NonNull Context context, @NonNull Looper looper, @NonNull FeatureFlags featureFlags) { super(looper); mContext = context; mFeatureFlags = featureFlags; Phone phone = SatelliteServiceUtils.getPhone(); mCi = phone.mCi; // Create the SatelliteModemInterface singleton, which is used to manage connections Loading Loading @@ -2128,6 +2134,30 @@ public class SatelliteController extends Handler { } } /** * Check whether satellite modem has to attach to a satellite network before sending/receiving * datagrams. * * @return {@code true} if satellite attach is required, {@code false} otherwise. */ public boolean isSatelliteAttachRequired() { if (!mFeatureFlags.oemEnabledSatelliteFlag()) { return false; } synchronized (mSatelliteCapabilitiesLock) { if (mSatelliteCapabilities == null) { loge("isSatelliteAttachRequired: mSatelliteCapabilities is null"); return false; } if (mSatelliteCapabilities.getSupportedRadioTechnologies().contains( SatelliteManager.NT_RADIO_TECHNOLOGY_NB_IOT_NTN)) { return true; } return false; } } /** * If we have not successfully queried the satellite modem for its satellite service support, * we will retry the query one more time. Otherwise, we will return the cached result. Loading Loading @@ -2477,6 +2507,12 @@ public class SatelliteController extends Handler { } mWaitingForSatelliteModemOff = false; } } else { if (mSatelliteSessionController != null) { mSatelliteSessionController.onSatelliteModemStateChanged(state); } else { loge("handleEventSatelliteModemStateChanged: mSatelliteSessionController is null"); } } mDatagramController.onSatelliteModemStateChanged(state); } Loading src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java +4 −0 Original line number Diff line number Diff line Loading @@ -150,6 +150,10 @@ public class SatelliteServiceUtils { return SatelliteManager.SATELLITE_MODEM_STATE_OFF; case SatelliteModemState.SATELLITE_MODEM_STATE_UNAVAILABLE: return SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE; case SatelliteModemState.SATELLITE_MODEM_STATE_NOT_CONNECTED: return SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED; case SatelliteModemState.SATELLITE_MODEM_STATE_CONNECTED: return SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED; default: loge("Received invalid modem state: " + modemState); return SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN; Loading Loading
src/java/com/android/internal/telephony/satellite/DatagramController.java +40 −4 Original line number Diff line number Diff line Loading @@ -16,6 +16,9 @@ package com.android.internal.telephony.satellite; import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED; import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING; import android.annotation.NonNull; import android.content.Context; import android.os.Build; Loading Loading @@ -46,6 +49,8 @@ public class DatagramController { 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); public static final long DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMEOUT = TimeUnit.SECONDS.toMillis(60); private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem"; private static final boolean DEBUG = !"user".equals(Build.TYPE); Loading Loading @@ -74,6 +79,10 @@ public class DatagramController { private SatelliteDatagram mDemoModeDatagram; private boolean mIsDemoMode = false; private long mAlignTimeoutDuration = SATELLITE_ALIGN_TIMEOUT; private long mDatagramWaitTimeForConnectedState = DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMEOUT; @GuardedBy("mLock") @SatelliteManager.SatelliteModemState private int mSatelltieModemState = SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN; /** * @return The singleton instance of DatagramController. Loading Loading @@ -267,6 +276,9 @@ public class DatagramController { * @param state Current satellite modem state. */ public void onSatelliteModemStateChanged(@SatelliteManager.SatelliteModemState int state) { synchronized (mLock) { mSatelltieModemState = state; } mDatagramDispatcher.onSatelliteModemStateChanged(state); mDatagramReceiver.onSatelliteModemStateChanged(state); } Loading @@ -284,17 +296,35 @@ public class DatagramController { } } /** * Check if Telephony needs to wait for the modem satellite connected to a satellite network * before transferring datagrams via satellite. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public boolean needsWaitingForSatelliteConnected() { synchronized (mLock) { if (SatelliteController.getInstance().isSatelliteAttachRequired() && mSatelltieModemState != SATELLITE_MODEM_STATE_CONNECTED && mSatelltieModemState != SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING) { return true; } return false; } } public boolean isSendingInIdleState() { synchronized (mLock) { return mSendDatagramTransferState == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE; return (mSendDatagramTransferState == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE) && (mDatagramDispatcher.getPendingDatagramCount() == 0); } } public boolean isPollingInIdleState() { synchronized (mLock) { return mReceiveDatagramTransferState == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE; return (mReceiveDatagramTransferState == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE) && !mDatagramReceiver.isPollingPending(); } } Loading Loading @@ -336,6 +366,11 @@ public class DatagramController { return mAlignTimeoutDuration; } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public long getDatagramWaitTimeForConnectedState() { return mDatagramWaitTimeForConnectedState; } /** * 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 Loading @@ -351,6 +386,7 @@ public class DatagramController { logd("setSatelliteDeviceAlignedTimeoutDuration: timeoutMillis=" + timeoutMillis); mAlignTimeoutDuration = timeoutMillis; mDatagramWaitTimeForConnectedState = timeoutMillis; return true; } Loading
src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java +53 −5 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.internal.telephony.satellite; import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED; import static com.android.internal.telephony.satellite.DatagramController.ROUNDING_UNIT; import android.annotation.NonNull; Loading Loading @@ -51,6 +53,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; private static final int EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT = 4; @NonNull private static DatagramDispatcher sInstance; @NonNull private final Context mContext; Loading Loading @@ -308,6 +311,10 @@ public class DatagramDispatcher extends Handler { break; } case EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT: handleEventDatagramWaitForConnectedStateTimedOut(); break; default: logw("DatagramDispatcherHandler: unexpected message code: " + msg.what); break; Loading Loading @@ -350,8 +357,13 @@ public class DatagramDispatcher extends Handler { mPendingNonEmergencyDatagramsMap.put(datagramId, datagramArgs); } // Modem can be busy receiving datagrams, so send datagram only when modem is not busy. if (!mSendingDatagramInProgress && mDatagramController.isPollingInIdleState()) { if (mDatagramController.needsWaitingForSatelliteConnected()) { logd("sendSatelliteDatagram: wait for satellite connected"); SatelliteSessionController.getInstance().onSatelliteDatagramsTransferRequested(); startDatagramWaitForConnectedStateTimer(); } else if (!mSendingDatagramInProgress && mDatagramController.isPollingInIdleState()) { // Modem can be busy receiving datagrams, so send datagram only when modem is // not busy. mSendingDatagramInProgress = true; datagramArgs.setDatagramStartTime(); mDatagramController.updateSendStatus(subId, Loading Loading @@ -525,10 +537,11 @@ public class DatagramDispatcher extends Handler { * Return pending datagram count * @return pending datagram count */ @GuardedBy("mLock") private int getPendingDatagramCount() { public int getPendingDatagramCount() { synchronized (mLock) { return mPendingEmergencyDatagramsMap.size() + mPendingNonEmergencyDatagramsMap.size(); } } /** * Posts the specified command to be executed on the main thread and returns immediately. Loading Loading @@ -579,6 +592,12 @@ public class DatagramDispatcher extends Handler { } else if (state == SatelliteManager.SATELLITE_MODEM_STATE_IDLE) { sendPendingDatagrams(); } if (state == SATELLITE_MODEM_STATE_CONNECTED && isDatagramWaitForConnectedStateTimerStarted()) { stopDatagramWaitForConnectedStateTimer(); sendPendingDatagrams(); } } } Loading @@ -598,11 +617,40 @@ public class DatagramDispatcher extends Handler { SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED); stopSatelliteAlignedTimer(); stopDatagramWaitForConnectedStateTimer(); mIsDemoMode = false; mSendSatelliteDatagramRequest = null; mIsAligned = false; } private void startDatagramWaitForConnectedStateTimer() { if (isDatagramWaitForConnectedStateTimerStarted()) { logd("DatagramWaitForConnectedStateTimer is already started"); return; } sendMessageDelayed(obtainMessage( EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT), mDatagramController.getDatagramWaitTimeForConnectedState()); } private void stopDatagramWaitForConnectedStateTimer() { removeMessages(EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT); } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public boolean isDatagramWaitForConnectedStateTimerStarted() { return hasMessages(EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT); } private void handleEventDatagramWaitForConnectedStateTimedOut() { logw("Timed out to wait for satellite connected before sending datagrams"); synchronized (mLock) { abortSendingPendingDatagrams(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE); SatelliteSessionController.getInstance().onDatagramWaitForConnectedStateTimerTimedOut(); } } private static void logd(@NonNull String log) { Rlog.d(TAG, log); } Loading
src/java/com/android/internal/telephony/satellite/DatagramReceiver.java +116 −11 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.internal.telephony.satellite; import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED; import static com.android.internal.telephony.satellite.DatagramController.ROUNDING_UNIT; import android.annotation.NonNull; Loading Loading @@ -65,6 +67,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; private static final int EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT = 4; /** Key used to read/write satellite datagramId in shared preferences. */ private static final String SATELLITE_DATAGRAM_ID_KEY = "satellite_datagram_id_key"; Loading @@ -82,7 +85,10 @@ public class DatagramReceiver extends Handler { private boolean mIsDemoMode = false; @GuardedBy("mLock") private boolean mIsAligned = false; private DatagramReceiverHandlerRequest mPollPendingSatelliteDatagramsRequest = null; @Nullable private DatagramReceiverHandlerRequest mDemoPollPendingSatelliteDatagramsRequest = null; @Nullable private DatagramReceiverHandlerRequest mPendingPollSatelliteDatagramsRequest = null; private final Object mLock = new Object(); /** Loading Loading @@ -497,6 +503,14 @@ public class DatagramReceiver extends Handler { handleEventSatelliteAlignedTimeout((DatagramReceiverHandlerRequest) msg.obj); break; } case EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT: handleEventDatagramWaitForConnectedStateTimedOut(); break; default: logw("DatagramDispatcherHandler: unexpected message code: " + msg.what); break; } } Loading Loading @@ -585,10 +599,38 @@ public class DatagramReceiver extends Handler { callback.accept(SatelliteManager.SATELLITE_RESULT_MODEM_BUSY); return; } pollPendingSatelliteDatagramsInternal(subId, callback); } /** * Check if DatagramReceiver is waiting for satellite modem connected to a satellite network * before pushing down the poll request to modem. */ public boolean isPollingPending() { synchronized (mLock) { return (mPendingPollSatelliteDatagramsRequest != null); } } private void handleSatelliteConnectedEvent() { synchronized (mLock) { if (isDatagramWaitForConnectedStateTimerStarted()) { stopDatagramWaitForConnectedStateTimer(); if (mPendingPollSatelliteDatagramsRequest == null) { loge("handleSatelliteConnectedEvent: mPendingPollSatelliteDatagramsRequest is" + " null"); return; } Consumer<Integer> callback = (Consumer<Integer>) mPendingPollSatelliteDatagramsRequest.argument; pollPendingSatelliteDatagramsInternal( mPendingPollSatelliteDatagramsRequest.subId, callback); mPendingPollSatelliteDatagramsRequest = null; } } } private void pollPendingSatelliteDatagramsInternal(int subId, @NonNull Consumer<Integer> callback) { if (!mDatagramController.isSendingInIdleState()) { Loading @@ -598,6 +640,17 @@ public class DatagramReceiver extends Handler { return; } if (mDatagramController.needsWaitingForSatelliteConnected()) { logd("pollPendingSatelliteDatagrams: wait for satellite connected"); synchronized (mLock) { mPendingPollSatelliteDatagramsRequest = new DatagramReceiverHandlerRequest( callback, SatelliteServiceUtils.getPhone(), subId); SatelliteSessionController.getInstance().onSatelliteDatagramsTransferRequested(); startDatagramWaitForConnectedStateTimer(); } return; } mDatagramController.updateReceiveStatus(subId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING, mDatagramController.getReceivePendingCount(), Loading Loading @@ -635,6 +688,8 @@ public class DatagramReceiver extends Handler { || state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE) { logd("onSatelliteModemStateChanged: cleaning up resources"); cleanUpResources(); } else if (state == SATELLITE_MODEM_STATE_CONNECTED) { handleSatelliteConnectedEvent(); } } } Loading @@ -643,22 +698,31 @@ public class DatagramReceiver extends Handler { private void cleanupDemoModeResources() { if (isSatelliteAlignedTimerStarted()) { stopSatelliteAlignedTimer(); if (mPollPendingSatelliteDatagramsRequest == null) { if (mDemoPollPendingSatelliteDatagramsRequest == null) { loge("Satellite aligned timer was started " + "but mPollPendingSatelliteDatagramsRequest is null"); + "but mDemoPollPendingSatelliteDatagramsRequest is null"); } else { Consumer<Integer> callback = (Consumer<Integer>) mPollPendingSatelliteDatagramsRequest.argument; (Consumer<Integer>) mDemoPollPendingSatelliteDatagramsRequest.argument; callback.accept(SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED); } } mIsDemoMode = false; mPollPendingSatelliteDatagramsRequest = null; mDemoPollPendingSatelliteDatagramsRequest = null; mIsAligned = false; } @GuardedBy("mLock") private void cleanUpResources() { synchronized (mLock) { if (mPendingPollSatelliteDatagramsRequest != null) { Consumer<Integer> callback = (Consumer<Integer>) mPendingPollSatelliteDatagramsRequest.argument; callback.accept(SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED); mPendingPollSatelliteDatagramsRequest = null; } stopDatagramWaitForConnectedStateTimer(); } if (mDatagramController.isReceivingDatagrams()) { mDatagramController.updateReceiveStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED, Loading Loading @@ -736,7 +800,7 @@ public class DatagramReceiver extends Handler { logd("Satellite aligned timer was already started"); return; } mPollPendingSatelliteDatagramsRequest = request; mDemoPollPendingSatelliteDatagramsRequest = request; sendMessageDelayed( obtainMessage(EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT, request), getSatelliteAlignedTimeoutDuration()); Loading @@ -751,13 +815,14 @@ public class DatagramReceiver extends Handler { if (isSatelliteAlignedTimerStarted()) { stopSatelliteAlignedTimer(); if (mPollPendingSatelliteDatagramsRequest == null) { loge("handleSatelliteAlignedTimer: mPollPendingSatelliteDatagramsRequest is null"); if (mDemoPollPendingSatelliteDatagramsRequest == null) { loge("handleSatelliteAlignedTimer: mDemoPollPendingSatelliteDatagramsRequest " + "is null"); } else { Message message = obtainMessage( EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE, mPollPendingSatelliteDatagramsRequest); mPollPendingSatelliteDatagramsRequest = null; mDemoPollPendingSatelliteDatagramsRequest); mDemoPollPendingSatelliteDatagramsRequest = null; AsyncResult.forMessage(message, null, null); message.sendToTarget(); } Loading @@ -781,6 +846,42 @@ public class DatagramReceiver extends Handler { removeMessages(EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT); } private void startDatagramWaitForConnectedStateTimer() { if (isDatagramWaitForConnectedStateTimerStarted()) { logd("DatagramWaitForConnectedStateTimer is already started"); return; } sendMessageDelayed(obtainMessage( EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT), mDatagramController.getDatagramWaitTimeForConnectedState()); } private void stopDatagramWaitForConnectedStateTimer() { removeMessages(EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT); } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public boolean isDatagramWaitForConnectedStateTimerStarted() { return hasMessages(EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT); } private void handleEventDatagramWaitForConnectedStateTimedOut() { synchronized (mLock) { if (mPendingPollSatelliteDatagramsRequest == null) { logw("handleEventDatagramWaitForConnectedStateTimedOut: " + "mPendingPollSatelliteDatagramsRequest is null"); return; } logw("Timed out to wait for satellite connected before polling datagrams"); Consumer<Integer> callback = (Consumer<Integer>) mPendingPollSatelliteDatagramsRequest.argument; callback.accept(SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE); mPendingPollSatelliteDatagramsRequest = null; SatelliteSessionController.getInstance().onDatagramWaitForConnectedStateTimerTimedOut(); } } /** * Destroys this DatagramDispatcher. Used for tearing down static resources during testing. */ Loading @@ -796,4 +897,8 @@ public class DatagramReceiver extends Handler { private static void loge(@NonNull String log) { Rlog.e(TAG, log); } private static void logw(@NonNull String log) { Rlog.w(TAG, log); } }
src/java/com/android/internal/telephony/satellite/SatelliteController.java +39 −3 Original line number Diff line number Diff line Loading @@ -71,6 +71,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.IIntegerConsumer; import com.android.internal.telephony.Phone; import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats; import com.android.internal.telephony.satellite.metrics.ProvisionMetricsStats; import com.android.internal.telephony.satellite.metrics.SessionMetricsStats; Loading Loading @@ -242,6 +243,7 @@ public class SatelliteController extends Handler { * {@code true} for enabled and {@code false} for disabled. */ @NonNull private final Map<Integer, Boolean> mIsSatelliteAttachEnabledForCarrierArrayPerSub = new HashMap<>(); @NonNull private final FeatureFlags mFeatureFlags; /** * @return The singleton instance of SatelliteController. */ Loading @@ -255,12 +257,13 @@ public class SatelliteController extends Handler { /** * Create the SatelliteController singleton instance. * @param context The Context to use to create the SatelliteController. * @param featureFlags The feature flag. */ public static void make(@NonNull Context context) { public static void make(@NonNull Context context, @NonNull FeatureFlags featureFlags) { if (sInstance == null) { HandlerThread satelliteThread = new HandlerThread(TAG); satelliteThread.start(); sInstance = new SatelliteController(context, satelliteThread.getLooper()); sInstance = new SatelliteController(context, satelliteThread.getLooper(), featureFlags); } } Loading @@ -270,12 +273,15 @@ public class SatelliteController extends Handler { * * @param context The Context for the SatelliteController. * @param looper The looper for the handler. It does not run on main thread. * @param featureFlags The feature flag. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public SatelliteController(@NonNull Context context, @NonNull Looper looper) { public SatelliteController( @NonNull Context context, @NonNull Looper looper, @NonNull FeatureFlags featureFlags) { super(looper); mContext = context; mFeatureFlags = featureFlags; Phone phone = SatelliteServiceUtils.getPhone(); mCi = phone.mCi; // Create the SatelliteModemInterface singleton, which is used to manage connections Loading Loading @@ -2128,6 +2134,30 @@ public class SatelliteController extends Handler { } } /** * Check whether satellite modem has to attach to a satellite network before sending/receiving * datagrams. * * @return {@code true} if satellite attach is required, {@code false} otherwise. */ public boolean isSatelliteAttachRequired() { if (!mFeatureFlags.oemEnabledSatelliteFlag()) { return false; } synchronized (mSatelliteCapabilitiesLock) { if (mSatelliteCapabilities == null) { loge("isSatelliteAttachRequired: mSatelliteCapabilities is null"); return false; } if (mSatelliteCapabilities.getSupportedRadioTechnologies().contains( SatelliteManager.NT_RADIO_TECHNOLOGY_NB_IOT_NTN)) { return true; } return false; } } /** * If we have not successfully queried the satellite modem for its satellite service support, * we will retry the query one more time. Otherwise, we will return the cached result. Loading Loading @@ -2477,6 +2507,12 @@ public class SatelliteController extends Handler { } mWaitingForSatelliteModemOff = false; } } else { if (mSatelliteSessionController != null) { mSatelliteSessionController.onSatelliteModemStateChanged(state); } else { loge("handleEventSatelliteModemStateChanged: mSatelliteSessionController is null"); } } mDatagramController.onSatelliteModemStateChanged(state); } Loading
src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java +4 −0 Original line number Diff line number Diff line Loading @@ -150,6 +150,10 @@ public class SatelliteServiceUtils { return SatelliteManager.SATELLITE_MODEM_STATE_OFF; case SatelliteModemState.SATELLITE_MODEM_STATE_UNAVAILABLE: return SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE; case SatelliteModemState.SATELLITE_MODEM_STATE_NOT_CONNECTED: return SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED; case SatelliteModemState.SATELLITE_MODEM_STATE_CONNECTED: return SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED; default: loge("Received invalid modem state: " + modemState); return SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN; Loading