• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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