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_IDLE;
20 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED;
21 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE;
22 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS;
23 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING;
24 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING;
25 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED;
26 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS;
27 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT;
28 
29 import android.annotation.NonNull;
30 import android.annotation.Nullable;
31 import android.content.ComponentName;
32 import android.content.Context;
33 import android.content.Intent;
34 import android.content.ServiceConnection;
35 import android.os.AsyncResult;
36 import android.os.Build;
37 import android.os.IBinder;
38 import android.os.Looper;
39 import android.os.Message;
40 import android.os.RemoteException;
41 import android.os.SystemProperties;
42 import android.telephony.DropBoxManagerLoggerBackend;
43 import android.telephony.PersistentLogger;
44 import android.telephony.Rlog;
45 import android.telephony.satellite.ISatelliteModemStateCallback;
46 import android.telephony.satellite.SatelliteManager;
47 import android.telephony.satellite.stub.ISatelliteGateway;
48 import android.telephony.satellite.stub.SatelliteGatewayService;
49 import android.text.TextUtils;
50 import android.util.Log;
51 
52 import com.android.internal.R;
53 import com.android.internal.annotations.GuardedBy;
54 import com.android.internal.annotations.VisibleForTesting;
55 import com.android.internal.telephony.ExponentialBackoff;
56 import com.android.internal.telephony.flags.FeatureFlags;
57 import com.android.internal.util.State;
58 import com.android.internal.util.StateMachine;
59 
60 import java.util.ArrayList;
61 import java.util.List;
62 import java.util.concurrent.ConcurrentHashMap;
63 import java.util.concurrent.atomic.AtomicBoolean;
64 
65 /**
66  * This module is responsible for managing session state transition and inform listeners of modem
67  * state changed events accordingly.
68  */
69 public class SatelliteSessionController extends StateMachine {
70     private static final String TAG = "SatelliteSessionController";
71     private static final boolean DBG = true;
72     private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem";
73     private static final boolean DEBUG = !"user".equals(Build.TYPE);
74 
75     /**
76      * The time duration in millis that the satellite will stay at listening mode to wait for the
77      * next incoming page before disabling listening mode when transitioning from sending mode.
78      */
79     public static final String SATELLITE_STAY_AT_LISTENING_FROM_SENDING_MILLIS =
80             "satellite_stay_at_listening_from_sending_millis";
81     /**
82      * The default value of {@link #SATELLITE_STAY_AT_LISTENING_FROM_SENDING_MILLIS}.
83      */
84     public static final long DEFAULT_SATELLITE_STAY_AT_LISTENING_FROM_SENDING_MILLIS = 180000;
85     /**
86      * The time duration in millis that the satellite will stay at listening mode to wait for the
87      * next incoming page before disabling listening mode when transitioning from receiving mode.
88      */
89     public static final String SATELLITE_STAY_AT_LISTENING_FROM_RECEIVING_MILLIS =
90             "satellite_stay_at_listening_from_receiving_millis";
91     /**
92      * The default value of {@link #SATELLITE_STAY_AT_LISTENING_FROM_RECEIVING_MILLIS}
93      */
94     public static final long DEFAULT_SATELLITE_STAY_AT_LISTENING_FROM_RECEIVING_MILLIS = 30000;
95     /**
96      * The default value of {@link #SATELLITE_STAY_AT_LISTENING_FROM_SENDING_MILLIS},
97      * and {@link #SATELLITE_STAY_AT_LISTENING_FROM_RECEIVING_MILLIS} for demo mode
98      */
99     public static final long DEMO_MODE_SATELLITE_STAY_AT_LISTENING_MILLIS = 3000;
100 
101     private static final int EVENT_DATAGRAM_TRANSFER_STATE_CHANGED = 1;
102     private static final int EVENT_LISTENING_TIMER_TIMEOUT = 2;
103     private static final int EVENT_SATELLITE_ENABLED_STATE_CHANGED = 3;
104     private static final int EVENT_SATELLITE_MODEM_STATE_CHANGED = 4;
105     private static final int EVENT_DISABLE_CELLULAR_MODEM_WHILE_SATELLITE_MODE_IS_ON_DONE = 5;
106     protected static final int EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT = 6;
107     private static final int EVENT_SATELLITE_ENABLEMENT_STARTED = 7;
108     private static final int EVENT_SATELLITE_ENABLEMENT_FAILED = 8;
109 
110     private static final long REBIND_INITIAL_DELAY = 2 * 1000; // 2 seconds
111     private static final long REBIND_MAXIMUM_DELAY = 64 * 1000; // 1 minute
112     private static final int REBIND_MULTIPLIER = 2;
113     @NonNull private final ExponentialBackoff mExponentialBackoff;
114     @NonNull private final Object mLock = new Object();
115     @Nullable
116     private ISatelliteGateway mSatelliteGatewayService;
117     private String mSatelliteGatewayServicePackageName = "";
118     @Nullable private SatelliteGatewayServiceConnection mSatelliteGatewayServiceConnection;
119     private boolean mIsBound;
120     private boolean mIsBinding;
121 
122     @NonNull private static SatelliteSessionController sInstance;
123 
124     @NonNull private final Context mContext;
125     @NonNull private final SatelliteModemInterface mSatelliteModemInterface;
126     @NonNull private final UnavailableState mUnavailableState = new UnavailableState();
127     @NonNull private final PowerOffState mPowerOffState = new PowerOffState();
128     @NonNull private final EnablingState mEnablingState = new EnablingState();
129     @NonNull private final DisablingState mDisablingState = new DisablingState();
130     @NonNull private final IdleState mIdleState = new IdleState();
131     @NonNull private final TransferringState mTransferringState = new TransferringState();
132     @NonNull private final ListeningState mListeningState = new ListeningState();
133     @NonNull private final NotConnectedState mNotConnectedState = new NotConnectedState();
134     @NonNull private final ConnectedState mConnectedState = new ConnectedState();
135     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
136     protected AtomicBoolean mIsSendingTriggeredDuringTransferringState;
137     private long mSatelliteStayAtListeningFromSendingMillis;
138     private long mSatelliteStayAtListeningFromReceivingMillis;
139     private long mSatelliteNbIotInactivityTimeoutMillis;
140     private final ConcurrentHashMap<IBinder, ISatelliteModemStateCallback> mListeners;
141     @SatelliteManager.SatelliteModemState private int mCurrentState;
142     final boolean mIsSatelliteSupported;
143     private boolean mIsDemoMode = false;
144     @GuardedBy("mLock")
145     @NonNull private boolean mIsDisableCellularModemInProgress = false;
146     @NonNull private final SatelliteController mSatelliteController;
147     @NonNull private final DatagramController mDatagramController;
148     @Nullable private PersistentLogger mPersistentLogger = null;
149 
150 
151     /**
152      * @return The singleton instance of SatelliteSessionController.
153      */
getInstance()154     public static SatelliteSessionController getInstance() {
155         if (sInstance == null) {
156             Log.e(TAG, "SatelliteSessionController was not yet initialized.");
157         }
158         return sInstance;
159     }
160 
161     /**
162      * Create the SatelliteSessionController singleton instance.
163      *
164      * @param context The Context for the SatelliteSessionController.
165      * @param looper The looper associated with the handler of this class.
166      * @param featureFlags The telephony feature flags.
167      * @param isSatelliteSupported Whether satellite is supported on the device.
168      * @return The singleton instance of SatelliteSessionController.
169      */
make( @onNull Context context, @NonNull Looper looper, @NonNull FeatureFlags featureFlags, boolean isSatelliteSupported)170     public static SatelliteSessionController make(
171             @NonNull Context context,
172             @NonNull Looper looper,
173             @NonNull FeatureFlags featureFlags,
174             boolean isSatelliteSupported) {
175         if (sInstance == null || isSatelliteSupported != sInstance.mIsSatelliteSupported) {
176             sInstance = new SatelliteSessionController(
177                     context,
178                     looper,
179                     featureFlags,
180                     isSatelliteSupported,
181                     SatelliteModemInterface.getInstance());
182         }
183         return sInstance;
184     }
185 
186     /**
187      * Create a SatelliteSessionController to manage satellite session.
188      *
189      * @param context The Context for the SatelliteSessionController.
190      * @param looper The looper associated with the handler of this class.
191      * @param featureFlags The telephony feature flags.
192      * @param isSatelliteSupported Whether satellite is supported on the device.
193      * @param satelliteModemInterface The singleton of SatelliteModemInterface.
194      */
195     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
SatelliteSessionController(@onNull Context context, @NonNull Looper looper, @NonNull FeatureFlags featureFlags, boolean isSatelliteSupported, @NonNull SatelliteModemInterface satelliteModemInterface)196     protected SatelliteSessionController(@NonNull Context context, @NonNull Looper looper,
197             @NonNull FeatureFlags featureFlags,
198             boolean isSatelliteSupported,
199             @NonNull SatelliteModemInterface satelliteModemInterface) {
200         super(TAG, looper);
201 
202         if (isSatellitePersistentLoggingEnabled(context, featureFlags)) {
203             mPersistentLogger = new PersistentLogger(
204                     DropBoxManagerLoggerBackend.getInstance(context));
205         }
206 
207         mContext = context;
208         mSatelliteModemInterface = satelliteModemInterface;
209         mSatelliteController = SatelliteController.getInstance();
210         mDatagramController = DatagramController.getInstance();
211         mSatelliteStayAtListeningFromSendingMillis = getSatelliteStayAtListeningFromSendingMillis();
212         mSatelliteStayAtListeningFromReceivingMillis =
213                 getSatelliteStayAtListeningFromReceivingMillis();
214         mSatelliteNbIotInactivityTimeoutMillis =
215                 getSatelliteNbIotInactivityTimeoutMillis();
216         mListeners = new ConcurrentHashMap<>();
217         mIsSendingTriggeredDuringTransferringState = new AtomicBoolean(false);
218         mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN;
219         mIsSatelliteSupported = isSatelliteSupported;
220         mExponentialBackoff = new ExponentialBackoff(REBIND_INITIAL_DELAY, REBIND_MAXIMUM_DELAY,
221                 REBIND_MULTIPLIER, looper, () -> {
222             synchronized (mLock) {
223                 if ((mIsBound && mSatelliteGatewayService != null) || mIsBinding) {
224                     return;
225                 }
226             }
227             if (mSatelliteGatewayServiceConnection != null) {
228                 synchronized (mLock) {
229                     mIsBound = false;
230                     mIsBinding = false;
231                 }
232                 unbindService();
233             }
234             bindService();
235         });
236 
237         addState(mUnavailableState);
238         addState(mPowerOffState);
239         addState(mEnablingState);
240         addState(mDisablingState);
241         addState(mIdleState);
242         addState(mTransferringState);
243         addState(mListeningState);
244         addState(mNotConnectedState);
245         addState(mConnectedState);
246         setInitialState(isSatelliteSupported);
247         start();
248     }
249 
250     /**
251      * {@link DatagramController} uses this function to notify {@link SatelliteSessionController}
252      * that its datagram transfer state has changed.
253      *
254      * @param sendState The current datagram send state of {@link DatagramController}.
255      * @param receiveState The current datagram receive state of {@link DatagramController}.
256      */
257     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
onDatagramTransferStateChanged( @atelliteManager.SatelliteDatagramTransferState int sendState, @SatelliteManager.SatelliteDatagramTransferState int receiveState)258     public void onDatagramTransferStateChanged(
259             @SatelliteManager.SatelliteDatagramTransferState int sendState,
260             @SatelliteManager.SatelliteDatagramTransferState int receiveState) {
261         sendMessage(EVENT_DATAGRAM_TRANSFER_STATE_CHANGED,
262                 new DatagramTransferState(sendState, receiveState));
263         if (sendState == SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING) {
264             mIsSendingTriggeredDuringTransferringState.set(true);
265         }
266     }
267 
268     /**
269      * {@link SatelliteController} uses this function to notify {@link SatelliteSessionController}
270      * that the satellite enabled state has changed.
271      *
272      * @param enabled {@code true} means enabled and {@code false} means disabled.
273      */
274     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
onSatelliteEnabledStateChanged(boolean enabled)275     public void onSatelliteEnabledStateChanged(boolean enabled) {
276         sendMessage(EVENT_SATELLITE_ENABLED_STATE_CHANGED, enabled);
277     }
278 
279     /**
280      * {@link SatelliteController} uses this function to notify {@link SatelliteSessionController}
281      * that the satellite enablement has just started.
282      *
283      * @param enabled {@code true} means being enabled and {@code false} means being disabled.
284      */
285     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
onSatelliteEnablementStarted(boolean enabled)286     public void onSatelliteEnablementStarted(boolean enabled) {
287         sendMessage(EVENT_SATELLITE_ENABLEMENT_STARTED, enabled);
288     }
289 
290     /**
291      * {@link SatelliteController} uses this function to notify {@link SatelliteSessionController}
292      * that the satellite enablement has just failed.
293      */
294     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
onSatelliteEnablementFailed()295     public void onSatelliteEnablementFailed() {
296         sendMessage(EVENT_SATELLITE_ENABLEMENT_FAILED);
297     }
298 
299     /**
300      * {@link SatelliteController} uses this function to notify {@link SatelliteSessionController}
301      * that the satellite modem state has changed.
302      *
303      * @param state The current state of the satellite modem.
304      */
305     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
onSatelliteModemStateChanged(@atelliteManager.SatelliteModemState int state)306     public void onSatelliteModemStateChanged(@SatelliteManager.SatelliteModemState int state) {
307         sendMessage(EVENT_SATELLITE_MODEM_STATE_CHANGED, state);
308     }
309 
310     /**
311      * Registers for modem state changed from satellite modem.
312      *
313      * @param callback The callback to handle the satellite modem state changed event.
314      */
registerForSatelliteModemStateChanged( @onNull ISatelliteModemStateCallback callback)315     public void registerForSatelliteModemStateChanged(
316             @NonNull ISatelliteModemStateCallback callback) {
317         try {
318             callback.onSatelliteModemStateChanged(mCurrentState);
319             mListeners.put(callback.asBinder(), callback);
320         } catch (RemoteException ex) {
321             ploge("registerForSatelliteModemStateChanged: Got RemoteException ex=" + ex);
322         }
323     }
324 
325     /**
326      * Unregisters for modem state changed from satellite modem.
327      * If callback was not registered before, the request will be ignored.
328      *
329      * @param callback The callback that was passed to
330      * {@link #registerForSatelliteModemStateChanged(ISatelliteModemStateCallback)}.
331      */
unregisterForSatelliteModemStateChanged( @onNull ISatelliteModemStateCallback callback)332     public void unregisterForSatelliteModemStateChanged(
333             @NonNull ISatelliteModemStateCallback callback) {
334         mListeners.remove(callback.asBinder());
335     }
336 
337     /**
338      * This API can be used by only CTS to update the timeout duration in milliseconds that
339      * satellite should stay at listening mode to wait for the next incoming page before disabling
340      * listening mode.
341      *
342      * @param timeoutMillis The timeout duration in millisecond.
343      * @return {@code true} if the timeout duration is set successfully, {@code false} otherwise.
344      */
setSatelliteListeningTimeoutDuration(long timeoutMillis)345     boolean setSatelliteListeningTimeoutDuration(long timeoutMillis) {
346         if (!isMockModemAllowed()) {
347             ploge("Updating listening timeout duration is not allowed");
348             return false;
349         }
350 
351         plogd("setSatelliteListeningTimeoutDuration: timeoutMillis=" + timeoutMillis);
352         if (timeoutMillis == 0) {
353             mSatelliteStayAtListeningFromSendingMillis =
354                     getSatelliteStayAtListeningFromSendingMillis();
355             mSatelliteStayAtListeningFromReceivingMillis =
356                     getSatelliteStayAtListeningFromReceivingMillis();
357             mSatelliteNbIotInactivityTimeoutMillis =
358                     getSatelliteNbIotInactivityTimeoutMillis();
359         } else {
360             mSatelliteStayAtListeningFromSendingMillis = timeoutMillis;
361             mSatelliteStayAtListeningFromReceivingMillis = timeoutMillis;
362             mSatelliteNbIotInactivityTimeoutMillis = timeoutMillis;
363         }
364 
365         return true;
366     }
367 
368     /**
369      * This API can be used by only CTS to update satellite gateway service package name.
370      *
371      * @param servicePackageName The package name of the satellite gateway service.
372      * @return {@code true} if the satellite gateway service is set successfully,
373      * {@code false} otherwise.
374      */
setSatelliteGatewayServicePackageName(@ullable String servicePackageName)375     boolean setSatelliteGatewayServicePackageName(@Nullable String servicePackageName) {
376         if (!isMockModemAllowed()) {
377             ploge("setSatelliteGatewayServicePackageName: modifying satellite gateway service "
378                     + "package name is not allowed");
379             return false;
380         }
381 
382         plogd("setSatelliteGatewayServicePackageName: config_satellite_gateway_service_package is "
383                 + "updated, new packageName=" + servicePackageName);
384 
385         if (servicePackageName == null || servicePackageName.equals("null")) {
386             mSatelliteGatewayServicePackageName = "";
387         } else {
388             mSatelliteGatewayServicePackageName = servicePackageName;
389         }
390 
391         if (mSatelliteGatewayServiceConnection != null) {
392             synchronized (mLock) {
393                 mIsBound = false;
394                 mIsBinding = false;
395             }
396             unbindService();
397             bindService();
398         }
399         return true;
400     }
401 
402     /**
403      * Adjusts listening timeout duration when demo mode is on
404      *
405      * @param isDemoMode {@code true} : The listening timeout durations will be set to
406      *                   {@link #DEMO_MODE_SATELLITE_STAY_AT_LISTENING_MILLIS}
407      *                   {@code false} : The listening timeout durations will be restored to
408      *                   production mode
409      */
410     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
setDemoMode(boolean isDemoMode)411     public void setDemoMode(boolean isDemoMode) {
412         mIsDemoMode = isDemoMode;
413     }
414 
415     /**
416      * Get whether state machine is in enabling state.
417      *
418      * @return {@code true} if state machine is in enabling state and {@code false} otherwise.
419      */
isInEnablingState()420     public boolean isInEnablingState() {
421         if (DBG) plogd("isInEnablingState: getCurrentState=" + getCurrentState());
422         return getCurrentState() == mEnablingState;
423     }
424 
isDemoMode()425     private boolean isDemoMode() {
426         return mIsDemoMode;
427     }
428 
429     private static class DatagramTransferState {
430         @SatelliteManager.SatelliteDatagramTransferState public int sendState;
431         @SatelliteManager.SatelliteDatagramTransferState public int receiveState;
432 
DatagramTransferState(@atelliteManager.SatelliteDatagramTransferState int sendState, @SatelliteManager.SatelliteDatagramTransferState int receiveState)433         DatagramTransferState(@SatelliteManager.SatelliteDatagramTransferState int sendState,
434                 @SatelliteManager.SatelliteDatagramTransferState int receiveState) {
435             this.sendState = sendState;
436             this.receiveState = receiveState;
437         }
438     }
439 
440     private class UnavailableState extends State {
441         @Override
enter()442         public void enter() {
443             if (DBG) plogd("Entering UnavailableState");
444             mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE;
445             notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE);
446         }
447 
448         @Override
processMessage(Message msg)449         public boolean processMessage(Message msg) {
450             ploge("UnavailableState: receive msg " + getWhatToString(msg.what) + " unexpectedly");
451             return HANDLED;
452         }
453     }
454 
455     private class PowerOffState extends State {
456         @Override
enter()457         public void enter() {
458             if (DBG) plogd("Entering PowerOffState");
459 
460             mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_OFF;
461             mIsSendingTriggeredDuringTransferringState.set(false);
462             synchronized (mLock) {
463                 mIsDisableCellularModemInProgress = false;
464             }
465             unbindService();
466             stopNbIotInactivityTimer();
467             DemoSimulator.getInstance().onSatelliteModeOff();
468             notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_OFF);
469         }
470 
471         @Override
exit()472         public void exit() {
473             if (DBG) plogd("Exiting PowerOffState");
474             plogd("Attempting to bind to SatelliteGatewayService.");
475             bindService();
476         }
477 
478         @Override
processMessage(Message msg)479         public boolean processMessage(Message msg) {
480             if (DBG) plogd("PowerOffState: processing " + getWhatToString(msg.what));
481             switch (msg.what) {
482                 case EVENT_SATELLITE_ENABLEMENT_STARTED:
483                     handleSatelliteEnablementStarted((boolean) msg.obj);
484                     break;
485             }
486             // Ignore all unexpected events.
487             return HANDLED;
488         }
489 
handleSatelliteEnablementStarted(boolean enabled)490         private void handleSatelliteEnablementStarted(boolean enabled) {
491             if (enabled) {
492                 transitionTo(mEnablingState);
493             } else {
494                 plogw("Unexpected satellite disablement started in PowerOff state");
495             }
496         }
497     }
498 
499     private class EnablingState extends State {
500         @Override
enter()501         public void enter() {
502             if (DBG) plogd("Entering EnablingState");
503 
504             mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_ENABLING_SATELLITE;
505             notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_ENABLING_SATELLITE);
506         }
507 
508         @Override
exit()509         public void exit() {
510             if (DBG) plogd("Exiting EnablingState");
511         }
512 
513         @Override
processMessage(Message msg)514         public boolean processMessage(Message msg) {
515             if (DBG) plogd("EnablingState: processing " + getWhatToString(msg.what));
516             switch (msg.what) {
517                 case EVENT_SATELLITE_ENABLED_STATE_CHANGED:
518                     handleSatelliteEnabledStateChanged((boolean) msg.obj);
519                     break;
520                 case EVENT_SATELLITE_ENABLEMENT_FAILED:
521                     transitionTo(mPowerOffState);
522                     break;
523                 case EVENT_SATELLITE_MODEM_STATE_CHANGED:
524                     deferMessage(msg);
525                     break;
526             }
527             // Ignore all unexpected events.
528             return HANDLED;
529         }
530 
handleSatelliteEnabledStateChanged(boolean on)531         private void handleSatelliteEnabledStateChanged(boolean on) {
532             if (on) {
533                 if (mSatelliteController.isSatelliteAttachRequired()) {
534                     transitionTo(mNotConnectedState);
535                 } else {
536                     transitionTo(mIdleState);
537                 }
538                 DemoSimulator.getInstance().onSatelliteModeOn();
539             } else {
540                 /*
541                  * During the state transition from ENABLING to NOT_CONNECTED, modem might be
542                  * reset. In such cases, we need to remove all deferred
543                  * EVENT_SATELLITE_MODEM_STATE_CHANGED events so that they will not mess up our
544                  * state machine later.
545                  */
546                 removeDeferredMessages(EVENT_SATELLITE_MODEM_STATE_CHANGED);
547                 transitionTo(mPowerOffState);
548             }
549         }
550     }
551 
552     private class DisablingState extends State {
553         @Override
enter()554         public void enter() {
555             if (DBG) plogd("Entering DisablingState");
556 
557             mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_DISABLING_SATELLITE;
558             notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_DISABLING_SATELLITE);
559         }
560 
561         @Override
exit()562         public void exit() {
563             if (DBG) plogd("Exiting DisablingState");
564         }
565 
566         @Override
processMessage(Message msg)567         public boolean processMessage(Message msg) {
568             if (DBG) plogd("DisablingState: processing " + getWhatToString(msg.what));
569             switch (msg.what) {
570                 case EVENT_SATELLITE_ENABLED_STATE_CHANGED:
571                     handleSatelliteEnabledStateChanged((boolean) msg.obj);
572                     break;
573             }
574             // Ignore all unexpected events.
575             return HANDLED;
576         }
577 
handleSatelliteEnabledStateChanged(boolean on)578         private void handleSatelliteEnabledStateChanged(boolean on) {
579             if (on) {
580                 plogw("Unexpected power on event while disabling satellite");
581             } else {
582                 transitionTo(mPowerOffState);
583             }
584         }
585     }
586 
587     private class IdleState extends State {
588         @Override
enter()589         public void enter() {
590             if (DBG) plogd("Entering IdleState");
591             mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_IDLE;
592             mIsSendingTriggeredDuringTransferringState.set(false);
593             stopNbIotInactivityTimer();
594             //Enable Cellular Modem scanning
595             mSatelliteModemInterface.enableCellularModemWhileSatelliteModeIsOn(true, null);
596             notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_IDLE);
597         }
598 
599         @Override
processMessage(Message msg)600         public boolean processMessage(Message msg) {
601             if (DBG) plogd("IdleState: processing " + getWhatToString(msg.what));
602             switch (msg.what) {
603                 case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED:
604                     handleEventDatagramTransferStateChanged((DatagramTransferState) msg.obj);
605                     break;
606                 case EVENT_SATELLITE_ENABLED_STATE_CHANGED:
607                     handleSatelliteEnabledStateChanged(!(boolean) msg.obj, "IdleState");
608                     break;
609                 case EVENT_DISABLE_CELLULAR_MODEM_WHILE_SATELLITE_MODE_IS_ON_DONE:
610                     handleEventDisableCellularModemWhileSatelliteModeIsOnDone(
611                             (AsyncResult) msg.obj);
612                     break;
613                 case EVENT_SATELLITE_ENABLEMENT_STARTED:
614                     handleSatelliteEnablementStarted((boolean) msg.obj);
615                     break;
616             }
617             // Ignore all unexpected events.
618             return HANDLED;
619         }
620 
handleEventDatagramTransferStateChanged( @onNull DatagramTransferState datagramTransferState)621         private void handleEventDatagramTransferStateChanged(
622                 @NonNull DatagramTransferState datagramTransferState) {
623             if ((datagramTransferState.sendState == SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING)
624                     || (datagramTransferState.receiveState
625                     == SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING)) {
626                 if (mSatelliteController.isSatelliteAttachRequired()) {
627                     ploge("Unexpected transferring state received for NB-IOT NTN");
628                 } else {
629                     transitionTo(mTransferringState);
630                 }
631             } else if ((datagramTransferState.sendState
632                     == SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT)
633                     || (datagramTransferState.receiveState
634                     == SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT)) {
635                 if (mSatelliteController.isSatelliteAttachRequired()) {
636                     disableCellularModemWhileSatelliteModeIsOn();
637                 } else {
638                     ploge("Unexpected transferring state received for non-NB-IOT NTN");
639                 }
640             }
641         }
642 
handleEventDisableCellularModemWhileSatelliteModeIsOnDone( @onNull AsyncResult result)643         private void handleEventDisableCellularModemWhileSatelliteModeIsOnDone(
644                 @NonNull AsyncResult result) {
645             synchronized (mLock) {
646                 if (mIsDisableCellularModemInProgress) {
647                     int error = SatelliteServiceUtils.getSatelliteError(
648                             result, "DisableCellularModemWhileSatelliteModeIsOnDone");
649                     if (error == SatelliteManager.SATELLITE_RESULT_SUCCESS) {
650                         transitionTo(mNotConnectedState);
651                     }
652                     mIsDisableCellularModemInProgress = false;
653                 } else {
654                     ploge("DisableCellularModemWhileSatelliteModeIsOn is not in progress");
655                 }
656             }
657         }
658 
disableCellularModemWhileSatelliteModeIsOn()659         private void disableCellularModemWhileSatelliteModeIsOn() {
660             synchronized (mLock) {
661                 if (mIsDisableCellularModemInProgress) {
662                     plogd("Cellular scanning is already being disabled");
663                     return;
664                 }
665 
666                 mIsDisableCellularModemInProgress = true;
667                 Message onCompleted =
668                         obtainMessage(EVENT_DISABLE_CELLULAR_MODEM_WHILE_SATELLITE_MODE_IS_ON_DONE);
669                 mSatelliteModemInterface.enableCellularModemWhileSatelliteModeIsOn(false,
670                         onCompleted);
671             }
672         }
673 
674         @Override
exit()675         public void exit() {
676             if (DBG) plogd("Exiting IdleState");
677             if (!mSatelliteController.isSatelliteAttachRequired()) {
678                 // Disable cellular modem scanning
679                 mSatelliteModemInterface.enableCellularModemWhileSatelliteModeIsOn(false, null);
680             }
681         }
682     }
683 
684     private class TransferringState extends State {
685         @Override
enter()686         public void enter() {
687             if (DBG) plogd("Entering TransferringState");
688             stopNbIotInactivityTimer();
689             mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING;
690             notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING);
691         }
692 
693         @Override
processMessage(Message msg)694         public boolean processMessage(Message msg) {
695             if (DBG) plogd("TransferringState: processing " + getWhatToString(msg.what));
696             switch (msg.what) {
697                 case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED:
698                     handleEventDatagramTransferStateChanged((DatagramTransferState) msg.obj);
699                     return HANDLED;
700                 case EVENT_SATELLITE_ENABLED_STATE_CHANGED:
701                     handleSatelliteEnabledStateChanged(!(boolean) msg.obj, "TransferringState");
702                     break;
703                 case EVENT_SATELLITE_MODEM_STATE_CHANGED:
704                     handleEventSatelliteModemStateChange(msg.arg1);
705                     break;
706                 case EVENT_SATELLITE_ENABLEMENT_STARTED:
707                     handleSatelliteEnablementStarted((boolean) msg.obj);
708                     break;
709             }
710             // Ignore all unexpected events.
711             return HANDLED;
712         }
713 
handleEventDatagramTransferStateChanged( @onNull DatagramTransferState datagramTransferState)714         private void handleEventDatagramTransferStateChanged(
715                 @NonNull DatagramTransferState datagramTransferState) {
716             if (isSending(datagramTransferState.sendState) || isReceiving(
717                     datagramTransferState.receiveState)) {
718                 // Stay at transferring state.
719             } else {
720                 if (mSatelliteController.isSatelliteAttachRequired()) {
721                     transitionTo(mConnectedState);
722                 } else {
723                     if ((datagramTransferState.sendState
724                             == SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED)
725                             || (datagramTransferState.receiveState
726                             == SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED)) {
727                         transitionTo(mIdleState);
728                     } else {
729                         transitionTo(mListeningState);
730                     }
731                 }
732             }
733         }
734 
handleEventSatelliteModemStateChange( @atelliteManager.SatelliteModemState int state)735         private void handleEventSatelliteModemStateChange(
736                 @SatelliteManager.SatelliteModemState int state) {
737             if (state == SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED) {
738                 transitionTo(mNotConnectedState);
739             }
740         }
741     }
742 
743     private class ListeningState extends State {
744         @Override
enter()745         public void enter() {
746             if (DBG) plogd("Entering ListeningState");
747 
748             mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_LISTENING;
749             long timeoutMillis = updateListeningMode(true);
750             sendMessageDelayed(EVENT_LISTENING_TIMER_TIMEOUT, timeoutMillis);
751             mIsSendingTriggeredDuringTransferringState.set(false);
752             notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_LISTENING);
753         }
754 
755         @Override
exit()756         public void exit() {
757             if (DBG) plogd("Exiting ListeningState");
758 
759             removeMessages(EVENT_LISTENING_TIMER_TIMEOUT);
760             updateListeningMode(false);
761         }
762 
763         @Override
processMessage(Message msg)764         public boolean processMessage(Message msg) {
765             if (DBG) plogd("ListeningState: processing " + getWhatToString(msg.what));
766             switch (msg.what) {
767                 case EVENT_LISTENING_TIMER_TIMEOUT:
768                     transitionTo(mIdleState);
769                     break;
770                 case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED:
771                     handleEventDatagramTransferStateChanged((DatagramTransferState) msg.obj);
772                     break;
773                 case EVENT_SATELLITE_ENABLED_STATE_CHANGED:
774                     handleSatelliteEnabledStateChanged(!(boolean) msg.obj, "ListeningState");
775                     break;
776                 case EVENT_SATELLITE_ENABLEMENT_STARTED:
777                     handleSatelliteEnablementStarted((boolean) msg.obj);
778                     break;
779             }
780             // Ignore all unexpected events.
781             return HANDLED;
782         }
783 
updateListeningMode(boolean enabled)784         private long updateListeningMode(boolean enabled) {
785             long timeoutMillis;
786             if (mIsSendingTriggeredDuringTransferringState.get()) {
787                 timeoutMillis = mSatelliteStayAtListeningFromSendingMillis;
788             } else {
789                 timeoutMillis = mSatelliteStayAtListeningFromReceivingMillis;
790             }
791             mSatelliteModemInterface.requestSatelliteListeningEnabled(
792                     enabled, (int) timeoutMillis, null);
793             return timeoutMillis;
794         }
795 
handleEventDatagramTransferStateChanged( @onNull DatagramTransferState datagramTransferState)796         private void handleEventDatagramTransferStateChanged(
797                 @NonNull DatagramTransferState datagramTransferState) {
798             if (datagramTransferState.sendState == SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING
799                     || datagramTransferState.receiveState
800                     == SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING) {
801                 transitionTo(mTransferringState);
802             }
803         }
804     }
805 
806     private class NotConnectedState extends State {
807         @Override
enter()808         public void enter() {
809             if (DBG) plogd("Entering NotConnectedState");
810 
811             mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED;
812             notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED);
813             startNbIotInactivityTimer();
814         }
815 
816         @Override
exit()817         public void exit() {
818             if (DBG) plogd("Exiting NotConnectedState");
819         }
820 
821         @Override
processMessage(Message msg)822         public boolean processMessage(Message msg) {
823             if (DBG) plogd("NotConnectedState: processing " + getWhatToString(msg.what));
824             switch (msg.what) {
825                 case EVENT_SATELLITE_ENABLED_STATE_CHANGED:
826                     handleSatelliteEnabledStateChanged(
827                             !(boolean) msg.obj, "NotConnectedState");
828                     break;
829                 case EVENT_SATELLITE_MODEM_STATE_CHANGED:
830                     handleEventSatelliteModemStateChanged(msg.arg1);
831                     break;
832                 case EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT:
833                     transitionTo(mIdleState);
834                     break;
835                 case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED:
836                     handleEventDatagramTransferStateChanged((DatagramTransferState) msg.obj);
837                     break;
838                 case EVENT_SATELLITE_ENABLEMENT_STARTED:
839                     handleSatelliteEnablementStarted((boolean) msg.obj);
840                     break;
841             }
842             // Ignore all unexpected events.
843             return HANDLED;
844         }
845 
handleEventSatelliteModemStateChanged( @atelliteManager.SatelliteModemState int state)846         private void handleEventSatelliteModemStateChanged(
847                 @SatelliteManager.SatelliteModemState int state) {
848             if (state == SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED) {
849                 transitionTo(mConnectedState);
850             }
851         }
852 
handleEventDatagramTransferStateChanged( @onNull DatagramTransferState datagramTransferState)853         private void handleEventDatagramTransferStateChanged(
854                 @NonNull DatagramTransferState datagramTransferState) {
855             if (datagramTransferState.sendState
856                     == SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT
857                     || datagramTransferState.receiveState
858                     == SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT) {
859                 stopNbIotInactivityTimer();
860             } else if (datagramTransferState.sendState == SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE
861                     && datagramTransferState.receiveState
862                     == SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE) {
863                 startNbIotInactivityTimer();
864             } else if (isSending(datagramTransferState.sendState)
865                     || isReceiving(datagramTransferState.receiveState)) {
866                 restartNbIotInactivityTimer();
867             }
868         }
869     }
870 
871     private class ConnectedState extends State {
872         @Override
enter()873         public void enter() {
874             if (DBG) plogd("Entering ConnectedState");
875 
876             mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED;
877             notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED);
878             startNbIotInactivityTimer();
879         }
880 
881         @Override
exit()882         public void exit() {
883             if (DBG) plogd("Exiting ConnectedState");
884         }
885 
886         @Override
processMessage(Message msg)887         public boolean processMessage(Message msg) {
888             if (DBG) plogd("ConnectedState: processing " + getWhatToString(msg.what));
889             switch (msg.what) {
890                 case EVENT_SATELLITE_ENABLED_STATE_CHANGED:
891                     handleSatelliteEnabledStateChanged(
892                             !(boolean) msg.obj, "ConnectedState");
893                     break;
894                 case EVENT_SATELLITE_MODEM_STATE_CHANGED:
895                     handleEventSatelliteModemStateChanged(msg.arg1);
896                     break;
897                 case EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT:
898                     transitionTo(mIdleState);
899                     break;
900                 case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED:
901                     handleEventDatagramTransferStateChanged((DatagramTransferState) msg.obj);
902                     break;
903                 case EVENT_SATELLITE_ENABLEMENT_STARTED:
904                     handleSatelliteEnablementStarted((boolean) msg.obj);
905                     break;
906             }
907             // Ignore all unexpected events.
908             return HANDLED;
909         }
910 
handleEventSatelliteModemStateChanged( @atelliteManager.SatelliteModemState int state)911         private void handleEventSatelliteModemStateChanged(
912                 @SatelliteManager.SatelliteModemState int state) {
913             if (state == SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED) {
914                 transitionTo(mNotConnectedState);
915             }
916         }
917 
handleEventDatagramTransferStateChanged( @onNull DatagramTransferState datagramTransferState)918         private void handleEventDatagramTransferStateChanged(
919                 @NonNull DatagramTransferState datagramTransferState) {
920             if (isSending(datagramTransferState.sendState)
921                     || isReceiving(datagramTransferState.receiveState)) {
922                 transitionTo(mTransferringState);
923             }
924         }
925     }
926 
927     /**
928      * @return the string for msg.what
929      */
930     @Override
getWhatToString(int what)931     protected String getWhatToString(int what) {
932         String whatString;
933         switch (what) {
934             case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED:
935                 whatString = "EVENT_DATAGRAM_TRANSFER_STATE_CHANGED";
936                 break;
937             case EVENT_LISTENING_TIMER_TIMEOUT:
938                 whatString = "EVENT_LISTENING_TIMER_TIMEOUT";
939                 break;
940             case EVENT_SATELLITE_ENABLED_STATE_CHANGED:
941                 whatString = "EVENT_SATELLITE_ENABLED_STATE_CHANGED";
942                 break;
943             case EVENT_DISABLE_CELLULAR_MODEM_WHILE_SATELLITE_MODE_IS_ON_DONE:
944                 whatString = "EVENT_DISABLE_CELLULAR_MODEM_WHILE_SATELLITE_MODE_IS_ON_DONE";
945                 break;
946             case EVENT_SATELLITE_MODEM_STATE_CHANGED:
947                 whatString = "EVENT_SATELLITE_MODEM_STATE_CHANGED";
948                 break;
949             case EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT:
950                 whatString = "EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT";
951                 break;
952             case EVENT_SATELLITE_ENABLEMENT_STARTED:
953                 whatString = "EVENT_SATELLITE_ENABLEMENT_STARTED";
954                 break;
955             case EVENT_SATELLITE_ENABLEMENT_FAILED:
956                 whatString = "EVENT_SATELLITE_ENABLEMENT_FAILED";
957                 break;
958             default:
959                 whatString = "UNKNOWN EVENT " + what;
960         }
961         return whatString;
962     }
963 
setInitialState(boolean isSatelliteSupported)964     private void setInitialState(boolean isSatelliteSupported) {
965         if (isSatelliteSupported) {
966             setInitialState(mPowerOffState);
967         } else {
968             setInitialState(mUnavailableState);
969         }
970     }
971 
notifyStateChangedEvent(@atelliteManager.SatelliteModemState int state)972     private void notifyStateChangedEvent(@SatelliteManager.SatelliteModemState int state) {
973         mDatagramController.onSatelliteModemStateChanged(state);
974 
975         List<ISatelliteModemStateCallback> toBeRemoved = new ArrayList<>();
976         mListeners.values().forEach(listener -> {
977             try {
978                 listener.onSatelliteModemStateChanged(state);
979             } catch (RemoteException e) {
980                 plogd("notifyStateChangedEvent RemoteException: " + e);
981                 toBeRemoved.add(listener);
982             }
983         });
984 
985         toBeRemoved.forEach(listener -> {
986             mListeners.remove(listener.asBinder());
987         });
988     }
989 
handleSatelliteEnabledStateChanged(boolean off, String caller)990     private void handleSatelliteEnabledStateChanged(boolean off, String caller) {
991         if (off) {
992             transitionTo(mPowerOffState);
993         } else {
994             ploge(caller + ": Unexpected satellite radio powered-on state changed event");
995         }
996     }
997 
isSending(@atelliteManager.SatelliteDatagramTransferState int sendState)998     private boolean isSending(@SatelliteManager.SatelliteDatagramTransferState int sendState) {
999         return (sendState == SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING
1000                 || sendState == SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS);
1001     }
1002 
isReceiving(@atelliteManager.SatelliteDatagramTransferState int receiveState)1003     private boolean isReceiving(@SatelliteManager.SatelliteDatagramTransferState int receiveState) {
1004         return (receiveState == SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING
1005                 || receiveState == SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS
1006                 || receiveState == SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE);
1007     }
1008 
1009     @NonNull
getSatelliteGatewayPackageName()1010     private String getSatelliteGatewayPackageName() {
1011         if (!TextUtils.isEmpty(mSatelliteGatewayServicePackageName)) {
1012             return mSatelliteGatewayServicePackageName;
1013         }
1014         return TextUtils.emptyIfNull(mContext.getResources().getString(
1015                 R.string.config_satellite_gateway_service_package));
1016     }
1017 
bindService()1018     private void bindService() {
1019         synchronized (mLock) {
1020             if (mIsBinding || mIsBound) return;
1021             mIsBinding = true;
1022         }
1023         mExponentialBackoff.start();
1024 
1025         String packageName = getSatelliteGatewayPackageName();
1026         if (TextUtils.isEmpty(packageName)) {
1027             ploge("Unable to bind to the satellite gateway service because the package is"
1028                     + " undefined.");
1029             // Since the package name comes from static device configs, stop retry because
1030             // rebind will continue to fail without a valid package name.
1031             synchronized (mLock) {
1032                 mIsBinding = false;
1033             }
1034             mExponentialBackoff.stop();
1035             return;
1036         }
1037         Intent intent = new Intent(SatelliteGatewayService.SERVICE_INTERFACE);
1038         intent.setPackage(packageName);
1039 
1040         mSatelliteGatewayServiceConnection = new SatelliteGatewayServiceConnection();
1041         try {
1042             boolean success = mContext.bindService(
1043                     intent, mSatelliteGatewayServiceConnection, Context.BIND_AUTO_CREATE);
1044             if (success) {
1045                 plogd("Successfully bound to the satellite gateway service.");
1046             } else {
1047                 synchronized (mLock) {
1048                     mIsBinding = false;
1049                 }
1050                 mExponentialBackoff.notifyFailed();
1051                 ploge("Error binding to the satellite gateway service. Retrying in "
1052                         + mExponentialBackoff.getCurrentDelay() + " ms.");
1053             }
1054         } catch (Exception e) {
1055             synchronized (mLock) {
1056                 mIsBinding = false;
1057             }
1058             mExponentialBackoff.notifyFailed();
1059             ploge("Exception binding to the satellite gateway service. Retrying in "
1060                     + mExponentialBackoff.getCurrentDelay() + " ms. Exception: " + e);
1061         }
1062     }
1063 
unbindService()1064     private void unbindService() {
1065         plogd("unbindService");
1066         mExponentialBackoff.stop();
1067         mSatelliteGatewayService = null;
1068         synchronized (mLock) {
1069             mIsBinding = false;
1070             mIsBound = false;
1071         }
1072         if (mSatelliteGatewayServiceConnection != null) {
1073             mContext.unbindService(mSatelliteGatewayServiceConnection);
1074             mSatelliteGatewayServiceConnection = null;
1075         }
1076     }
1077     private class SatelliteGatewayServiceConnection implements ServiceConnection {
1078         @Override
onServiceConnected(ComponentName name, IBinder service)1079         public void onServiceConnected(ComponentName name, IBinder service) {
1080             plogd("onServiceConnected: ComponentName=" + name);
1081             synchronized (mLock) {
1082                 mIsBound = true;
1083                 mIsBinding = false;
1084             }
1085             mSatelliteGatewayService = ISatelliteGateway.Stub.asInterface(service);
1086             mExponentialBackoff.stop();
1087         }
1088 
1089         @Override
onServiceDisconnected(ComponentName name)1090         public void onServiceDisconnected(ComponentName name) {
1091             ploge("onServiceDisconnected: Waiting for reconnect.");
1092             synchronized (mLock) {
1093                 mIsBinding = false;
1094                 mIsBound = false;
1095             }
1096             mSatelliteGatewayService = null;
1097         }
1098 
1099         @Override
onBindingDied(ComponentName name)1100         public void onBindingDied(ComponentName name) {
1101             ploge("onBindingDied: Unbinding and rebinding service.");
1102             synchronized (mLock) {
1103                 mIsBound = false;
1104                 mIsBinding = false;
1105             }
1106             unbindService();
1107             mExponentialBackoff.start();
1108         }
1109     }
1110 
handleSatelliteEnablementStarted(boolean enabled)1111     private void handleSatelliteEnablementStarted(boolean enabled) {
1112         if (!enabled) {
1113             transitionTo(mDisablingState);
1114         }
1115     }
1116 
isMockModemAllowed()1117     private boolean isMockModemAllowed() {
1118         return (DEBUG || SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false));
1119     }
1120 
getSatelliteStayAtListeningFromSendingMillis()1121     private long getSatelliteStayAtListeningFromSendingMillis() {
1122         if (isDemoMode()) {
1123             return DEMO_MODE_SATELLITE_STAY_AT_LISTENING_MILLIS;
1124         } else {
1125             return mContext.getResources().getInteger(
1126                     R.integer.config_satellite_stay_at_listening_from_sending_millis);
1127         }
1128     }
1129 
getSatelliteStayAtListeningFromReceivingMillis()1130     private long getSatelliteStayAtListeningFromReceivingMillis() {
1131         if (isDemoMode()) {
1132             return DEMO_MODE_SATELLITE_STAY_AT_LISTENING_MILLIS;
1133         } else {
1134             return mContext.getResources().getInteger(
1135                     R.integer.config_satellite_stay_at_listening_from_receiving_millis);
1136         }
1137     }
1138 
getSatelliteNbIotInactivityTimeoutMillis()1139     private long getSatelliteNbIotInactivityTimeoutMillis() {
1140         if (isDemoMode()) {
1141             return mContext.getResources().getInteger(
1142                     R.integer.config_satellite_demo_mode_nb_iot_inactivity_timeout_millis);
1143         } else {
1144             return mContext.getResources().getInteger(
1145                     R.integer.config_satellite_nb_iot_inactivity_timeout_millis);
1146         }
1147     }
1148 
restartNbIotInactivityTimer()1149     private void restartNbIotInactivityTimer() {
1150         stopNbIotInactivityTimer();
1151         startNbIotInactivityTimer();
1152     }
1153 
startNbIotInactivityTimer()1154     private void startNbIotInactivityTimer() {
1155         if (isNbIotInactivityTimerStarted()) {
1156             plogd("NB IOT inactivity timer is already started");
1157             return;
1158         }
1159 
1160         DatagramController datagramController = DatagramController.getInstance();
1161         if (datagramController.isSendingInIdleState()
1162                 && datagramController.isPollingInIdleState()) {
1163             sendMessageDelayed(
1164                     EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT,
1165                     mSatelliteNbIotInactivityTimeoutMillis);
1166         }
1167     }
1168 
stopNbIotInactivityTimer()1169     private void stopNbIotInactivityTimer() {
1170         removeMessages(EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT);
1171     }
1172 
isNbIotInactivityTimerStarted()1173     private boolean isNbIotInactivityTimerStarted() {
1174         return hasMessages(EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT);
1175     }
1176 
isSatellitePersistentLoggingEnabled( @onNull Context context, @NonNull FeatureFlags featureFlags)1177     private boolean isSatellitePersistentLoggingEnabled(
1178             @NonNull Context context, @NonNull FeatureFlags featureFlags) {
1179         if (featureFlags.satellitePersistentLogging()) {
1180             return true;
1181         }
1182         try {
1183             return context.getResources().getBoolean(
1184                     R.bool.config_dropboxmanager_persistent_logging_enabled);
1185         } catch (RuntimeException e) {
1186             return false;
1187         }
1188     }
1189 
plogd(@onNull String log)1190     private void plogd(@NonNull String log) {
1191         logd(log);
1192         if (mPersistentLogger != null) {
1193             mPersistentLogger.debug(TAG, log);
1194         }
1195     }
1196 
plogw(@onNull String log)1197     private void plogw(@NonNull String log) {
1198         logw(log);
1199         if (mPersistentLogger != null) {
1200             mPersistentLogger.warn(TAG, log);
1201         }
1202     }
1203 
ploge(@onNull String log)1204     private void ploge(@NonNull String log) {
1205         loge(log);
1206         if (mPersistentLogger != null) {
1207             mPersistentLogger.error(TAG, log);
1208         }
1209     }
1210 }
1211