• 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.google.android.telephony.satellite;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.content.Intent;
22 import android.os.Binder;
23 import android.os.IBinder;
24 import android.telephony.satellite.stub.ISatelliteCapabilitiesConsumer;
25 import android.telephony.satellite.stub.ISatelliteListener;
26 import android.telephony.satellite.stub.NTRadioTechnology;
27 import android.telephony.satellite.stub.PointingInfo;
28 import android.telephony.satellite.stub.SatelliteCapabilities;
29 import android.telephony.satellite.stub.SatelliteDatagram;
30 import android.telephony.satellite.stub.SatelliteError;
31 import android.telephony.satellite.stub.SatelliteImplBase;
32 import android.telephony.satellite.stub.SatelliteModemState;
33 import android.telephony.satellite.stub.SatelliteService;
34 
35 import com.android.internal.telephony.IBooleanConsumer;
36 import com.android.internal.telephony.IIntegerConsumer;
37 import com.android.internal.util.FunctionalUtils;
38 import com.android.telephony.Rlog;
39 
40 import java.util.ArrayList;
41 import java.util.HashMap;
42 import java.util.HashSet;
43 import java.util.List;
44 import java.util.Map;
45 import java.util.Set;
46 import java.util.concurrent.Executor;
47 
48 public class CFSatelliteService extends SatelliteImplBase {
49     private static final String TAG = "CFSatelliteService";
50 
51     // Hardcoded values below
52     private static final int SATELLITE_ALWAYS_VISIBLE = 0;
53     /** SatelliteCapabilities constant indicating that the radio technology is proprietary. */
54     private static final int[] SUPPORTED_RADIO_TECHNOLOGIES =
55             new int[] {NTRadioTechnology.PROPRIETARY};
56     /** SatelliteCapabilities constant indicating that pointing to satellite is required. */
57     private static final boolean POINTING_TO_SATELLITE_REQUIRED = true;
58     /** SatelliteCapabilities constant indicating the maximum number of characters per datagram. */
59     private static final int MAX_BYTES_PER_DATAGRAM = 339;
60 
61     @NonNull private final Map<IBinder, ISatelliteListener> mListeners = new HashMap<>();
62 
63     private boolean mIsCommunicationAllowedInLocation;
64     private boolean mIsEnabled;
65     private boolean mIsProvisioned;
66     private boolean mIsSupported;
67     private int mModemState;
68 
69     /**
70      * Create CFSatelliteService using the Executor specified for methods being called from
71      * the framework.
72      *
73      * @param executor The executor for the framework to use when executing satellite methods.
74      */
CFSatelliteService(@onNull Executor executor)75     public CFSatelliteService(@NonNull Executor executor) {
76         super(executor);
77         mIsCommunicationAllowedInLocation = true;
78         mIsEnabled = false;
79         mIsProvisioned = false;
80         mIsSupported = true;
81         mModemState = SatelliteModemState.SATELLITE_MODEM_STATE_OFF;
82     }
83 
84     /**
85      * Zero-argument constructor to prevent service binding exception.
86      */
CFSatelliteService()87     public CFSatelliteService() {
88         this(Runnable::run);
89     }
90 
91     @Override
onBind(Intent intent)92     public IBinder onBind(Intent intent) {
93         if (SatelliteService.SERVICE_INTERFACE.equals(intent.getAction())) {
94             logd("CFSatelliteService bound");
95             return new CFSatelliteService().getBinder();
96         }
97         return null;
98     }
99 
100     @Override
onCreate()101     public void onCreate() {
102         super.onCreate();
103         logd("onCreate");
104     }
105 
106     @Override
onDestroy()107     public void onDestroy() {
108         super.onDestroy();
109         logd("onDestroy");
110     }
111 
112     @Override
setSatelliteListener(@onNull ISatelliteListener listener)113     public void setSatelliteListener(@NonNull ISatelliteListener listener) {
114         logd("setSatelliteListener");
115         mListeners.put(listener.asBinder(), listener);
116     }
117 
118     @Override
requestSatelliteListeningEnabled(boolean enable, int timeout, @NonNull IIntegerConsumer errorCallback)119     public void requestSatelliteListeningEnabled(boolean enable, int timeout,
120             @NonNull IIntegerConsumer errorCallback) {
121         logd("requestSatelliteListeningEnabled");
122         if (!verifySatelliteModemState(errorCallback)) {
123             return;
124         }
125         if (enable) {
126             updateSatelliteModemState(SatelliteModemState.SATELLITE_MODEM_STATE_LISTENING);
127         } else {
128             updateSatelliteModemState(SatelliteModemState.SATELLITE_MODEM_STATE_IDLE);
129         }
130         runWithExecutor(() -> errorCallback.accept(SatelliteError.ERROR_NONE));
131     }
132 
133     @Override
requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode, @NonNull IIntegerConsumer errorCallback)134     public void requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode,
135             @NonNull IIntegerConsumer errorCallback) {
136         logd("requestSatelliteEnabled");
137         if (enableSatellite) {
138             enableSatellite(errorCallback);
139         } else {
140             disableSatellite(errorCallback);
141         }
142     }
143 
enableSatellite(@onNull IIntegerConsumer errorCallback)144     private void enableSatellite(@NonNull IIntegerConsumer errorCallback) {
145         mIsEnabled = true;
146         updateSatelliteModemState(SatelliteModemState.SATELLITE_MODEM_STATE_IDLE);
147         runWithExecutor(() -> errorCallback.accept(SatelliteError.ERROR_NONE));
148     }
149 
disableSatellite(@onNull IIntegerConsumer errorCallback)150     private void disableSatellite(@NonNull IIntegerConsumer errorCallback) {
151         mIsEnabled = false;
152         updateSatelliteModemState(SatelliteModemState.SATELLITE_MODEM_STATE_OFF);
153         runWithExecutor(() -> errorCallback.accept(SatelliteError.ERROR_NONE));
154     }
155 
156     @Override
requestIsSatelliteEnabled(@onNull IIntegerConsumer errorCallback, @NonNull IBooleanConsumer callback)157     public void requestIsSatelliteEnabled(@NonNull IIntegerConsumer errorCallback,
158             @NonNull IBooleanConsumer callback) {
159         logd("requestIsSatelliteEnabled");
160         runWithExecutor(() -> callback.accept(mIsEnabled));
161     }
162 
163     @Override
requestIsSatelliteSupported(@onNull IIntegerConsumer errorCallback, @NonNull IBooleanConsumer callback)164     public void requestIsSatelliteSupported(@NonNull IIntegerConsumer errorCallback,
165             @NonNull IBooleanConsumer callback) {
166         logd("requestIsSatelliteSupported");
167         runWithExecutor(() -> callback.accept(mIsSupported));
168     }
169 
170     @Override
requestSatelliteCapabilities(@onNull IIntegerConsumer errorCallback, @NonNull ISatelliteCapabilitiesConsumer callback)171     public void requestSatelliteCapabilities(@NonNull IIntegerConsumer errorCallback,
172             @NonNull ISatelliteCapabilitiesConsumer callback) {
173         logd("requestSatelliteCapabilities");
174         SatelliteCapabilities capabilities = new SatelliteCapabilities();
175         capabilities.supportedRadioTechnologies = SUPPORTED_RADIO_TECHNOLOGIES;
176         capabilities.isPointingRequired = POINTING_TO_SATELLITE_REQUIRED;
177         capabilities.maxBytesPerOutgoingDatagram = MAX_BYTES_PER_DATAGRAM;
178         runWithExecutor(() -> callback.accept(capabilities));
179     }
180 
181     @Override
startSendingSatellitePointingInfo(@onNull IIntegerConsumer errorCallback)182     public void startSendingSatellitePointingInfo(@NonNull IIntegerConsumer errorCallback) {
183         logd("startSendingSatellitePointingInfo");
184         if (!verifySatelliteModemState(errorCallback)) {
185             return;
186         }
187         runWithExecutor(() -> errorCallback.accept(SatelliteError.ERROR_NONE));
188     }
189 
190     @Override
stopSendingSatellitePointingInfo(@onNull IIntegerConsumer errorCallback)191     public void stopSendingSatellitePointingInfo(@NonNull IIntegerConsumer errorCallback) {
192         logd("stopSendingSatellitePointingInfo");
193         runWithExecutor(() -> errorCallback.accept(SatelliteError.ERROR_NONE));
194     }
195 
196     @Override
provisionSatelliteService(@onNull String token, @NonNull byte[] provisionData, @NonNull IIntegerConsumer errorCallback)197     public void provisionSatelliteService(@NonNull String token, @NonNull byte[] provisionData,
198             @NonNull IIntegerConsumer errorCallback) {
199         logd("provisionSatelliteService");
200         runWithExecutor(() -> errorCallback.accept(SatelliteError.ERROR_NONE));
201         updateSatelliteProvisionState(true);
202     }
203 
204     @Override
deprovisionSatelliteService(@onNull String token, @NonNull IIntegerConsumer errorCallback)205     public void deprovisionSatelliteService(@NonNull String token,
206             @NonNull IIntegerConsumer errorCallback) {
207         logd("deprovisionSatelliteService");
208         runWithExecutor(() -> errorCallback.accept(SatelliteError.ERROR_NONE));
209         updateSatelliteProvisionState(false);
210     }
211 
212     @Override
requestIsSatelliteProvisioned(@onNull IIntegerConsumer errorCallback, @NonNull IBooleanConsumer callback)213     public void requestIsSatelliteProvisioned(@NonNull IIntegerConsumer errorCallback,
214             @NonNull IBooleanConsumer callback) {
215         logd("requestIsSatelliteProvisioned");
216         runWithExecutor(() -> callback.accept(mIsProvisioned));
217     }
218 
219     @Override
pollPendingSatelliteDatagrams(@onNull IIntegerConsumer errorCallback)220     public void pollPendingSatelliteDatagrams(@NonNull IIntegerConsumer errorCallback) {
221         logd("pollPendingSatelliteDatagrams");
222         runWithExecutor(() -> errorCallback.accept(SatelliteError.ERROR_NONE));
223     }
224 
225     @Override
sendSatelliteDatagram(@onNull SatelliteDatagram datagram, boolean isEmergency, @NonNull IIntegerConsumer errorCallback)226     public void sendSatelliteDatagram(@NonNull SatelliteDatagram datagram, boolean isEmergency,
227             @NonNull IIntegerConsumer errorCallback) {
228         logd("sendSatelliteDatagram");
229         runWithExecutor(() -> errorCallback.accept(SatelliteError.ERROR_NONE));
230     }
231 
232     @Override
requestSatelliteModemState(@onNull IIntegerConsumer errorCallback, @NonNull IIntegerConsumer callback)233     public void requestSatelliteModemState(@NonNull IIntegerConsumer errorCallback,
234             @NonNull IIntegerConsumer callback) {
235         logd("requestSatelliteModemState");
236         runWithExecutor(() -> callback.accept(mModemState));
237     }
238 
239     @Override
requestIsSatelliteCommunicationAllowedForCurrentLocation( @onNull IIntegerConsumer errorCallback, @NonNull IBooleanConsumer callback)240     public void requestIsSatelliteCommunicationAllowedForCurrentLocation(
241             @NonNull IIntegerConsumer errorCallback, @NonNull IBooleanConsumer callback) {
242         logd("requestIsSatelliteCommunicationAllowedForCurrentLocation");
243         if (mIsCommunicationAllowedInLocation) {
244             runWithExecutor(() -> callback.accept(true));
245         } else {
246             runWithExecutor(() -> callback.accept(false));
247         }
248     }
249 
250     @Override
requestTimeForNextSatelliteVisibility(@onNull IIntegerConsumer errorCallback, @NonNull IIntegerConsumer callback)251     public void requestTimeForNextSatelliteVisibility(@NonNull IIntegerConsumer errorCallback,
252             @NonNull IIntegerConsumer callback) {
253         logd("requestTimeForNextSatelliteVisibility");
254         runWithExecutor(() -> callback.accept(SATELLITE_ALWAYS_VISIBLE));
255     }
256 
257     /**
258      * Helper method to verify that the satellite modem is properly configured to receive requests.
259      *
260      * @param errorCallback The callback to notify of any errors preventing satellite requests.
261      * @return {@code true} if the satellite modem is configured to receive requests and
262      *         {@code false} if it is not.
263      */
verifySatelliteModemState(@onNull IIntegerConsumer errorCallback)264     private boolean verifySatelliteModemState(@NonNull IIntegerConsumer errorCallback) {
265         if (!mIsSupported) {
266             runWithExecutor(() -> errorCallback.accept(SatelliteError.REQUEST_NOT_SUPPORTED));
267             return false;
268         }
269         if (!mIsProvisioned) {
270             runWithExecutor(() -> errorCallback.accept(SatelliteError.SERVICE_NOT_PROVISIONED));
271             return false;
272         }
273         if (!mIsEnabled) {
274             runWithExecutor(() -> errorCallback.accept(SatelliteError.INVALID_MODEM_STATE));
275             return false;
276         }
277         return true;
278     }
279 
280     /**
281      * Update the satellite modem state and notify listeners if it changed.
282      *
283      * @param modemState The {@link SatelliteModemState} to update.
284      */
updateSatelliteModemState(int modemState)285     private void updateSatelliteModemState(int modemState) {
286         if (modemState == mModemState) {
287             return;
288         }
289         logd("updateSatelliteModemState: mListeners.size=" + mListeners.size());
290         mListeners.values().forEach(listener -> runWithExecutor(() ->
291                 listener.onSatelliteModemStateChanged(modemState)));
292         mModemState = modemState;
293     }
294 
295     /**
296      * Update the satellite provision state and notify listeners if it changed.
297      *
298      * @param isProvisioned {@code true} if the satellite is currently provisioned and
299      *                      {@code false} if it is not.
300      */
updateSatelliteProvisionState(boolean isProvisioned)301     private void updateSatelliteProvisionState(boolean isProvisioned) {
302         if (isProvisioned == mIsProvisioned) {
303             return;
304         }
305         logd("updateSatelliteProvisionState: mListeners.size=" + mListeners.size());
306         mIsProvisioned = isProvisioned;
307         mListeners.values().forEach(listener -> runWithExecutor(() ->
308                 listener.onSatelliteProvisionStateChanged(mIsProvisioned)));
309     }
310 
311     /**
312      * Execute the given runnable using the executor that this service was created with.
313      *
314      * @param r A runnable that can throw an exception.
315      */
runWithExecutor(@onNull FunctionalUtils.ThrowingRunnable r)316     private void runWithExecutor(@NonNull FunctionalUtils.ThrowingRunnable r) {
317         mExecutor.execute(() -> Binder.withCleanCallingIdentity(r));
318     }
319 
320     /**
321      * Log the message to the radio buffer with {@code DEBUG} priority.
322      *
323      * @param log The message to log.
324      */
logd(@onNull String log)325     private static void logd(@NonNull String log) {
326         Rlog.d(TAG, log);
327     }
328 }
329