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.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED; 20 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE; 21 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS; 22 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING; 23 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING; 24 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED; 25 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS; 26 27 import android.annotation.NonNull; 28 import android.annotation.Nullable; 29 import android.content.ComponentName; 30 import android.content.Context; 31 import android.content.Intent; 32 import android.content.ServiceConnection; 33 import android.os.Build; 34 import android.os.IBinder; 35 import android.os.Looper; 36 import android.os.Message; 37 import android.os.RemoteException; 38 import android.os.SystemProperties; 39 import android.provider.DeviceConfig; 40 import android.telephony.Rlog; 41 import android.telephony.satellite.ISatelliteStateCallback; 42 import android.telephony.satellite.SatelliteManager; 43 import android.telephony.satellite.stub.ISatelliteGateway; 44 import android.telephony.satellite.stub.SatelliteGatewayService; 45 import android.text.TextUtils; 46 import android.util.Log; 47 48 import com.android.internal.R; 49 import com.android.internal.annotations.VisibleForTesting; 50 import com.android.internal.telephony.ExponentialBackoff; 51 import com.android.internal.util.State; 52 import com.android.internal.util.StateMachine; 53 54 import java.util.ArrayList; 55 import java.util.List; 56 import java.util.concurrent.ConcurrentHashMap; 57 import java.util.concurrent.atomic.AtomicBoolean; 58 59 /** 60 * This module is responsible for managing session state transition and inform listeners of modem 61 * state changed events accordingly. 62 */ 63 public class SatelliteSessionController extends StateMachine { 64 private static final String TAG = "SatelliteSessionController"; 65 private static final boolean DBG = true; 66 private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem"; 67 private static final boolean DEBUG = !"user".equals(Build.TYPE); 68 69 /** 70 * The time duration in millis that the satellite will stay at listening mode to wait for the 71 * next incoming page before disabling listening mode when transitioning from sending mode. 72 */ 73 public static final String SATELLITE_STAY_AT_LISTENING_FROM_SENDING_MILLIS = 74 "satellite_stay_at_listening_from_sending_millis"; 75 /** 76 * The default value of {@link #SATELLITE_STAY_AT_LISTENING_FROM_SENDING_MILLIS}. 77 */ 78 public static final long DEFAULT_SATELLITE_STAY_AT_LISTENING_FROM_SENDING_MILLIS = 180000; 79 /** 80 * The time duration in millis that the satellite will stay at listening mode to wait for the 81 * next incoming page before disabling listening mode when transitioning from receiving mode. 82 */ 83 public static final String SATELLITE_STAY_AT_LISTENING_FROM_RECEIVING_MILLIS = 84 "satellite_stay_at_listening_from_receiving_millis"; 85 /** 86 * The default value of {@link #SATELLITE_STAY_AT_LISTENING_FROM_RECEIVING_MILLIS} 87 */ 88 public static final long DEFAULT_SATELLITE_STAY_AT_LISTENING_FROM_RECEIVING_MILLIS = 30000; 89 /** 90 * The default value of {@link #SATELLITE_STAY_AT_LISTENING_FROM_SENDING_MILLIS}, 91 * and {@link #SATELLITE_STAY_AT_LISTENING_FROM_RECEIVING_MILLIS} for demo mode 92 */ 93 public static final long DEMO_MODE_SATELLITE_STAY_AT_LISTENING_MILLIS = 3000; 94 95 private static final int EVENT_DATAGRAM_TRANSFER_STATE_CHANGED = 1; 96 private static final int EVENT_LISTENING_TIMER_TIMEOUT = 2; 97 private static final int EVENT_SATELLITE_ENABLED_STATE_CHANGED = 3; 98 99 private static final long REBIND_INITIAL_DELAY = 2 * 1000; // 2 seconds 100 private static final long REBIND_MAXIMUM_DELAY = 64 * 1000; // 1 minute 101 private static final int REBIND_MULTIPLIER = 2; 102 @NonNull private final ExponentialBackoff mExponentialBackoff; 103 @NonNull private final Object mLock = new Object(); 104 @Nullable 105 private ISatelliteGateway mSatelliteGatewayService; 106 private String mSatelliteGatewayServicePackageName = ""; 107 @Nullable private SatelliteGatewayServiceConnection mSatelliteGatewayServiceConnection; 108 private boolean mIsBound; 109 private boolean mIsBinding; 110 111 @NonNull private static SatelliteSessionController sInstance; 112 113 @NonNull private final Context mContext; 114 @NonNull private final SatelliteModemInterface mSatelliteModemInterface; 115 @NonNull private final UnavailableState mUnavailableState = new UnavailableState(); 116 @NonNull private final PowerOffState mPowerOffState = new PowerOffState(); 117 @NonNull private final IdleState mIdleState = new IdleState(); 118 @NonNull private final TransferringState mTransferringState = new TransferringState(); 119 @NonNull private final ListeningState mListeningState = new ListeningState(); 120 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) 121 protected AtomicBoolean mIsSendingTriggeredDuringTransferringState; 122 private long mSatelliteStayAtListeningFromSendingMillis; 123 private long mSatelliteStayAtListeningFromReceivingMillis; 124 private final ConcurrentHashMap<IBinder, ISatelliteStateCallback> mListeners; 125 @SatelliteManager.SatelliteModemState private int mCurrentState; 126 final boolean mIsSatelliteSupported; 127 private boolean mIsDemoMode = false; 128 129 /** 130 * @return The singleton instance of SatelliteSessionController. 131 */ getInstance()132 public static SatelliteSessionController getInstance() { 133 if (sInstance == null) { 134 Log.e(TAG, "SatelliteSessionController was not yet initialized."); 135 } 136 return sInstance; 137 } 138 139 /** 140 * Create the SatelliteSessionController singleton instance. 141 * 142 * @param context The Context for the SatelliteSessionController. 143 * @param looper The looper associated with the handler of this class. 144 * @param isSatelliteSupported Whether satellite is supported on the device. 145 * @return The singleton instance of SatelliteSessionController. 146 */ make( @onNull Context context, @NonNull Looper looper, boolean isSatelliteSupported)147 public static SatelliteSessionController make( 148 @NonNull Context context, @NonNull Looper looper, boolean isSatelliteSupported) { 149 if (sInstance == null) { 150 sInstance = new SatelliteSessionController(context, looper, isSatelliteSupported, 151 SatelliteModemInterface.getInstance(), 152 getSatelliteStayAtListeningFromSendingMillis(), 153 getSatelliteStayAtListeningFromReceivingMillis()); 154 } else { 155 if (isSatelliteSupported != sInstance.mIsSatelliteSupported) { 156 Rlog.e(TAG, "New satellite support state " + isSatelliteSupported 157 + " is different from existing state " + sInstance.mIsSatelliteSupported 158 + ". Ignore the new state."); 159 } 160 } 161 return sInstance; 162 } 163 164 /** 165 * Create a SatelliteSessionController to manage satellite session. 166 * 167 * @param context The Context for the SatelliteSessionController. 168 * @param looper The looper associated with the handler of this class. 169 * @param isSatelliteSupported Whether satellite is supported on the device. 170 * @param satelliteModemInterface The singleton of SatelliteModemInterface. 171 * @param satelliteStayAtListeningFromSendingMillis The duration to stay at listening mode when 172 * transitioning from sending mode. 173 * @param satelliteStayAtListeningFromReceivingMillis The duration to stay at listening mode 174 * when transitioning from receiving mode. 175 */ 176 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) SatelliteSessionController(@onNull Context context, @NonNull Looper looper, boolean isSatelliteSupported, @NonNull SatelliteModemInterface satelliteModemInterface, long satelliteStayAtListeningFromSendingMillis, long satelliteStayAtListeningFromReceivingMillis)177 protected SatelliteSessionController(@NonNull Context context, @NonNull Looper looper, 178 boolean isSatelliteSupported, 179 @NonNull SatelliteModemInterface satelliteModemInterface, 180 long satelliteStayAtListeningFromSendingMillis, 181 long satelliteStayAtListeningFromReceivingMillis) { 182 super(TAG, looper); 183 184 mContext = context; 185 mSatelliteModemInterface = satelliteModemInterface; 186 mSatelliteStayAtListeningFromSendingMillis = satelliteStayAtListeningFromSendingMillis; 187 mSatelliteStayAtListeningFromReceivingMillis = satelliteStayAtListeningFromReceivingMillis; 188 mListeners = new ConcurrentHashMap<>(); 189 mIsSendingTriggeredDuringTransferringState = new AtomicBoolean(false); 190 mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN; 191 mIsSatelliteSupported = isSatelliteSupported; 192 mExponentialBackoff = new ExponentialBackoff(REBIND_INITIAL_DELAY, REBIND_MAXIMUM_DELAY, 193 REBIND_MULTIPLIER, looper, () -> { 194 synchronized (mLock) { 195 if ((mIsBound && mSatelliteGatewayService != null) || mIsBinding) { 196 return; 197 } 198 } 199 if (mSatelliteGatewayServiceConnection != null) { 200 synchronized (mLock) { 201 mIsBound = false; 202 mIsBinding = false; 203 } 204 unbindService(); 205 } 206 bindService(); 207 }); 208 209 addState(mUnavailableState); 210 addState(mPowerOffState); 211 addState(mIdleState); 212 addState(mTransferringState); 213 addState(mListeningState, mTransferringState); 214 setInitialState(isSatelliteSupported); 215 start(); 216 } 217 218 /** 219 * {@link DatagramController} uses this function to notify {@link SatelliteSessionController} 220 * that its datagram transfer state has changed. 221 * 222 * @param sendState The current datagram send state of {@link DatagramController}. 223 * @param receiveState The current datagram receive state of {@link DatagramController}. 224 */ 225 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) onDatagramTransferStateChanged( @atelliteManager.SatelliteDatagramTransferState int sendState, @SatelliteManager.SatelliteDatagramTransferState int receiveState)226 public void onDatagramTransferStateChanged( 227 @SatelliteManager.SatelliteDatagramTransferState int sendState, 228 @SatelliteManager.SatelliteDatagramTransferState int receiveState) { 229 sendMessage(EVENT_DATAGRAM_TRANSFER_STATE_CHANGED, 230 new DatagramTransferState(sendState, receiveState)); 231 if (sendState == SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING) { 232 mIsSendingTriggeredDuringTransferringState.set(true); 233 } 234 } 235 236 /** 237 * {@link SatelliteController} uses this function to notify {@link SatelliteSessionController} 238 * that the satellite enabled state has changed. 239 * 240 * @param enabled {@code true} means enabled and {@code false} means disabled. 241 */ 242 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) onSatelliteEnabledStateChanged(boolean enabled)243 public void onSatelliteEnabledStateChanged(boolean enabled) { 244 sendMessage(EVENT_SATELLITE_ENABLED_STATE_CHANGED, enabled); 245 } 246 247 /** 248 * Registers for modem state changed from satellite modem. 249 * 250 * @param callback The callback to handle the satellite modem state changed event. 251 */ registerForSatelliteModemStateChanged(@onNull ISatelliteStateCallback callback)252 public void registerForSatelliteModemStateChanged(@NonNull ISatelliteStateCallback callback) { 253 try { 254 callback.onSatelliteModemStateChanged(mCurrentState); 255 mListeners.put(callback.asBinder(), callback); 256 } catch (RemoteException ex) { 257 loge("registerForSatelliteModemStateChanged: Got RemoteException ex=" + ex); 258 } 259 } 260 261 /** 262 * Unregisters for modem state changed from satellite modem. 263 * If callback was not registered before, the request will be ignored. 264 * 265 * @param callback The callback that was passed to 266 * {@link #registerForSatelliteModemStateChanged(ISatelliteStateCallback)}. 267 */ unregisterForSatelliteModemStateChanged(@onNull ISatelliteStateCallback callback)268 public void unregisterForSatelliteModemStateChanged(@NonNull ISatelliteStateCallback callback) { 269 mListeners.remove(callback.asBinder()); 270 } 271 272 /** 273 * This API can be used by only CTS to update the timeout duration in milliseconds that 274 * satellite should stay at listening mode to wait for the next incoming page before disabling 275 * listening mode. 276 * 277 * @param timeoutMillis The timeout duration in millisecond. 278 * @return {@code true} if the timeout duration is set successfully, {@code false} otherwise. 279 */ setSatelliteListeningTimeoutDuration(long timeoutMillis)280 boolean setSatelliteListeningTimeoutDuration(long timeoutMillis) { 281 if (!isMockModemAllowed()) { 282 loge("Updating listening timeout duration is not allowed"); 283 return false; 284 } 285 286 logd("setSatelliteListeningTimeoutDuration: timeoutMillis=" + timeoutMillis); 287 if (timeoutMillis == 0) { 288 mSatelliteStayAtListeningFromSendingMillis = 289 getSatelliteStayAtListeningFromSendingMillis(); 290 mSatelliteStayAtListeningFromReceivingMillis = 291 getSatelliteStayAtListeningFromReceivingMillis(); 292 } else { 293 mSatelliteStayAtListeningFromSendingMillis = timeoutMillis; 294 mSatelliteStayAtListeningFromReceivingMillis = timeoutMillis; 295 } 296 297 return true; 298 } 299 300 /** 301 * This API can be used by only CTS to update satellite gateway service package name. 302 * 303 * @param servicePackageName The package name of the satellite gateway service. 304 * @return {@code true} if the satellite gateway service is set successfully, 305 * {@code false} otherwise. 306 */ setSatelliteGatewayServicePackageName(@ullable String servicePackageName)307 boolean setSatelliteGatewayServicePackageName(@Nullable String servicePackageName) { 308 if (!isMockModemAllowed()) { 309 loge("setSatelliteGatewayServicePackageName: modifying satellite gateway service " 310 + "package name is not allowed"); 311 return false; 312 } 313 314 logd("setSatelliteGatewayServicePackageName: config_satellite_gateway_service_package is " 315 + "updated, new packageName=" + servicePackageName); 316 317 if (servicePackageName == null || servicePackageName.equals("null")) { 318 mSatelliteGatewayServicePackageName = ""; 319 } else { 320 mSatelliteGatewayServicePackageName = servicePackageName; 321 } 322 323 if (mSatelliteGatewayServiceConnection != null) { 324 synchronized (mLock) { 325 mIsBound = false; 326 mIsBinding = false; 327 } 328 unbindService(); 329 bindService(); 330 } 331 return true; 332 } 333 /** 334 * Adjusts listening timeout duration when demo mode is on 335 * 336 * @param isDemoMode {@code true} : The listening timeout durations will be set to 337 * {@link #DEMO_MODE_SATELLITE_STAY_AT_LISTENING_MILLIS} 338 * {@code false} : The listening timeout durations will be restored to 339 * production mode 340 */ 341 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) setDemoMode(boolean isDemoMode)342 public void setDemoMode(boolean isDemoMode) { 343 mIsDemoMode = isDemoMode; 344 } 345 isDemoMode()346 private boolean isDemoMode() { 347 return mIsDemoMode; 348 } 349 350 private static class DatagramTransferState { 351 @SatelliteManager.SatelliteDatagramTransferState public int sendState; 352 @SatelliteManager.SatelliteDatagramTransferState public int receiveState; 353 DatagramTransferState(@atelliteManager.SatelliteDatagramTransferState int sendState, @SatelliteManager.SatelliteDatagramTransferState int receiveState)354 DatagramTransferState(@SatelliteManager.SatelliteDatagramTransferState int sendState, 355 @SatelliteManager.SatelliteDatagramTransferState int receiveState) { 356 this.sendState = sendState; 357 this.receiveState = receiveState; 358 } 359 } 360 361 private class UnavailableState extends State { 362 @Override enter()363 public void enter() { 364 if (DBG) logd("Entering UnavailableState"); 365 mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE; 366 } 367 368 @Override processMessage(Message msg)369 public boolean processMessage(Message msg) { 370 loge("UnavailableState: receive msg " + getWhatToString(msg.what) + " unexpectedly"); 371 return HANDLED; 372 } 373 } 374 375 private class PowerOffState extends State { 376 @Override enter()377 public void enter() { 378 if (DBG) logd("Entering PowerOffState"); 379 380 mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_OFF; 381 mIsSendingTriggeredDuringTransferringState.set(false); 382 unbindService(); 383 notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_OFF); 384 } 385 386 @Override exit()387 public void exit() { 388 if (DBG) logd("Exiting PowerOffState"); 389 logd("Attempting to bind to SatelliteGatewayService."); 390 bindService(); 391 } 392 393 @Override processMessage(Message msg)394 public boolean processMessage(Message msg) { 395 if (DBG) log("PowerOffState: processing " + getWhatToString(msg.what)); 396 switch (msg.what) { 397 case EVENT_SATELLITE_ENABLED_STATE_CHANGED: 398 handleSatelliteEnabledStateChanged((boolean) msg.obj); 399 break; 400 } 401 // Ignore all unexpected events. 402 return HANDLED; 403 } 404 handleSatelliteEnabledStateChanged(boolean on)405 private void handleSatelliteEnabledStateChanged(boolean on) { 406 if (on) { 407 transitionTo(mIdleState); 408 } 409 } 410 } 411 412 private class IdleState extends State { 413 @Override enter()414 public void enter() { 415 if (DBG) logd("Entering IdleState"); 416 mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_IDLE; 417 mIsSendingTriggeredDuringTransferringState.set(false); 418 //Enable Cellular Modem scanning 419 mSatelliteModemInterface.enableCellularModemWhileSatelliteModeIsOn(true, null); 420 notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_IDLE); 421 } 422 423 @Override processMessage(Message msg)424 public boolean processMessage(Message msg) { 425 if (DBG) log("IdleState: processing " + getWhatToString(msg.what)); 426 switch (msg.what) { 427 case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED: 428 handleEventDatagramTransferStateChanged((DatagramTransferState) msg.obj); 429 break; 430 case EVENT_SATELLITE_ENABLED_STATE_CHANGED: 431 handleSatelliteEnabledStateChanged(!(boolean) msg.obj, "IdleState"); 432 break; 433 } 434 // Ignore all unexpected events. 435 return HANDLED; 436 } 437 handleEventDatagramTransferStateChanged( @onNull DatagramTransferState datagramTransferState)438 private void handleEventDatagramTransferStateChanged( 439 @NonNull DatagramTransferState datagramTransferState) { 440 if ((datagramTransferState.sendState == SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING) 441 || (datagramTransferState.receiveState 442 == SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING)) { 443 transitionTo(mTransferringState); 444 } 445 } 446 447 @Override exit()448 public void exit() { 449 if (DBG) logd("Exiting IdleState"); 450 //Disable Cellular Modem Scanning 451 mSatelliteModemInterface.enableCellularModemWhileSatelliteModeIsOn(false, null); 452 } 453 } 454 455 private class TransferringState extends State { 456 @Override enter()457 public void enter() { 458 if (DBG) logd("Entering TransferringState"); 459 mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING; 460 notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING); 461 } 462 463 @Override processMessage(Message msg)464 public boolean processMessage(Message msg) { 465 if (DBG) log("TransferringState: processing " + getWhatToString(msg.what)); 466 switch (msg.what) { 467 case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED: 468 handleEventDatagramTransferStateChanged((DatagramTransferState) msg.obj); 469 return HANDLED; 470 case EVENT_SATELLITE_ENABLED_STATE_CHANGED: 471 handleSatelliteEnabledStateChanged(!(boolean) msg.obj, "TransferringState"); 472 break; 473 } 474 // Ignore all unexpected events. 475 return HANDLED; 476 } 477 handleEventDatagramTransferStateChanged( @onNull DatagramTransferState datagramTransferState)478 private void handleEventDatagramTransferStateChanged( 479 @NonNull DatagramTransferState datagramTransferState) { 480 if (isSending(datagramTransferState.sendState) || isReceiving( 481 datagramTransferState.receiveState)) { 482 // Stay at transferring state. 483 } else if ((datagramTransferState.sendState 484 == SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED) 485 || (datagramTransferState.receiveState 486 == SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED)) { 487 transitionTo(mIdleState); 488 } else { 489 transitionTo(mListeningState); 490 } 491 } 492 } 493 494 private class ListeningState extends State { 495 @Override enter()496 public void enter() { 497 if (DBG) logd("Entering ListeningState"); 498 499 mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_LISTENING; 500 long timeoutMillis = updateListeningMode(true); 501 sendMessageDelayed(EVENT_LISTENING_TIMER_TIMEOUT, timeoutMillis); 502 mIsSendingTriggeredDuringTransferringState.set(false); 503 notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_LISTENING); 504 } 505 506 @Override exit()507 public void exit() { 508 removeMessages(EVENT_LISTENING_TIMER_TIMEOUT); 509 updateListeningMode(false); 510 } 511 512 @Override processMessage(Message msg)513 public boolean processMessage(Message msg) { 514 if (DBG) log("ListeningState: processing " + getWhatToString(msg.what)); 515 switch (msg.what) { 516 case EVENT_LISTENING_TIMER_TIMEOUT: 517 transitionTo(mIdleState); 518 break; 519 case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED: 520 handleEventDatagramTransferStateChanged((DatagramTransferState) msg.obj); 521 break; 522 case EVENT_SATELLITE_ENABLED_STATE_CHANGED: 523 handleSatelliteEnabledStateChanged(!(boolean) msg.obj, "ListeningState"); 524 break; 525 } 526 // Ignore all unexpected events. 527 return HANDLED; 528 } 529 updateListeningMode(boolean enabled)530 private long updateListeningMode(boolean enabled) { 531 long timeoutMillis; 532 if (mIsSendingTriggeredDuringTransferringState.get()) { 533 timeoutMillis = mSatelliteStayAtListeningFromSendingMillis; 534 } else { 535 timeoutMillis = mSatelliteStayAtListeningFromReceivingMillis; 536 } 537 mSatelliteModemInterface.requestSatelliteListeningEnabled( 538 enabled, (int) timeoutMillis, null); 539 return timeoutMillis; 540 } 541 handleEventDatagramTransferStateChanged( @onNull DatagramTransferState datagramTransferState)542 private void handleEventDatagramTransferStateChanged( 543 @NonNull DatagramTransferState datagramTransferState) { 544 if (datagramTransferState.sendState == SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING 545 || datagramTransferState.receiveState 546 == SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING) { 547 transitionTo(mTransferringState); 548 } 549 } 550 } 551 552 /** 553 * @return the string for msg.what 554 */ 555 @Override getWhatToString(int what)556 protected String getWhatToString(int what) { 557 String whatString; 558 switch (what) { 559 case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED: 560 whatString = "EVENT_DATAGRAM_TRANSFER_STATE_CHANGED"; 561 break; 562 case EVENT_LISTENING_TIMER_TIMEOUT: 563 whatString = "EVENT_LISTENING_TIMER_TIMEOUT"; 564 break; 565 case EVENT_SATELLITE_ENABLED_STATE_CHANGED: 566 whatString = "EVENT_SATELLITE_ENABLED_STATE_CHANGED"; 567 break; 568 default: 569 whatString = "UNKNOWN EVENT " + what; 570 } 571 return whatString; 572 } 573 setInitialState(boolean isSatelliteSupported)574 private void setInitialState(boolean isSatelliteSupported) { 575 if (isSatelliteSupported) { 576 setInitialState(mPowerOffState); 577 } else { 578 setInitialState(mUnavailableState); 579 } 580 } 581 notifyStateChangedEvent(@atelliteManager.SatelliteModemState int state)582 private void notifyStateChangedEvent(@SatelliteManager.SatelliteModemState int state) { 583 List<ISatelliteStateCallback> toBeRemoved = new ArrayList<>(); 584 mListeners.values().forEach(listener -> { 585 try { 586 listener.onSatelliteModemStateChanged(state); 587 } catch (RemoteException e) { 588 logd("notifyStateChangedEvent RemoteException: " + e); 589 toBeRemoved.add(listener); 590 } 591 }); 592 593 toBeRemoved.forEach(listener -> { 594 mListeners.remove(listener.asBinder()); 595 }); 596 } 597 handleSatelliteEnabledStateChanged(boolean off, String caller)598 private void handleSatelliteEnabledStateChanged(boolean off, String caller) { 599 if (off) { 600 transitionTo(mPowerOffState); 601 } else { 602 loge(caller + ": Unexpected satellite radio powered-on state changed event"); 603 } 604 } 605 isSending(@atelliteManager.SatelliteDatagramTransferState int sendState)606 private boolean isSending(@SatelliteManager.SatelliteDatagramTransferState int sendState) { 607 return (sendState == SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING 608 || sendState == SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS); 609 } 610 isReceiving(@atelliteManager.SatelliteDatagramTransferState int receiveState)611 private boolean isReceiving(@SatelliteManager.SatelliteDatagramTransferState int receiveState) { 612 return (receiveState == SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING 613 || receiveState == SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS 614 || receiveState == SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE); 615 } 616 617 @NonNull getSatelliteGatewayPackageName()618 private String getSatelliteGatewayPackageName() { 619 if (!TextUtils.isEmpty(mSatelliteGatewayServicePackageName)) { 620 return mSatelliteGatewayServicePackageName; 621 } 622 return TextUtils.emptyIfNull(mContext.getResources().getString( 623 R.string.config_satellite_gateway_service_package)); 624 } 625 bindService()626 private void bindService() { 627 synchronized (mLock) { 628 if (mIsBinding || mIsBound) return; 629 mIsBinding = true; 630 } 631 mExponentialBackoff.start(); 632 633 String packageName = getSatelliteGatewayPackageName(); 634 if (TextUtils.isEmpty(packageName)) { 635 loge("Unable to bind to the satellite gateway service because the package is" 636 + " undefined."); 637 // Since the package name comes from static device configs, stop retry because 638 // rebind will continue to fail without a valid package name. 639 synchronized (mLock) { 640 mIsBinding = false; 641 } 642 mExponentialBackoff.stop(); 643 return; 644 } 645 Intent intent = new Intent(SatelliteGatewayService.SERVICE_INTERFACE); 646 intent.setPackage(packageName); 647 648 mSatelliteGatewayServiceConnection = new SatelliteGatewayServiceConnection(); 649 try { 650 boolean success = mContext.bindService( 651 intent, mSatelliteGatewayServiceConnection, Context.BIND_AUTO_CREATE); 652 if (success) { 653 logd("Successfully bound to the satellite gateway service."); 654 } else { 655 synchronized (mLock) { 656 mIsBinding = false; 657 } 658 mExponentialBackoff.notifyFailed(); 659 loge("Error binding to the satellite gateway service. Retrying in " 660 + mExponentialBackoff.getCurrentDelay() + " ms."); 661 } 662 } catch (Exception e) { 663 synchronized (mLock) { 664 mIsBinding = false; 665 } 666 mExponentialBackoff.notifyFailed(); 667 loge("Exception binding to the satellite gateway service. Retrying in " 668 + mExponentialBackoff.getCurrentDelay() + " ms. Exception: " + e); 669 } 670 } 671 unbindService()672 private void unbindService() { 673 logd("unbindService"); 674 mExponentialBackoff.stop(); 675 mSatelliteGatewayService = null; 676 synchronized (mLock) { 677 mIsBinding = false; 678 mIsBound = false; 679 } 680 if (mSatelliteGatewayServiceConnection != null) { 681 mContext.unbindService(mSatelliteGatewayServiceConnection); 682 mSatelliteGatewayServiceConnection = null; 683 } 684 } 685 private class SatelliteGatewayServiceConnection implements ServiceConnection { 686 @Override onServiceConnected(ComponentName name, IBinder service)687 public void onServiceConnected(ComponentName name, IBinder service) { 688 logd("onServiceConnected: ComponentName=" + name); 689 synchronized (mLock) { 690 mIsBound = true; 691 mIsBinding = false; 692 } 693 mSatelliteGatewayService = ISatelliteGateway.Stub.asInterface(service); 694 mExponentialBackoff.stop(); 695 } 696 697 @Override onServiceDisconnected(ComponentName name)698 public void onServiceDisconnected(ComponentName name) { 699 loge("onServiceDisconnected: Waiting for reconnect."); 700 synchronized (mLock) { 701 mIsBinding = false; 702 mIsBound = false; 703 } 704 mSatelliteGatewayService = null; 705 } 706 707 @Override onBindingDied(ComponentName name)708 public void onBindingDied(ComponentName name) { 709 loge("onBindingDied: Unbinding and rebinding service."); 710 synchronized (mLock) { 711 mIsBound = false; 712 mIsBinding = false; 713 } 714 unbindService(); 715 mExponentialBackoff.start(); 716 } 717 } 718 isMockModemAllowed()719 private boolean isMockModemAllowed() { 720 return (DEBUG || SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false)); 721 } 722 getSatelliteStayAtListeningFromSendingMillis()723 private static long getSatelliteStayAtListeningFromSendingMillis() { 724 if (sInstance != null && sInstance.isDemoMode()) { 725 return DEMO_MODE_SATELLITE_STAY_AT_LISTENING_MILLIS; 726 } else { 727 return DeviceConfig.getLong(DeviceConfig.NAMESPACE_TELEPHONY, 728 SATELLITE_STAY_AT_LISTENING_FROM_SENDING_MILLIS, 729 DEFAULT_SATELLITE_STAY_AT_LISTENING_FROM_SENDING_MILLIS); 730 } 731 } 732 getSatelliteStayAtListeningFromReceivingMillis()733 private static long getSatelliteStayAtListeningFromReceivingMillis() { 734 if (sInstance != null && sInstance.isDemoMode()) { 735 return DEMO_MODE_SATELLITE_STAY_AT_LISTENING_MILLIS; 736 } else { 737 return DeviceConfig.getLong(DeviceConfig.NAMESPACE_TELEPHONY, 738 SATELLITE_STAY_AT_LISTENING_FROM_RECEIVING_MILLIS, 739 DEFAULT_SATELLITE_STAY_AT_LISTENING_FROM_RECEIVING_MILLIS); 740 } 741 } 742 } 743