• 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 android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.ServiceConnection;
25 import android.os.AsyncResult;
26 import android.os.Binder;
27 import android.os.Handler;
28 import android.os.IBinder;
29 import android.os.Looper;
30 import android.os.Message;
31 import android.os.RegistrantList;
32 import android.os.RemoteException;
33 import android.telephony.Rlog;
34 import android.telephony.satellite.SatelliteCapabilities;
35 import android.telephony.satellite.SatelliteDatagram;
36 import android.telephony.satellite.SatelliteManager;
37 import android.telephony.satellite.SatelliteManager.SatelliteException;
38 import android.telephony.satellite.stub.ISatellite;
39 import android.telephony.satellite.stub.ISatelliteCapabilitiesConsumer;
40 import android.telephony.satellite.stub.ISatelliteListener;
41 import android.telephony.satellite.stub.SatelliteService;
42 import android.text.TextUtils;
43 import android.util.Pair;
44 
45 import com.android.internal.R;
46 import com.android.internal.annotations.VisibleForTesting;
47 import com.android.internal.telephony.ExponentialBackoff;
48 import com.android.internal.telephony.IBooleanConsumer;
49 import com.android.internal.telephony.IIntegerConsumer;
50 
51 import java.util.Arrays;
52 
53 /**
54  * Satellite modem interface to manage connections with the satellite service and HAL interface.
55  */
56 public class SatelliteModemInterface {
57     private static final String TAG = "SatelliteModemInterface";
58     private static final long REBIND_INITIAL_DELAY = 2 * 1000; // 2 seconds
59     private static final long REBIND_MAXIMUM_DELAY = 64 * 1000; // 1 minute
60     private static final int REBIND_MULTIPLIER = 2;
61 
62     @NonNull private static SatelliteModemInterface sInstance;
63     @NonNull private final Context mContext;
64     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
65     @NonNull protected final ExponentialBackoff mExponentialBackoff;
66     @NonNull private final Object mLock = new Object();
67     @NonNull private final SatelliteController mSatelliteController;
68     /**
69      * {@code true} to use the vendor satellite service and {@code false} to use the HAL.
70      */
71     private boolean mIsSatelliteServiceSupported;
72     @Nullable private ISatellite mSatelliteService;
73     @Nullable private SatelliteServiceConnection mSatelliteServiceConnection;
74     @NonNull private String mVendorSatellitePackageName = "";
75     private boolean mIsBound;
76     private boolean mIsBinding;
77 
78     @NonNull private final RegistrantList mSatelliteProvisionStateChangedRegistrants =
79             new RegistrantList();
80     @NonNull private final RegistrantList mSatellitePositionInfoChangedRegistrants =
81             new RegistrantList();
82     @NonNull private final RegistrantList mDatagramTransferStateChangedRegistrants =
83             new RegistrantList();
84     @NonNull private final RegistrantList mSatelliteModemStateChangedRegistrants =
85             new RegistrantList();
86     @NonNull private final RegistrantList mPendingDatagramsRegistrants = new RegistrantList();
87     @NonNull private final RegistrantList mSatelliteDatagramsReceivedRegistrants =
88             new RegistrantList();
89 
90     @NonNull private final ISatelliteListener mListener = new ISatelliteListener.Stub() {
91         @Override
92         public void onSatelliteProvisionStateChanged(boolean provisioned) {
93             mSatelliteProvisionStateChangedRegistrants.notifyResult(provisioned);
94         }
95 
96         @Override
97         public void onSatelliteDatagramReceived(
98                 android.telephony.satellite.stub.SatelliteDatagram datagram, int pendingCount) {
99             mSatelliteDatagramsReceivedRegistrants.notifyResult(new Pair<>(
100                     SatelliteServiceUtils.fromSatelliteDatagram(datagram), pendingCount));
101         }
102 
103         @Override
104         public void onPendingDatagrams() {
105             mPendingDatagramsRegistrants.notifyResult(null);
106         }
107 
108         @Override
109         public void onSatellitePositionChanged(
110                 android.telephony.satellite.stub.PointingInfo pointingInfo) {
111             mSatellitePositionInfoChangedRegistrants.notifyResult(
112                     SatelliteServiceUtils.fromPointingInfo(pointingInfo));
113         }
114 
115         @Override
116         public void onSatelliteModemStateChanged(int state) {
117             mSatelliteModemStateChangedRegistrants.notifyResult(
118                     SatelliteServiceUtils.fromSatelliteModemState(state));
119             int datagramTransferState = SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN;
120             switch (state) {
121                 case SatelliteManager.SATELLITE_MODEM_STATE_IDLE:
122                     datagramTransferState = SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE;
123                     break;
124                 case SatelliteManager.SATELLITE_MODEM_STATE_LISTENING:
125                     datagramTransferState =
126                             SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING;
127                     break;
128                 case SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING:
129                     datagramTransferState =
130                             SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING;
131                     break;
132                 case SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_RETRYING:
133                     // keep previous state as this could be retrying sending or receiving
134                     break;
135             }
136             mDatagramTransferStateChangedRegistrants.notifyResult(datagramTransferState);
137         }
138     };
139 
140     /**
141      * @return The singleton instance of SatelliteModemInterface.
142      */
getInstance()143     public static SatelliteModemInterface getInstance() {
144         if (sInstance == null) {
145             loge("SatelliteModemInterface was not yet initialized.");
146         }
147         return sInstance;
148     }
149 
150     /**
151      * Create the SatelliteModemInterface singleton instance.
152      * @param context The Context to use to create the SatelliteModemInterface.
153      * @param satelliteController The singleton instance of SatelliteController.
154      * @return The singleton instance of SatelliteModemInterface.
155      */
make(@onNull Context context, SatelliteController satelliteController)156     public static SatelliteModemInterface make(@NonNull Context context,
157             SatelliteController satelliteController) {
158         if (sInstance == null) {
159             sInstance = new SatelliteModemInterface(
160                     context, satelliteController, Looper.getMainLooper());
161         }
162         return sInstance;
163     }
164 
165     /**
166      * Create a SatelliteModemInterface to manage connections to the SatelliteService.
167      *
168      * @param context The Context for the SatelliteModemInterface.
169      * @param looper The Looper to run binding retry on.
170      */
171     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
SatelliteModemInterface(@onNull Context context, SatelliteController satelliteController, @NonNull Looper looper)172     protected SatelliteModemInterface(@NonNull Context context,
173             SatelliteController satelliteController, @NonNull Looper looper) {
174         mContext = context;
175         mIsSatelliteServiceSupported = getSatelliteServiceSupport();
176         mSatelliteController = satelliteController;
177         mExponentialBackoff = new ExponentialBackoff(REBIND_INITIAL_DELAY, REBIND_MAXIMUM_DELAY,
178                 REBIND_MULTIPLIER, looper, () -> {
179             synchronized (mLock) {
180                 if ((mIsBound && mSatelliteService != null) || mIsBinding) {
181                     return;
182                 }
183             }
184             if (mSatelliteServiceConnection != null) {
185                 synchronized (mLock) {
186                     mIsBound = false;
187                     mIsBinding = false;
188                 }
189                 unbindService();
190             }
191             bindService();
192         });
193         mExponentialBackoff.start();
194         logd("Created SatelliteModemInterface. Attempting to bind to SatelliteService.");
195         bindService();
196     }
197 
198     /**
199      * Get the SatelliteService interface, if it exists.
200      *
201      * @return The bound ISatellite, or {@code null} if it is not yet connected.
202      */
getService()203     @Nullable public ISatellite getService() {
204         return mSatelliteService;
205     }
206 
getSatellitePackageName()207     @NonNull private String getSatellitePackageName() {
208         if (!TextUtils.isEmpty(mVendorSatellitePackageName)) {
209             return mVendorSatellitePackageName;
210         }
211         return TextUtils.emptyIfNull(mContext.getResources().getString(
212                 R.string.config_satellite_service_package));
213     }
214 
getSatelliteServiceSupport()215     private boolean getSatelliteServiceSupport() {
216         return !TextUtils.isEmpty(getSatellitePackageName());
217     }
218 
219     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
bindService()220     protected void bindService() {
221         synchronized (mLock) {
222             if (mIsBinding || mIsBound) return;
223             mIsBinding = true;
224         }
225         String packageName = getSatellitePackageName();
226         if (TextUtils.isEmpty(packageName)) {
227             loge("Unable to bind to the satellite service because the package is undefined.");
228             // Since the package name comes from static device configs, stop retry because
229             // rebind will continue to fail without a valid package name.
230             synchronized (mLock) {
231                 mIsBinding = false;
232             }
233             mExponentialBackoff.stop();
234             return;
235         }
236         Intent intent = new Intent(SatelliteService.SERVICE_INTERFACE);
237         intent.setPackage(packageName);
238 
239         mSatelliteServiceConnection = new SatelliteServiceConnection();
240         logd("Binding to " + packageName);
241         try {
242             boolean success = mContext.bindService(
243                     intent, mSatelliteServiceConnection, Context.BIND_AUTO_CREATE);
244             if (success) {
245                 logd("Successfully bound to the satellite service.");
246             } else {
247                 synchronized (mLock) {
248                     mIsBinding = false;
249                 }
250                 mExponentialBackoff.notifyFailed();
251                 loge("Error binding to the satellite service. Retrying in "
252                         + mExponentialBackoff.getCurrentDelay() + " ms.");
253             }
254         } catch (Exception e) {
255             synchronized (mLock) {
256                 mIsBinding = false;
257             }
258             mExponentialBackoff.notifyFailed();
259             loge("Exception binding to the satellite service. Retrying in "
260                     + mExponentialBackoff.getCurrentDelay() + " ms. Exception: " + e);
261         }
262     }
263 
264     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
unbindService()265     protected void unbindService() {
266         disconnectSatelliteService();
267         mContext.unbindService(mSatelliteServiceConnection);
268         mSatelliteServiceConnection = null;
269     }
270 
disconnectSatelliteService()271     private void disconnectSatelliteService() {
272         // TODO: clean up any listeners and return failed for pending callbacks
273         mSatelliteService = null;
274     }
275 
276     private class SatelliteServiceConnection implements ServiceConnection {
277         @Override
onServiceConnected(ComponentName name, IBinder service)278         public void onServiceConnected(ComponentName name, IBinder service) {
279             logd("onServiceConnected: ComponentName=" + name);
280             synchronized (mLock) {
281                 mIsBound = true;
282                 mIsBinding = false;
283             }
284             mSatelliteService = ISatellite.Stub.asInterface(service);
285             mExponentialBackoff.stop();
286             try {
287                 mSatelliteService.setSatelliteListener(mListener);
288             } catch (RemoteException e) {
289                 // TODO: Retry setSatelliteListener
290                 logd("setSatelliteListener: RemoteException " + e);
291             }
292             mSatelliteController.onSatelliteServiceConnected();
293         }
294 
295         @Override
onServiceDisconnected(ComponentName name)296         public void onServiceDisconnected(ComponentName name) {
297             loge("onServiceDisconnected: Waiting for reconnect.");
298             synchronized (mLock) {
299                 mIsBinding = false;
300             }
301             // Since we are still technically bound, clear the service and wait for reconnect.
302             disconnectSatelliteService();
303         }
304 
305         @Override
onBindingDied(ComponentName name)306         public void onBindingDied(ComponentName name) {
307             loge("onBindingDied: Unbinding and rebinding service.");
308             synchronized (mLock) {
309                 mIsBound = false;
310                 mIsBinding = false;
311             }
312             unbindService();
313             mExponentialBackoff.start();
314         }
315     }
316 
317     /**
318      * Registers for the satellite provision state changed.
319      *
320      * @param h Handler for notification message.
321      * @param what User-defined message code.
322      * @param obj User object.
323      */
registerForSatelliteProvisionStateChanged( @onNull Handler h, int what, @Nullable Object obj)324     public void registerForSatelliteProvisionStateChanged(
325             @NonNull Handler h, int what, @Nullable Object obj) {
326         mSatelliteProvisionStateChangedRegistrants.add(h, what, obj);
327     }
328 
329     /**
330      * Unregisters for the satellite provision state changed.
331      *
332      * @param h Handler to be removed from the registrant list.
333      */
unregisterForSatelliteProvisionStateChanged(@onNull Handler h)334     public void unregisterForSatelliteProvisionStateChanged(@NonNull Handler h) {
335         mSatelliteProvisionStateChangedRegistrants.remove(h);
336     }
337 
338     /**
339      * Registers for satellite position info changed from satellite modem.
340      *
341      * @param h Handler for notification message.
342      * @param what User-defined message code.
343      * @param obj User object.
344      */
registerForSatellitePositionInfoChanged( @onNull Handler h, int what, @Nullable Object obj)345     public void registerForSatellitePositionInfoChanged(
346             @NonNull Handler h, int what, @Nullable Object obj) {
347         mSatellitePositionInfoChangedRegistrants.add(h, what, obj);
348     }
349 
350     /**
351      * Unregisters for satellite position info changed from satellite modem.
352      *
353      * @param h Handler to be removed from the registrant list.
354      */
unregisterForSatellitePositionInfoChanged(@onNull Handler h)355     public void unregisterForSatellitePositionInfoChanged(@NonNull Handler h) {
356         mSatellitePositionInfoChangedRegistrants.remove(h);
357     }
358 
359     /**
360      * Registers for datagram transfer state changed.
361      *
362      * @param h Handler for notification message.
363      * @param what User-defined message code.
364      * @param obj User object.
365      */
registerForDatagramTransferStateChanged( @onNull Handler h, int what, @Nullable Object obj)366     public void registerForDatagramTransferStateChanged(
367             @NonNull Handler h, int what, @Nullable Object obj) {
368         mDatagramTransferStateChangedRegistrants.add(h, what, obj);
369     }
370 
371     /**
372      * Unregisters for datagram transfer state changed.
373      *
374      * @param h Handler to be removed from the registrant list.
375      */
unregisterForDatagramTransferStateChanged(@onNull Handler h)376     public void unregisterForDatagramTransferStateChanged(@NonNull Handler h) {
377         mDatagramTransferStateChangedRegistrants.remove(h);
378     }
379 
380     /**
381      * Registers for modem state changed from satellite modem.
382      *
383      * @param h Handler for notification message.
384      * @param what User-defined message code.
385      * @param obj User object.
386      */
registerForSatelliteModemStateChanged( @onNull Handler h, int what, @Nullable Object obj)387     public void registerForSatelliteModemStateChanged(
388             @NonNull Handler h, int what, @Nullable Object obj) {
389         mSatelliteModemStateChangedRegistrants.add(h, what, obj);
390     }
391 
392     /**
393      * Unregisters for modem state changed from satellite modem.
394      *
395      * @param h Handler to be removed from the registrant list.
396      */
unregisterForSatelliteModemStateChanged(@onNull Handler h)397     public void unregisterForSatelliteModemStateChanged(@NonNull Handler h) {
398         mSatelliteModemStateChangedRegistrants.remove(h);
399     }
400 
401     /**
402      * Registers for pending datagrams indication from satellite modem.
403      *
404      * @param h Handler for notification message.
405      * @param what User-defined message code.
406      * @param obj User object.
407      */
registerForPendingDatagrams(@onNull Handler h, int what, @Nullable Object obj)408     public void registerForPendingDatagrams(@NonNull Handler h, int what, @Nullable Object obj) {
409         mPendingDatagramsRegistrants.add(h, what, obj);
410     }
411 
412     /**
413      * Unregisters for pending datagrams indication from satellite modem.
414      *
415      * @param h Handler to be removed from the registrant list.
416      */
unregisterForPendingDatagrams(@onNull Handler h)417     public void unregisterForPendingDatagrams(@NonNull Handler h) {
418         mPendingDatagramsRegistrants.remove(h);
419     }
420 
421     /**
422      * Registers for new datagrams received from satellite modem.
423      *
424      * @param h Handler for notification message.
425      * @param what User-defined message code.
426      * @param obj User object.
427      */
registerForSatelliteDatagramsReceived( @onNull Handler h, int what, @Nullable Object obj)428     public void registerForSatelliteDatagramsReceived(
429             @NonNull Handler h, int what, @Nullable Object obj) {
430         mSatelliteDatagramsReceivedRegistrants.add(h, what, obj);
431     }
432 
433     /**
434      * Unregisters for new datagrams received from satellite modem.
435      *
436      * @param h Handler to be removed from the registrant list.
437      */
unregisterForSatelliteDatagramsReceived(@onNull Handler h)438     public void unregisterForSatelliteDatagramsReceived(@NonNull Handler h) {
439         mSatelliteDatagramsReceivedRegistrants.remove(h);
440     }
441 
442     /**
443      * Request to enable or disable the satellite service listening mode.
444      * Listening mode allows the satellite service to listen for incoming pages.
445      *
446      * @param enable True to enable satellite listening mode and false to disable.
447      * @param timeout How long the satellite modem should wait for the next incoming page before
448      *                disabling listening mode.
449      * @param message The Message to send to result of the operation to.
450      */
requestSatelliteListeningEnabled(boolean enable, int timeout, @Nullable Message message)451     public void requestSatelliteListeningEnabled(boolean enable, int timeout,
452             @Nullable Message message) {
453         if (mSatelliteService != null) {
454             try {
455                 mSatelliteService.requestSatelliteListeningEnabled(enable, timeout,
456                         new IIntegerConsumer.Stub() {
457                             @Override
458                             public void accept(int result) {
459                                 int error = SatelliteServiceUtils.fromSatelliteError(result);
460                                 logd("requestSatelliteListeningEnabled: " + error);
461                                 Binder.withCleanCallingIdentity(() -> {
462                                     if (message != null) {
463                                         sendMessageWithResult(message, null, error);
464                                     }
465                                 });
466                             }
467                         });
468             } catch (RemoteException e) {
469                 loge("requestSatelliteListeningEnabled: RemoteException " + e);
470                 if (message != null) {
471                     sendMessageWithResult(
472                             message, null, SatelliteManager.SATELLITE_SERVICE_ERROR);
473                 }
474             }
475         } else {
476             loge("requestSatelliteListeningEnabled: Satellite service is unavailable.");
477             if (message != null) {
478                 sendMessageWithResult(message, null,
479                         SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE);
480             }
481         }
482     }
483 
484     /**
485      * Allow cellular modem scanning while satellite mode is on.
486      * @param enabled  {@code true} to enable cellular modem while satellite mode is on
487      * and {@code false} to disable
488      * @param message The Message to send to result of the operation to.
489      */
enableCellularModemWhileSatelliteModeIsOn(boolean enabled, @Nullable Message message)490     public void enableCellularModemWhileSatelliteModeIsOn(boolean enabled,
491             @Nullable Message message) {
492         if (mSatelliteService != null) {
493             try {
494                 mSatelliteService.enableCellularModemWhileSatelliteModeIsOn(enabled,
495                         new IIntegerConsumer.Stub() {
496                             @Override
497                             public void accept(int result) {
498                                 int error = SatelliteServiceUtils.fromSatelliteError(result);
499                                 logd("enableCellularModemWhileSatelliteModeIsOn: " + error);
500                                 Binder.withCleanCallingIdentity(() -> {
501                                         if (message != null) {
502                                             sendMessageWithResult(message, null, error);
503                                         }
504                                 });
505                             }
506                         });
507             } catch (RemoteException e) {
508                 loge("enableCellularModemWhileSatelliteModeIsOn: RemoteException " + e);
509                 if (message != null) {
510                     sendMessageWithResult(
511                             message, null, SatelliteManager.SATELLITE_SERVICE_ERROR);
512                 }
513             }
514         } else {
515             loge("enableCellularModemWhileSatelliteModeIsOn: Satellite service is unavailable.");
516             if (message != null) {
517                 sendMessageWithResult(message, null,
518                         SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE);
519             }
520         }
521     }
522     /**
523      * Request to enable or disable the satellite modem and demo mode. If the satellite modem
524      * is enabled, this may also disable the cellular modem, and if the satellite modem is disabled,
525      * this may also re-enable the cellular modem.
526      *
527      * @param enableSatellite True to enable the satellite modem and false to disable.
528      * @param enableDemoMode True to enable demo mode and false to disable.
529      * @param message The Message to send to result of the operation to.
530      */
requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode, @NonNull Message message)531     public void requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode,
532             @NonNull Message message) {
533         if (mSatelliteService != null) {
534             try {
535                 mSatelliteService.requestSatelliteEnabled(enableSatellite, enableDemoMode,
536                         new IIntegerConsumer.Stub() {
537                     @Override
538                     public void accept(int result) {
539                         int error = SatelliteServiceUtils.fromSatelliteError(result);
540                         logd("setSatelliteEnabled: " + error);
541                         Binder.withCleanCallingIdentity(() ->
542                                 sendMessageWithResult(message, null, error));
543                     }
544                 });
545             } catch (RemoteException e) {
546                 loge("setSatelliteEnabled: RemoteException " + e);
547                 sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR);
548             }
549         } else {
550             loge("setSatelliteEnabled: Satellite service is unavailable.");
551             sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE);
552         }
553     }
554 
555     /**
556      * Request to get whether the satellite modem is enabled.
557      *
558      * @param message The Message to send to result of the operation to.
559      */
requestIsSatelliteEnabled(@onNull Message message)560     public void requestIsSatelliteEnabled(@NonNull Message message) {
561         if (mSatelliteService != null) {
562             try {
563                 mSatelliteService.requestIsSatelliteEnabled(new IIntegerConsumer.Stub() {
564                     @Override
565                     public void accept(int result) {
566                         int error = SatelliteServiceUtils.fromSatelliteError(result);
567                         logd("requestIsSatelliteEnabled: " + error);
568                         Binder.withCleanCallingIdentity(() ->
569                                 sendMessageWithResult(message, null, error));
570                     }
571                 }, new IBooleanConsumer.Stub() {
572                     @Override
573                     public void accept(boolean result) {
574                         // Convert for compatibility with SatelliteResponse
575                         // TODO: This should just report result instead.
576                         int[] enabled = new int[] {result ? 1 : 0};
577                         logd("requestIsSatelliteEnabled: " + Arrays.toString(enabled));
578                         Binder.withCleanCallingIdentity(() -> sendMessageWithResult(
579                                 message, enabled, SatelliteManager.SATELLITE_ERROR_NONE));
580                     }
581                 });
582             } catch (RemoteException e) {
583                 loge("requestIsSatelliteEnabled: RemoteException " + e);
584                 sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR);
585             }
586         } else {
587             loge("requestIsSatelliteEnabled: Satellite service is unavailable.");
588             sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE);
589         }
590     }
591 
592     /**
593      * Request to get whether the satellite service is supported on the device.
594      *
595      * @param message The Message to send to result of the operation to.
596      */
requestIsSatelliteSupported(@onNull Message message)597     public void requestIsSatelliteSupported(@NonNull Message message) {
598         if (mSatelliteService != null) {
599             try {
600                 mSatelliteService.requestIsSatelliteSupported(new IIntegerConsumer.Stub() {
601                     @Override
602                     public void accept(int result) {
603                         int error = SatelliteServiceUtils.fromSatelliteError(result);
604                         logd("requestIsSatelliteSupported: " + error);
605                         Binder.withCleanCallingIdentity(() ->
606                                 sendMessageWithResult(message, null, error));
607                     }
608                 }, new IBooleanConsumer.Stub() {
609                     @Override
610                     public void accept(boolean result) {
611                         logd("requestIsSatelliteSupported: " + result);
612                         Binder.withCleanCallingIdentity(() -> sendMessageWithResult(
613                                 message, result, SatelliteManager.SATELLITE_ERROR_NONE));
614                     }
615                 });
616             } catch (RemoteException e) {
617                 loge("requestIsSatelliteSupported: RemoteException " + e);
618                 sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR);
619             }
620         } else {
621             loge("requestIsSatelliteSupported: Satellite service is unavailable.");
622             sendMessageWithResult(
623                     message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE);
624         }
625     }
626 
627     /**
628      * Request to get the SatelliteCapabilities of the satellite service.
629      *
630      * @param message The Message to send to result of the operation to.
631      */
requestSatelliteCapabilities(@onNull Message message)632     public void requestSatelliteCapabilities(@NonNull Message message) {
633         if (mSatelliteService != null) {
634             try {
635                 mSatelliteService.requestSatelliteCapabilities(new IIntegerConsumer.Stub() {
636                     @Override
637                     public void accept(int result) {
638                         int error = SatelliteServiceUtils.fromSatelliteError(result);
639                         logd("requestSatelliteCapabilities: " + error);
640                         Binder.withCleanCallingIdentity(() ->
641                                 sendMessageWithResult(message, null, error));
642                     }
643                 }, new ISatelliteCapabilitiesConsumer.Stub() {
644                     @Override
645                     public void accept(android.telephony.satellite.stub.SatelliteCapabilities
646                             result) {
647                         SatelliteCapabilities capabilities =
648                                 SatelliteServiceUtils.fromSatelliteCapabilities(result);
649                         logd("requestSatelliteCapabilities: " + capabilities);
650                         Binder.withCleanCallingIdentity(() -> sendMessageWithResult(
651                                 message, capabilities, SatelliteManager.SATELLITE_ERROR_NONE));
652                     }
653                 });
654             } catch (RemoteException e) {
655                 loge("requestSatelliteCapabilities: RemoteException " + e);
656                 sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR);
657             }
658         } else {
659             loge("requestSatelliteCapabilities: Satellite service is unavailable.");
660             sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE);
661         }
662     }
663 
664     /**
665      * User started pointing to the satellite.
666      * The satellite service should report the satellite pointing info via
667      * ISatelliteListener#onSatellitePositionChanged as the user device/satellite moves.
668      *
669      * @param message The Message to send to result of the operation to.
670      */
startSendingSatellitePointingInfo(@onNull Message message)671     public void startSendingSatellitePointingInfo(@NonNull Message message) {
672         if (mSatelliteService != null) {
673             try {
674                 mSatelliteService.startSendingSatellitePointingInfo(new IIntegerConsumer.Stub() {
675                     @Override
676                     public void accept(int result) {
677                         int error = SatelliteServiceUtils.fromSatelliteError(result);
678                         logd("startSendingSatellitePointingInfo: " + error);
679                         Binder.withCleanCallingIdentity(() ->
680                                 sendMessageWithResult(message, null, error));
681                     }
682                 });
683             } catch (RemoteException e) {
684                 loge("startSendingSatellitePointingInfo: RemoteException " + e);
685                 sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR);
686             }
687         } else {
688             loge("startSendingSatellitePointingInfo: Satellite service is unavailable.");
689             sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE);
690         }
691     }
692 
693     /**
694      * User stopped pointing to the satellite.
695      * The satellite service should stop reporting satellite pointing info to the framework.
696      *
697      * @param message The Message to send to result of the operation to.
698      */
stopSendingSatellitePointingInfo(@onNull Message message)699     public void stopSendingSatellitePointingInfo(@NonNull Message message) {
700         if (mSatelliteService != null) {
701             try {
702                 mSatelliteService.stopSendingSatellitePointingInfo(new IIntegerConsumer.Stub() {
703                     @Override
704                     public void accept(int result) {
705                         int error = SatelliteServiceUtils.fromSatelliteError(result);
706                         logd("stopSendingSatellitePointingInfo: " + error);
707                         Binder.withCleanCallingIdentity(() ->
708                                 sendMessageWithResult(message, null, error));
709                     }
710                 });
711             } catch (RemoteException e) {
712                 loge("stopSendingSatellitePointingInfo: RemoteException " + e);
713                 sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR);
714             }
715         } else {
716             loge("stopSendingSatellitePointingInfo: Satellite service is unavailable.");
717             sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE);
718         }
719     }
720 
721     /**
722      * Provision the device with a satellite provider.
723      * This is needed if the provider allows dynamic registration.
724      * Once provisioned, ISatelliteListener#onSatelliteProvisionStateChanged should report true.
725      *
726      * @param token The token to be used as a unique identifier for provisioning with satellite
727      *              gateway.
728      * @param provisionData Data from the provisioning app that can be used by provisioning server
729      * @param message The Message to send to result of the operation to.
730      */
provisionSatelliteService(@onNull String token, @NonNull byte[] provisionData, @NonNull Message message)731     public void provisionSatelliteService(@NonNull String token, @NonNull byte[] provisionData,
732             @NonNull Message message) {
733         if (mSatelliteService != null) {
734             try {
735                 mSatelliteService.provisionSatelliteService(token, provisionData,
736                         new IIntegerConsumer.Stub() {
737                             @Override
738                             public void accept(int result) {
739                                 int error = SatelliteServiceUtils.fromSatelliteError(result);
740                                 logd("provisionSatelliteService: " + error);
741                                 Binder.withCleanCallingIdentity(() ->
742                                         sendMessageWithResult(message, null, error));
743                             }
744                         });
745             } catch (RemoteException e) {
746                 loge("provisionSatelliteService: RemoteException " + e);
747                 sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR);
748             }
749         } else {
750             loge("provisionSatelliteService: Satellite service is unavailable.");
751             sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE);
752         }
753     }
754 
755     /**
756      * Deprovision the device with the satellite provider.
757      * This is needed if the provider allows dynamic registration.
758      * Once deprovisioned, ISatelliteListener#onSatelliteProvisionStateChanged should report false.
759      *
760      * @param token The token of the device/subscription to be deprovisioned.
761      * @param message The Message to send to result of the operation to.
762      */
deprovisionSatelliteService(@onNull String token, @NonNull Message message)763     public void deprovisionSatelliteService(@NonNull String token, @NonNull Message message) {
764         if (mSatelliteService != null) {
765             try {
766                 mSatelliteService.deprovisionSatelliteService(token, new IIntegerConsumer.Stub() {
767                     @Override
768                     public void accept(int result) {
769                         int error = SatelliteServiceUtils.fromSatelliteError(result);
770                         logd("deprovisionSatelliteService: " + error);
771                         Binder.withCleanCallingIdentity(() ->
772                                 sendMessageWithResult(message, null, error));
773                     }
774                 });
775             } catch (RemoteException e) {
776                 loge("deprovisionSatelliteService: RemoteException " + e);
777                 sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR);
778             }
779         } else {
780             loge("deprovisionSatelliteService: Satellite service is unavailable.");
781             sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE);
782         }
783     }
784 
785     /**
786      * Request to get whether this device is provisioned with a satellite provider.
787      *
788      * @param message The Message to send to result of the operation to.
789      */
requestIsSatelliteProvisioned(@onNull Message message)790     public void requestIsSatelliteProvisioned(@NonNull Message message) {
791         if (mSatelliteService != null) {
792             try {
793                 mSatelliteService.requestIsSatelliteProvisioned(new IIntegerConsumer.Stub() {
794                     @Override
795                     public void accept(int result) {
796                         int error = SatelliteServiceUtils.fromSatelliteError(result);
797                         logd("requestIsSatelliteProvisioned: " + error);
798                         Binder.withCleanCallingIdentity(() ->
799                                 sendMessageWithResult(message, null, error));
800                     }
801                 }, new IBooleanConsumer.Stub() {
802                     @Override
803                     public void accept(boolean result) {
804                         // Convert for compatibility with SatelliteResponse
805                         // TODO: This should just report result instead.
806                         int[] provisioned = new int[] {result ? 1 : 0};
807                         logd("requestIsSatelliteProvisioned: " + Arrays.toString(provisioned));
808                         Binder.withCleanCallingIdentity(() -> sendMessageWithResult(
809                                 message, provisioned, SatelliteManager.SATELLITE_ERROR_NONE));
810                     }
811                 });
812             } catch (RemoteException e) {
813                 loge("requestIsSatelliteProvisioned: RemoteException " + e);
814                 sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR);
815             }
816         } else {
817             loge("requestIsSatelliteProvisioned: Satellite service is unavailable.");
818             sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE);
819         }
820     }
821 
822     /**
823      * Poll the pending datagrams to be received over satellite.
824      * The satellite service should check if there are any pending datagrams to be received over
825      * satellite and report them via ISatelliteListener#onSatelliteDatagramsReceived.
826      *
827      * @param message The Message to send to result of the operation to.
828      */
pollPendingSatelliteDatagrams(@onNull Message message)829     public void pollPendingSatelliteDatagrams(@NonNull Message message) {
830         if (mSatelliteService != null) {
831             try {
832                 mSatelliteService.pollPendingSatelliteDatagrams(new IIntegerConsumer.Stub() {
833                     @Override
834                     public void accept(int result) {
835                         int error = SatelliteServiceUtils.fromSatelliteError(result);
836                         logd("pollPendingSatelliteDatagrams: " + error);
837                         Binder.withCleanCallingIdentity(() ->
838                                 sendMessageWithResult(message, null, error));
839                     }
840                 });
841             } catch (RemoteException e) {
842                 loge("pollPendingSatelliteDatagrams: RemoteException " + e);
843                 sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR);
844             }
845         } else {
846             loge("pollPendingSatelliteDatagrams: Satellite service is unavailable.");
847             sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE);
848         }
849     }
850 
851     /**
852      * Send datagram over satellite.
853      *
854      * @param datagram Datagram to send in byte format.
855      * @param isEmergency Whether this is an emergency datagram.
856      * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in
857      *                                 full screen mode.
858      * @param message The Message to send to result of the operation to.
859      */
sendSatelliteDatagram(@onNull SatelliteDatagram datagram, boolean isEmergency, boolean needFullScreenPointingUI, @NonNull Message message)860     public void sendSatelliteDatagram(@NonNull SatelliteDatagram datagram, boolean isEmergency,
861             boolean needFullScreenPointingUI, @NonNull Message message) {
862         if (mSatelliteService != null) {
863             try {
864                 mSatelliteService.sendSatelliteDatagram(
865                         SatelliteServiceUtils.toSatelliteDatagram(datagram), isEmergency,
866                         new IIntegerConsumer.Stub() {
867                             @Override
868                             public void accept(int result) {
869                                 int error = SatelliteServiceUtils.fromSatelliteError(result);
870                                 logd("sendSatelliteDatagram: " + error);
871                                 Binder.withCleanCallingIdentity(() ->
872                                         sendMessageWithResult(message, null, error));
873                             }
874                         });
875             } catch (RemoteException e) {
876                 loge("sendSatelliteDatagram: RemoteException " + e);
877                 sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR);
878             }
879         } else {
880             loge("sendSatelliteDatagram: Satellite service is unavailable.");
881             sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE);
882         }
883     }
884 
885     /**
886      * Request the current satellite modem state.
887      * The satellite service should report the current satellite modem state via
888      * ISatelliteListener#onSatelliteModemStateChanged.
889      *
890      * @param message The Message to send to result of the operation to.
891      */
requestSatelliteModemState(@onNull Message message)892     public void requestSatelliteModemState(@NonNull Message message) {
893         if (mSatelliteService != null) {
894             try {
895                 mSatelliteService.requestSatelliteModemState(new IIntegerConsumer.Stub() {
896                     @Override
897                     public void accept(int result) {
898                         int error = SatelliteServiceUtils.fromSatelliteError(result);
899                         logd("requestSatelliteModemState: " + error);
900                         Binder.withCleanCallingIdentity(() ->
901                                 sendMessageWithResult(message, null, error));
902                     }
903                 }, new IIntegerConsumer.Stub() {
904                     @Override
905                     public void accept(int result) {
906                         // Convert SatelliteModemState from service to frameworks definition.
907                         int modemState = SatelliteServiceUtils.fromSatelliteModemState(result);
908                         logd("requestSatelliteModemState: " + modemState);
909                         Binder.withCleanCallingIdentity(() -> sendMessageWithResult(
910                                 message, modemState, SatelliteManager.SATELLITE_ERROR_NONE));
911                     }
912                 });
913             } catch (RemoteException e) {
914                 loge("requestSatelliteModemState: RemoteException " + e);
915                 sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR);
916             }
917         } else {
918             loge("requestSatelliteModemState: Satellite service is unavailable.");
919             sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE);
920         }
921     }
922 
923     /**
924      * Request to get whether satellite communication is allowed for the current location.
925      *
926      * @param message The Message to send to result of the operation to.
927      */
requestIsSatelliteCommunicationAllowedForCurrentLocation(@onNull Message message)928     public void requestIsSatelliteCommunicationAllowedForCurrentLocation(@NonNull Message message) {
929         if (mSatelliteService != null) {
930             try {
931                 mSatelliteService.requestIsSatelliteCommunicationAllowedForCurrentLocation(
932                         new IIntegerConsumer.Stub() {
933                             @Override
934                             public void accept(int result) {
935                                 int error = SatelliteServiceUtils.fromSatelliteError(result);
936                                 logd("requestIsSatelliteCommunicationAllowedForCurrentLocation: "
937                                         + error);
938                                 Binder.withCleanCallingIdentity(() ->
939                                         sendMessageWithResult(message, null, error));
940                             }
941                         }, new IBooleanConsumer.Stub() {
942                             @Override
943                             public void accept(boolean result) {
944                                 logd("requestIsSatelliteCommunicationAllowedForCurrentLocation: "
945                                         + result);
946                                 Binder.withCleanCallingIdentity(() -> sendMessageWithResult(
947                                         message, result, SatelliteManager.SATELLITE_ERROR_NONE));
948                             }
949                         });
950             } catch (RemoteException e) {
951                 loge("requestIsSatelliteCommunicationAllowedForCurrentLocation: RemoteException "
952                         + e);
953                 sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR);
954             }
955         } else {
956             loge("requestIsSatelliteCommunicationAllowedForCurrentLocation: "
957                     + "Satellite service is unavailable.");
958             sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE);
959         }
960     }
961 
962     /**
963      * Request to get the time after which the satellite will be visible. This is an int
964      * representing the duration in seconds after which the satellite will be visible.
965      * This will return 0 if the satellite is currently visible.
966      *
967      * @param message The Message to send to result of the operation to.
968      */
requestTimeForNextSatelliteVisibility(@onNull Message message)969     public void requestTimeForNextSatelliteVisibility(@NonNull Message message) {
970         if (mSatelliteService != null) {
971             try {
972                 mSatelliteService.requestTimeForNextSatelliteVisibility(
973                         new IIntegerConsumer.Stub() {
974                             @Override
975                             public void accept(int result) {
976                                 int error = SatelliteServiceUtils.fromSatelliteError(result);
977                                 logd("requestTimeForNextSatelliteVisibility: " + error);
978                                 Binder.withCleanCallingIdentity(() ->
979                                         sendMessageWithResult(message, null, error));
980                             }
981                         }, new IIntegerConsumer.Stub() {
982                             @Override
983                             public void accept(int result) {
984                                 // Convert for compatibility with SatelliteResponse
985                                 // TODO: This should just report result instead.
986                                 int[] time = new int[] {result};
987                                 logd("requestTimeForNextSatelliteVisibility: "
988                                         + Arrays.toString(time));
989                                 Binder.withCleanCallingIdentity(() -> sendMessageWithResult(
990                                         message, time, SatelliteManager.SATELLITE_ERROR_NONE));
991                             }
992                         });
993             } catch (RemoteException e) {
994                 loge("requestTimeForNextSatelliteVisibility: RemoteException " + e);
995                 sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR);
996             }
997         } else {
998             loge("requestTimeForNextSatelliteVisibility: Satellite service is unavailable.");
999             sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE);
1000         }
1001     }
1002 
isSatelliteServiceSupported()1003     public boolean isSatelliteServiceSupported() {
1004         return mIsSatelliteServiceSupported;
1005     }
1006 
1007     /**
1008      * This API can be used by only CTS to update satellite vendor service package name.
1009      *
1010      * @param servicePackageName The package name of the satellite vendor service.
1011      * @return {@code true} if the satellite vendor service is set successfully,
1012      * {@code false} otherwise.
1013      */
1014     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
setSatelliteServicePackageName(@ullable String servicePackageName)1015     public void setSatelliteServicePackageName(@Nullable String servicePackageName) {
1016         logd("setSatelliteServicePackageName: config_satellite_service_package is "
1017                 + "updated, new packageName=" + servicePackageName);
1018         mExponentialBackoff.stop();
1019         if (mSatelliteServiceConnection != null) {
1020             synchronized (mLock) {
1021                 mIsBound = false;
1022                 mIsBinding = false;
1023             }
1024             unbindService();
1025         }
1026 
1027         if (servicePackageName == null || servicePackageName.equals("null")) {
1028             mVendorSatellitePackageName = "";
1029         } else {
1030             mVendorSatellitePackageName = servicePackageName;
1031         }
1032         mIsSatelliteServiceSupported = getSatelliteServiceSupport();
1033         bindService();
1034         mExponentialBackoff.start();
1035     }
1036 
1037     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
sendMessageWithResult(@onNull Message message, @Nullable Object result, @SatelliteManager.SatelliteError int error)1038     protected static void sendMessageWithResult(@NonNull Message message, @Nullable Object result,
1039             @SatelliteManager.SatelliteError int error) {
1040         SatelliteException exception = error == SatelliteManager.SATELLITE_ERROR_NONE
1041                 ? null : new SatelliteException(error);
1042         AsyncResult.forMessage(message, result, exception);
1043         message.sendToTarget();
1044     }
1045 
logd(@onNull String log)1046     private static void logd(@NonNull String log) {
1047         Rlog.d(TAG, log);
1048     }
1049 
loge(@onNull String log)1050     private static void loge(@NonNull String log) {
1051         Rlog.e(TAG, log);
1052     }
1053 }
1054