1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.telephony.satellite; 18 19 import static android.telephony.SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; 20 import static android.telephony.satellite.SatelliteManager.DATAGRAM_TYPE_KEEP_ALIVE; 21 import static android.telephony.satellite.SatelliteManager.DATAGRAM_TYPE_UNKNOWN; 22 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE; 23 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED; 24 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING; 25 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_IDLE; 26 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED; 27 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_OFF; 28 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS; 29 30 import android.annotation.NonNull; 31 import android.annotation.Nullable; 32 import android.content.Context; 33 import android.content.res.Resources; 34 import android.os.Build; 35 import android.os.Looper; 36 import android.os.SystemProperties; 37 import android.telephony.DropBoxManagerLoggerBackend; 38 import android.telephony.PersistentLogger; 39 import android.telephony.Rlog; 40 import android.telephony.satellite.ISatelliteDatagramCallback; 41 import android.telephony.satellite.SatelliteDatagram; 42 import android.telephony.satellite.SatelliteManager; 43 44 import com.android.internal.R; 45 import com.android.internal.annotations.GuardedBy; 46 import com.android.internal.annotations.VisibleForTesting; 47 import com.android.internal.telephony.flags.FeatureFlags; 48 49 import java.util.ArrayList; 50 import java.util.List; 51 import java.util.concurrent.TimeUnit; 52 import java.util.function.Consumer; 53 54 /** 55 * Datagram controller used for sending and receiving satellite datagrams. 56 */ 57 public class DatagramController { 58 private static final String TAG = "DatagramController"; 59 60 @NonNull private static DatagramController sInstance; 61 @NonNull private final Context mContext; 62 @NonNull private final FeatureFlags mFeatureFlags; 63 @NonNull private final PointingAppController mPointingAppController; 64 @NonNull private final DatagramDispatcher mDatagramDispatcher; 65 @NonNull private final DatagramReceiver mDatagramReceiver; 66 67 public static final long MAX_DATAGRAM_ID = (long) Math.pow(2, 16); 68 public static final int ROUNDING_UNIT = 10; 69 public static final long SATELLITE_ALIGN_TIMEOUT = TimeUnit.SECONDS.toMillis(30); 70 /** This type is used by CTS to override the satellite align timeout */ 71 public static final int TIMEOUT_TYPE_ALIGN = 1; 72 /** This type is used by CTS to override the time to wait for connected state */ 73 public static final int TIMEOUT_TYPE_DATAGRAM_WAIT_FOR_CONNECTED_STATE = 2; 74 /** This type is used by CTS to override the time to wait for response of the send request */ 75 public static final int TIMEOUT_TYPE_WAIT_FOR_DATAGRAM_SENDING_RESPONSE = 3; 76 /** This type is used by CTS to override the time to datagram delay in demo mode */ 77 public static final int TIMEOUT_TYPE_DATAGRAM_DELAY_IN_DEMO_MODE = 4; 78 /** This type is used by CTS to override wait for device alignment in demo datagram boolean */ 79 public static final int BOOLEAN_TYPE_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_DATAGRAM = 1; 80 private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem"; 81 private static final boolean DEBUG = !"user".equals(Build.TYPE); 82 83 /** Variables used to update onSendDatagramStateChanged(). */ 84 private final Object mLock = new Object(); 85 @GuardedBy("mLock") 86 private int mSendSubId; 87 @GuardedBy("mLock") 88 private @SatelliteManager.DatagramType int mDatagramType = DATAGRAM_TYPE_UNKNOWN; 89 @GuardedBy("mLock") 90 private @SatelliteManager.SatelliteDatagramTransferState int mSendDatagramTransferState = 91 SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE; 92 @GuardedBy("mLock") 93 private int mSendPendingCount = 0; 94 @GuardedBy("mLock") 95 private int mSendErrorCode = SatelliteManager.SATELLITE_RESULT_SUCCESS; 96 /** Variables used to update onReceiveDatagramStateChanged(). */ 97 @GuardedBy("mLock") 98 private int mReceiveSubId; 99 @GuardedBy("mLock") 100 private @SatelliteManager.SatelliteDatagramTransferState int mReceiveDatagramTransferState = 101 SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE; 102 @GuardedBy("mLock") 103 private int mReceivePendingCount = 0; 104 @GuardedBy("mLock") 105 private int mReceiveErrorCode = SatelliteManager.SATELLITE_RESULT_SUCCESS; 106 @GuardedBy("mLock") 107 private final List<SatelliteDatagram> mDemoModeDatagramList; 108 private boolean mIsDemoMode = false; 109 private long mAlignTimeoutDuration = SATELLITE_ALIGN_TIMEOUT; 110 private long mDatagramWaitTimeForConnectedState; 111 private long mModemImageSwitchingDuration; 112 private boolean mWaitForDeviceAlignmentInDemoDatagram; 113 private long mDatagramWaitTimeForConnectedStateForLastMessage; 114 @GuardedBy("mLock") 115 @SatelliteManager.SatelliteModemState 116 private int mSatelltieModemState = SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN; 117 @Nullable 118 private PersistentLogger mPersistentLogger = null; 119 120 /** 121 * @return The singleton instance of DatagramController. 122 */ getInstance()123 public static DatagramController getInstance() { 124 if (sInstance == null) { 125 loge("DatagramController was not yet initialized."); 126 } 127 return sInstance; 128 } 129 130 /** 131 * Create the DatagramController singleton instance. 132 * @param context The Context to use to create the DatagramController. 133 * @param looper The looper for the handler. 134 * @param featureFlags The telephony feature flags. 135 * @param pointingAppController PointingAppController is used to update 136 * PointingApp about datagram transfer state changes. 137 * @return The singleton instance of DatagramController. 138 */ make(@onNull Context context, @NonNull Looper looper, @NonNull FeatureFlags featureFlags, @NonNull PointingAppController pointingAppController)139 public static DatagramController make(@NonNull Context context, @NonNull Looper looper, 140 @NonNull FeatureFlags featureFlags, 141 @NonNull PointingAppController pointingAppController) { 142 if (sInstance == null) { 143 sInstance = new DatagramController( 144 context, looper, featureFlags, pointingAppController); 145 } 146 return sInstance; 147 } 148 149 /** 150 * Create a DatagramController to send and receive satellite datagrams. 151 * 152 * @param context The Context for the DatagramController. 153 * @param looper The looper for the handler 154 * @param featureFlags The telephony feature flags. 155 * @param pointingAppController PointingAppController is used to update PointingApp 156 * about datagram transfer state changes. 157 */ 158 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) DatagramController(@onNull Context context, @NonNull Looper looper, @NonNull FeatureFlags featureFlags, @NonNull PointingAppController pointingAppController)159 public DatagramController(@NonNull Context context, @NonNull Looper looper, 160 @NonNull FeatureFlags featureFlags, 161 @NonNull PointingAppController pointingAppController) { 162 mContext = context; 163 mFeatureFlags = featureFlags; 164 mPointingAppController = pointingAppController; 165 166 // Create the DatagramDispatcher singleton, 167 // which is used to send satellite datagrams. 168 mDatagramDispatcher = DatagramDispatcher.make( 169 mContext, looper, mFeatureFlags, this); 170 171 // Create the DatagramReceiver singleton, 172 // which is used to receive satellite datagrams. 173 mDatagramReceiver = DatagramReceiver.make( 174 mContext, looper, mFeatureFlags, this); 175 176 mDatagramWaitTimeForConnectedState = getDatagramWaitForConnectedStateTimeoutMillis(); 177 mModemImageSwitchingDuration = getSatelliteModemImageSwitchingDurationMillis(); 178 mWaitForDeviceAlignmentInDemoDatagram = 179 getWaitForDeviceAlignmentInDemoDatagramFromResources(); 180 mDatagramWaitTimeForConnectedStateForLastMessage = 181 getDatagramWaitForConnectedStateForLastMessageTimeoutMillis(); 182 mDemoModeDatagramList = new ArrayList<>(); 183 184 if (isSatellitePersistentLoggingEnabled(context, featureFlags)) { 185 mPersistentLogger = new PersistentLogger( 186 DropBoxManagerLoggerBackend.getInstance(context)); 187 } 188 } 189 190 /** 191 * Register to receive incoming datagrams over satellite. 192 * 193 * @param subId The subId of the subscription to register for incoming satellite datagrams. 194 * @param callback The callback to handle incoming datagrams over satellite. 195 * 196 * @return The {@link SatelliteManager.SatelliteResult} result of the operation. 197 */ registerForSatelliteDatagram(int subId, @NonNull ISatelliteDatagramCallback callback)198 @SatelliteManager.SatelliteResult public int registerForSatelliteDatagram(int subId, 199 @NonNull ISatelliteDatagramCallback callback) { 200 return mDatagramReceiver.registerForSatelliteDatagram(subId, callback); 201 } 202 203 /** 204 * Unregister to stop receiving incoming datagrams over satellite. 205 * If callback was not registered before, the request will be ignored. 206 * 207 * @param subId The subId of the subscription to unregister for incoming satellite datagrams. 208 * @param callback The callback that was passed to 209 * {@link #registerForSatelliteDatagram(int, ISatelliteDatagramCallback)}. 210 */ unregisterForSatelliteDatagram(int subId, @NonNull ISatelliteDatagramCallback callback)211 public void unregisterForSatelliteDatagram(int subId, 212 @NonNull ISatelliteDatagramCallback callback) { 213 mDatagramReceiver.unregisterForSatelliteDatagram(subId, callback); 214 } 215 216 /** 217 * Poll pending satellite datagrams over satellite. 218 * 219 * This method requests modem to check if there are any pending datagrams to be received over 220 * satellite. If there are any incoming datagrams, they will be received via 221 * {@link android.telephony.satellite.SatelliteDatagramCallback#onSatelliteDatagramReceived( 222 * long, SatelliteDatagram, int, Consumer)} 223 * 224 * @param subId The subId of the subscription used for receiving datagrams. 225 * @param callback The callback to get {@link SatelliteManager.SatelliteResult} of the request. 226 */ pollPendingSatelliteDatagrams(int subId, @NonNull Consumer<Integer> callback)227 public void pollPendingSatelliteDatagrams(int subId, @NonNull Consumer<Integer> callback) { 228 plogd("pollPendingSatelliteDatagrams"); 229 mDatagramReceiver.pollPendingSatelliteDatagrams(subId, callback); 230 } 231 232 /** 233 * Send datagram over satellite. 234 * 235 * Gateway encodes SOS message or location sharing message into a datagram and passes it as 236 * input to this method. Datagram received here will be passed down to modem without any 237 * encoding or encryption. 238 * 239 * When demo mode is on, save the sent datagram and this datagram will be used as a received 240 * datagram. 241 * 242 * @param subId The subId of the subscription to send satellite datagrams for. 243 * @param datagramType datagram type indicating whether the datagram is of type 244 * SOS_SMS or LOCATION_SHARING. 245 * @param datagram encoded gateway datagram which is encrypted by the caller. 246 * Datagram will be passed down to modem without any encoding or encryption. 247 * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in 248 * full screen mode. 249 * @param callback The callback to get {@link SatelliteManager.SatelliteResult} of the request. 250 */ sendSatelliteDatagram(int subId, @SatelliteManager.DatagramType int datagramType, @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI, @NonNull Consumer<Integer> callback)251 public void sendSatelliteDatagram(int subId, @SatelliteManager.DatagramType int datagramType, 252 @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI, 253 @NonNull Consumer<Integer> callback) { 254 mDatagramDispatcher.sendSatelliteDatagram(subId, datagramType, datagram, 255 needFullScreenPointingUI, callback); 256 } 257 258 /** 259 * Update send status to {@link PointingAppController}. 260 * 261 * @param subId The subId of the subscription to send satellite datagrams for 262 * @param datagramTransferState The new send datagram transfer state. 263 * @param sendPendingCount number of datagrams that are currently being sent 264 * @param errorCode If datagram transfer failed, the reason for failure. 265 */ updateSendStatus(int subId, @SatelliteManager.DatagramType int datagramType, @SatelliteManager.SatelliteDatagramTransferState int datagramTransferState, int sendPendingCount, int errorCode)266 public void updateSendStatus(int subId, @SatelliteManager.DatagramType int datagramType, 267 @SatelliteManager.SatelliteDatagramTransferState int datagramTransferState, 268 int sendPendingCount, int errorCode) { 269 synchronized (mLock) { 270 plogd("updateSendStatus" 271 + " subId: " + subId 272 + " datagramType: " + datagramType 273 + " datagramTransferState: " + datagramTransferState 274 + " sendPendingCount: " + sendPendingCount + " errorCode: " + errorCode); 275 if (shouldSuppressDatagramTransferStateUpdate(datagramType)) { 276 plogd("Ignore the request to update send status"); 277 return; 278 } 279 280 mSendSubId = subId; 281 mDatagramType = datagramType; 282 mSendDatagramTransferState = datagramTransferState; 283 mSendPendingCount = sendPendingCount; 284 mSendErrorCode = errorCode; 285 notifyDatagramTransferStateChangedToSessionController(); 286 mPointingAppController.updateSendDatagramTransferState(mSendSubId, mDatagramType, 287 mSendDatagramTransferState, mSendPendingCount, mSendErrorCode); 288 retryPollPendingDatagramsInDemoMode(); 289 } 290 } 291 shouldSuppressDatagramTransferStateUpdate( @atelliteManager.DatagramType int datagramType)292 private boolean shouldSuppressDatagramTransferStateUpdate( 293 @SatelliteManager.DatagramType int datagramType) { 294 synchronized (mLock) { 295 if (!SatelliteController.getInstance().isSatelliteAttachRequired()) { 296 return false; 297 } 298 if (datagramType == DATAGRAM_TYPE_KEEP_ALIVE 299 && mSatelltieModemState == SATELLITE_MODEM_STATE_NOT_CONNECTED) { 300 return true; 301 } 302 return false; 303 } 304 } 305 306 /** 307 * Update receive status to {@link PointingAppController}. 308 * 309 * @param subId The subId of the subscription used to receive datagrams 310 * @param datagramTransferState The new receive datagram transfer state. 311 * @param receivePendingCount The number of datagrams that are currently pending to be received. 312 * @param errorCode If datagram transfer failed, the reason for failure. 313 */ updateReceiveStatus(int subId, @SatelliteManager.SatelliteDatagramTransferState int datagramTransferState, int receivePendingCount, int errorCode)314 public void updateReceiveStatus(int subId, 315 @SatelliteManager.SatelliteDatagramTransferState int datagramTransferState, 316 int receivePendingCount, int errorCode) { 317 synchronized (mLock) { 318 plogd("updateReceiveStatus" 319 + " subId: " + subId 320 + " datagramTransferState: " + datagramTransferState 321 + " receivePendingCount: " + receivePendingCount + " errorCode: " + errorCode); 322 323 mReceiveSubId = subId; 324 mReceiveDatagramTransferState = datagramTransferState; 325 mReceivePendingCount = receivePendingCount; 326 mReceiveErrorCode = errorCode; 327 328 notifyDatagramTransferStateChangedToSessionController(); 329 mPointingAppController.updateReceiveDatagramTransferState(mReceiveSubId, 330 mReceiveDatagramTransferState, mReceivePendingCount, mReceiveErrorCode); 331 retryPollPendingDatagramsInDemoMode(); 332 } 333 334 if (isPollingInIdleState()) { 335 mDatagramDispatcher.retrySendingDatagrams(); 336 } 337 } 338 339 /** 340 * Return receive pending datagram count 341 * @return receive pending datagram count. 342 */ getReceivePendingCount()343 public int getReceivePendingCount() { 344 return mReceivePendingCount; 345 } 346 347 /** 348 * This function is used by {@link SatelliteController} to notify {@link DatagramController} 349 * that satellite modem state has changed. 350 * 351 * @param state Current satellite modem state. 352 */ onSatelliteModemStateChanged(@atelliteManager.SatelliteModemState int state)353 public void onSatelliteModemStateChanged(@SatelliteManager.SatelliteModemState int state) { 354 synchronized (mLock) { 355 mSatelltieModemState = state; 356 } 357 mDatagramDispatcher.onSatelliteModemStateChanged(state); 358 mDatagramReceiver.onSatelliteModemStateChanged(state); 359 } 360 361 /** 362 * Set whether the device is aligned with the satellite. 363 */ 364 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) setDeviceAlignedWithSatellite(boolean isAligned)365 public void setDeviceAlignedWithSatellite(boolean isAligned) { 366 mDatagramDispatcher.setDeviceAlignedWithSatellite(isAligned); 367 mDatagramReceiver.setDeviceAlignedWithSatellite(isAligned); 368 if (isAligned) { 369 retryPollPendingDatagramsInDemoMode(); 370 } 371 } 372 373 @VisibleForTesting isReceivingDatagrams()374 public boolean isReceivingDatagrams() { 375 synchronized (mLock) { 376 return (mReceiveDatagramTransferState 377 == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); 378 } 379 } 380 381 /** 382 * Check if Telephony needs to wait for the modem satellite connected to a satellite network 383 * before transferring datagrams via satellite. 384 */ 385 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) needsWaitingForSatelliteConnected( @atelliteManager.DatagramType int datagramType)386 public boolean needsWaitingForSatelliteConnected( 387 @SatelliteManager.DatagramType int datagramType) { 388 synchronized (mLock) { 389 if (!SatelliteController.getInstance().isSatelliteAttachRequired()) { 390 return false; 391 } 392 if (datagramType == DATAGRAM_TYPE_KEEP_ALIVE 393 && mSatelltieModemState == SATELLITE_MODEM_STATE_NOT_CONNECTED) { 394 return false; 395 } 396 if (mSatelltieModemState != SATELLITE_MODEM_STATE_CONNECTED 397 && mSatelltieModemState != SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING) { 398 return true; 399 } 400 return false; 401 } 402 } 403 isSendingInIdleState()404 public boolean isSendingInIdleState() { 405 synchronized (mLock) { 406 return (mSendDatagramTransferState 407 == SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); 408 } 409 } 410 isPollingInIdleState()411 public boolean isPollingInIdleState() { 412 synchronized (mLock) { 413 return (mReceiveDatagramTransferState 414 == SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); 415 } 416 } 417 418 /** 419 * Set variables for {@link DatagramDispatcher} and {@link DatagramReceiver} to run demo mode 420 * @param isDemoMode {@code true} means demo mode is on, {@code false} otherwise. 421 */ 422 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) setDemoMode(boolean isDemoMode)423 public void setDemoMode(boolean isDemoMode) { 424 mIsDemoMode = isDemoMode; 425 mDatagramDispatcher.setDemoMode(isDemoMode); 426 mDatagramReceiver.setDemoMode(isDemoMode); 427 428 if (!isDemoMode) { 429 synchronized (mLock) { 430 mDemoModeDatagramList.clear(); 431 } 432 setDeviceAlignedWithSatellite(false); 433 } 434 plogd("setDemoMode: mIsDemoMode=" + mIsDemoMode); 435 } 436 437 /** Get the last sent datagram for demo mode */ 438 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) popDemoModeDatagram()439 public SatelliteDatagram popDemoModeDatagram() { 440 if (!mIsDemoMode) { 441 return null; 442 } 443 444 synchronized (mLock) { 445 plogd("popDemoModeDatagram"); 446 return mDemoModeDatagramList.size() > 0 ? mDemoModeDatagramList.remove(0) : null; 447 } 448 } 449 450 /** 451 * Set last sent datagram for demo mode 452 * @param datagramType datagram type, DATAGRAM_TYPE_SOS_MESSAGE, 453 * DATAGRAM_TYPE_LAST_SOS_MESSAGE_STILL_NEED_HELP, 454 * DATAGRAM_TYPE_LAST_SOS_MESSAGE_NO_HELP_NEEDED will be saved 455 * @param datagram datagram The last datagram saved when sendSatelliteDatagramForDemo is called 456 */ 457 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) pushDemoModeDatagram(@atelliteManager.DatagramType int datagramType, SatelliteDatagram datagram)458 public void pushDemoModeDatagram(@SatelliteManager.DatagramType int datagramType, 459 SatelliteDatagram datagram) { 460 if (mIsDemoMode && SatelliteServiceUtils.isSosMessage(datagramType)) { 461 synchronized (mLock) { 462 mDemoModeDatagramList.add(datagram); 463 plogd("pushDemoModeDatagram size=" + mDemoModeDatagramList.size()); 464 } 465 } 466 } 467 getSatelliteAlignedTimeoutDuration()468 long getSatelliteAlignedTimeoutDuration() { 469 return mAlignTimeoutDuration; 470 } 471 472 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) getDatagramWaitTimeForConnectedState(boolean isLastSosMessage)473 public long getDatagramWaitTimeForConnectedState(boolean isLastSosMessage) { 474 synchronized (mLock) { 475 long timeout = isLastSosMessage ? mDatagramWaitTimeForConnectedStateForLastMessage : 476 mDatagramWaitTimeForConnectedState; 477 logd("getDatagramWaitTimeForConnectedState: isLastSosMessage=" + isLastSosMessage 478 + ", timeout=" + timeout + ", modemState=" + mSatelltieModemState); 479 if (mSatelltieModemState == SATELLITE_MODEM_STATE_OFF 480 || mSatelltieModemState == SATELLITE_MODEM_STATE_IDLE) { 481 return (timeout + mModemImageSwitchingDuration); 482 } 483 return timeout; 484 } 485 } 486 487 /** 488 * This API can be used by only CTS to timeout durations used by DatagramController module. 489 * 490 * @param timeoutMillis The timeout duration in millisecond. 491 * @return {@code true} if the timeout duration is set successfully, {@code false} otherwise. 492 */ setDatagramControllerTimeoutDuration( boolean reset, int timeoutType, long timeoutMillis)493 boolean setDatagramControllerTimeoutDuration( 494 boolean reset, int timeoutType, long timeoutMillis) { 495 if (!isMockModemAllowed()) { 496 ploge("Updating timeout duration is not allowed"); 497 return false; 498 } 499 500 plogd("setDatagramControllerTimeoutDuration: timeoutMillis=" + timeoutMillis 501 + ", reset=" + reset + ", timeoutType=" + timeoutType); 502 if (timeoutType == TIMEOUT_TYPE_ALIGN) { 503 if (reset) { 504 mAlignTimeoutDuration = SATELLITE_ALIGN_TIMEOUT; 505 } else { 506 mAlignTimeoutDuration = timeoutMillis; 507 } 508 } else if (timeoutType == TIMEOUT_TYPE_DATAGRAM_WAIT_FOR_CONNECTED_STATE) { 509 if (reset) { 510 mDatagramWaitTimeForConnectedState = 511 getDatagramWaitForConnectedStateTimeoutMillis(); 512 mModemImageSwitchingDuration = getSatelliteModemImageSwitchingDurationMillis(); 513 } else { 514 mDatagramWaitTimeForConnectedState = timeoutMillis; 515 mModemImageSwitchingDuration = 0; 516 } 517 } else if (timeoutType == TIMEOUT_TYPE_WAIT_FOR_DATAGRAM_SENDING_RESPONSE) { 518 mDatagramDispatcher.setWaitTimeForDatagramSendingResponse(reset, timeoutMillis); 519 } else if (timeoutType == TIMEOUT_TYPE_DATAGRAM_DELAY_IN_DEMO_MODE) { 520 mDatagramDispatcher.setTimeoutDatagramDelayInDemoMode(reset, timeoutMillis); 521 } else { 522 ploge("Invalid timeout type " + timeoutType); 523 return false; 524 } 525 return true; 526 } 527 528 /** 529 * This API can be used by only CTS to override the boolean configs used by the 530 * DatagramController module. 531 * 532 * @param enable Whether to enable or disable boolean config. 533 * @return {@code true} if the boolean config is set successfully, {@code false} otherwise. 534 */ setDatagramControllerBooleanConfig( boolean reset, int booleanType, boolean enable)535 boolean setDatagramControllerBooleanConfig( 536 boolean reset, int booleanType, boolean enable) { 537 if (!isMockModemAllowed()) { 538 loge("Updating boolean config is not allowed"); 539 return false; 540 } 541 542 logd("setDatagramControllerTimeoutDuration: booleanType=" + booleanType 543 + ", reset=" + reset + ", enable=" + enable); 544 if (booleanType == BOOLEAN_TYPE_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_DATAGRAM) { 545 if (reset) { 546 mWaitForDeviceAlignmentInDemoDatagram = 547 getWaitForDeviceAlignmentInDemoDatagramFromResources(); 548 } else { 549 mWaitForDeviceAlignmentInDemoDatagram = enable; 550 } 551 } else { 552 loge("Invalid boolean type " + booleanType); 553 return false; 554 } 555 return true; 556 } 557 isMockModemAllowed()558 private boolean isMockModemAllowed() { 559 return (DEBUG || SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false)); 560 } 561 notifyDatagramTransferStateChangedToSessionController()562 private void notifyDatagramTransferStateChangedToSessionController() { 563 SatelliteSessionController sessionController = SatelliteSessionController.getInstance(); 564 if (sessionController == null) { 565 ploge("notifyDatagramTransferStateChangeToSessionController: SatelliteSessionController" 566 + " is not initialized yet"); 567 } else { 568 sessionController.onDatagramTransferStateChanged( 569 mSendDatagramTransferState, mReceiveDatagramTransferState); 570 } 571 } 572 getDatagramWaitForConnectedStateTimeoutMillis()573 private long getDatagramWaitForConnectedStateTimeoutMillis() { 574 return mContext.getResources().getInteger( 575 R.integer.config_datagram_wait_for_connected_state_timeout_millis); 576 } 577 getSatelliteModemImageSwitchingDurationMillis()578 private long getSatelliteModemImageSwitchingDurationMillis() { 579 return mContext.getResources().getInteger( 580 R.integer.config_satellite_modem_image_switching_duration_millis); 581 } 582 getDatagramWaitForConnectedStateForLastMessageTimeoutMillis()583 private long getDatagramWaitForConnectedStateForLastMessageTimeoutMillis() { 584 return mContext.getResources().getInteger( 585 R.integer.config_datagram_wait_for_connected_state_for_last_message_timeout_millis); 586 } 587 588 /** 589 * This API can be used by only CTS to override the cached value for the device overlay config 590 * value : config_send_satellite_datagram_to_modem_in_demo_mode, which determines whether 591 * outgoing satellite datagrams should be sent to modem in demo mode. 592 * 593 * @param shouldSendToModemInDemoMode Whether send datagram in demo mode should be sent to 594 * satellite modem or not. 595 */ setShouldSendDatagramToModemInDemoMode(boolean shouldSendToModemInDemoMode)596 void setShouldSendDatagramToModemInDemoMode(boolean shouldSendToModemInDemoMode) { 597 mDatagramDispatcher.setShouldSendDatagramToModemInDemoMode(shouldSendToModemInDemoMode); 598 } 599 retryPollPendingDatagramsInDemoMode()600 private void retryPollPendingDatagramsInDemoMode() { 601 synchronized (mLock) { 602 if (mIsDemoMode && isSendingInIdleState() && isPollingInIdleState() 603 && !mDemoModeDatagramList.isEmpty()) { 604 Consumer<Integer> internalCallback = new Consumer<Integer>() { 605 @Override 606 public void accept(Integer result) { 607 if (result != SATELLITE_RESULT_SUCCESS) { 608 plogd("retryPollPendingDatagramsInDemoMode result: " + result); 609 } 610 } 611 }; 612 pollPendingSatelliteDatagrams(DEFAULT_SUBSCRIPTION_ID, internalCallback); 613 } 614 } 615 } 616 617 /** 618 * Get whether to wait for device alignment with satellite before sending datagrams. 619 * 620 * @param isAligned if the device is aligned with satellite or not 621 * @return {@code true} if device is not aligned to satellite, 622 * and it is required to wait for alignment else {@code false} 623 */ 624 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) waitForAligningToSatellite(boolean isAligned)625 public boolean waitForAligningToSatellite(boolean isAligned) { 626 if (isAligned) { 627 return false; 628 } 629 630 return getWaitForDeviceAlignmentInDemoDatagram(); 631 } 632 getWaitForDeviceAlignmentInDemoDatagram()633 private boolean getWaitForDeviceAlignmentInDemoDatagram() { 634 return mWaitForDeviceAlignmentInDemoDatagram; 635 } 636 getWaitForDeviceAlignmentInDemoDatagramFromResources()637 private boolean getWaitForDeviceAlignmentInDemoDatagramFromResources() { 638 boolean waitForDeviceAlignmentInDemoDatagram = false; 639 try { 640 waitForDeviceAlignmentInDemoDatagram = mContext.getResources().getBoolean( 641 R.bool.config_wait_for_device_alignment_in_demo_datagram); 642 } catch (Resources.NotFoundException ex) { 643 loge("getWaitForDeviceAlignmentInDemoDatagram: ex=" + ex); 644 } 645 646 return waitForDeviceAlignmentInDemoDatagram; 647 } 648 logd(@onNull String log)649 private static void logd(@NonNull String log) { 650 Rlog.d(TAG, log); 651 } 652 loge(@onNull String log)653 private static void loge(@NonNull String log) { 654 Rlog.e(TAG, log); 655 } 656 isSatellitePersistentLoggingEnabled( @onNull Context context, @NonNull FeatureFlags featureFlags)657 private boolean isSatellitePersistentLoggingEnabled( 658 @NonNull Context context, @NonNull FeatureFlags featureFlags) { 659 if (featureFlags.satellitePersistentLogging()) { 660 return true; 661 } 662 try { 663 return context.getResources().getBoolean( 664 R.bool.config_dropboxmanager_persistent_logging_enabled); 665 } catch (RuntimeException e) { 666 return false; 667 } 668 } 669 plogd(@onNull String log)670 private void plogd(@NonNull String log) { 671 Rlog.d(TAG, log); 672 if (mPersistentLogger != null) { 673 mPersistentLogger.debug(TAG, log); 674 } 675 } 676 ploge(@onNull String log)677 private void ploge(@NonNull String log) { 678 Rlog.e(TAG, log); 679 if (mPersistentLogger != null) { 680 mPersistentLogger.error(TAG, log); 681 } 682 } 683 } 684