• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.telephony.satellite;
18 
19 import static android.telephony.NetworkRegistrationInfo.FIRST_SERVICE_TYPE;
20 import static android.telephony.NetworkRegistrationInfo.LAST_SERVICE_TYPE;
21 
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.content.Context;
25 import android.os.AsyncResult;
26 import android.os.Binder;
27 import android.os.PersistableBundle;
28 import android.telephony.NetworkRegistrationInfo;
29 import android.telephony.Rlog;
30 import android.telephony.SubscriptionManager;
31 import android.telephony.satellite.AntennaPosition;
32 import android.telephony.satellite.PointingInfo;
33 import android.telephony.satellite.SatelliteCapabilities;
34 import android.telephony.satellite.SatelliteDatagram;
35 import android.telephony.satellite.SatelliteManager;
36 import android.telephony.satellite.stub.NTRadioTechnology;
37 import android.telephony.satellite.stub.SatelliteError;
38 import android.telephony.satellite.stub.SatelliteModemState;
39 
40 import com.android.internal.telephony.CommandException;
41 import com.android.internal.telephony.Phone;
42 import com.android.internal.telephony.PhoneFactory;
43 import com.android.internal.telephony.RILUtils;
44 import com.android.internal.telephony.subscription.SubscriptionManagerService;
45 
46 import java.util.Arrays;
47 import java.util.HashMap;
48 import java.util.HashSet;
49 import java.util.Map;
50 import java.util.Set;
51 import java.util.stream.Collectors;
52 
53 /**
54  * Utils class for satellite service <-> framework conversions
55  */
56 public class SatelliteServiceUtils {
57     private static final String TAG = "SatelliteServiceUtils";
58 
59     /**
60      * Convert radio technology from service definition to framework definition.
61      * @param radioTechnology The NTRadioTechnology from the satellite service.
62      * @return The converted NTRadioTechnology for the framework.
63      */
64     @SatelliteManager.NTRadioTechnology
fromSatelliteRadioTechnology(int radioTechnology)65     public static int fromSatelliteRadioTechnology(int radioTechnology) {
66         switch (radioTechnology) {
67             case NTRadioTechnology.NB_IOT_NTN:
68                 return SatelliteManager.NT_RADIO_TECHNOLOGY_NB_IOT_NTN;
69             case NTRadioTechnology.NR_NTN:
70                 return SatelliteManager.NT_RADIO_TECHNOLOGY_NR_NTN;
71             case NTRadioTechnology.EMTC_NTN:
72                 return SatelliteManager.NT_RADIO_TECHNOLOGY_EMTC_NTN;
73             case NTRadioTechnology.PROPRIETARY:
74                 return SatelliteManager.NT_RADIO_TECHNOLOGY_PROPRIETARY;
75             default:
76                 loge("Received invalid radio technology: " + radioTechnology);
77                 return SatelliteManager.NT_RADIO_TECHNOLOGY_UNKNOWN;
78         }
79     }
80 
81     /**
82      * Convert satellite error from service definition to framework definition.
83      * @param error The SatelliteError from the satellite service.
84      * @return The converted SatelliteError for the framework.
85      */
fromSatelliteError(int error)86     @SatelliteManager.SatelliteError public static int fromSatelliteError(int error) {
87         switch (error) {
88             case SatelliteError.ERROR_NONE:
89                 return SatelliteManager.SATELLITE_ERROR_NONE;
90             case SatelliteError.SATELLITE_ERROR:
91                 return SatelliteManager.SATELLITE_ERROR;
92             case SatelliteError.SERVER_ERROR:
93                 return SatelliteManager.SATELLITE_SERVER_ERROR;
94             case SatelliteError.SERVICE_ERROR:
95                 return SatelliteManager.SATELLITE_SERVICE_ERROR;
96             case SatelliteError.MODEM_ERROR:
97                 return SatelliteManager.SATELLITE_MODEM_ERROR;
98             case SatelliteError.NETWORK_ERROR:
99                 return SatelliteManager.SATELLITE_NETWORK_ERROR;
100             case SatelliteError.INVALID_TELEPHONY_STATE:
101                 return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE;
102             case SatelliteError.INVALID_MODEM_STATE:
103                 return SatelliteManager.SATELLITE_INVALID_MODEM_STATE;
104             case SatelliteError.INVALID_ARGUMENTS:
105                 return SatelliteManager.SATELLITE_INVALID_ARGUMENTS;
106             case SatelliteError.REQUEST_FAILED:
107                 return SatelliteManager.SATELLITE_REQUEST_FAILED;
108             case SatelliteError.RADIO_NOT_AVAILABLE:
109                 return SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE;
110             case SatelliteError.REQUEST_NOT_SUPPORTED:
111                 return SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED;
112             case SatelliteError.NO_RESOURCES:
113                 return SatelliteManager.SATELLITE_NO_RESOURCES;
114             case SatelliteError.SERVICE_NOT_PROVISIONED:
115                 return SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED;
116             case SatelliteError.SERVICE_PROVISION_IN_PROGRESS:
117                 return SatelliteManager.SATELLITE_SERVICE_PROVISION_IN_PROGRESS;
118             case SatelliteError.REQUEST_ABORTED:
119                 return SatelliteManager.SATELLITE_REQUEST_ABORTED;
120             case SatelliteError.SATELLITE_ACCESS_BARRED:
121                 return SatelliteManager.SATELLITE_ACCESS_BARRED;
122             case SatelliteError.NETWORK_TIMEOUT:
123                 return SatelliteManager.SATELLITE_NETWORK_TIMEOUT;
124             case SatelliteError.SATELLITE_NOT_REACHABLE:
125                 return SatelliteManager.SATELLITE_NOT_REACHABLE;
126             case SatelliteError.NOT_AUTHORIZED:
127                 return SatelliteManager.SATELLITE_NOT_AUTHORIZED;
128         }
129         loge("Received invalid satellite service error: " + error);
130         return SatelliteManager.SATELLITE_SERVICE_ERROR;
131     }
132 
133     /**
134      * Convert satellite modem state from service definition to framework definition.
135      * @param modemState The SatelliteModemState from the satellite service.
136      * @return The converted SatelliteModemState for the framework.
137      */
138     @SatelliteManager.SatelliteModemState
fromSatelliteModemState(int modemState)139     public static int fromSatelliteModemState(int modemState) {
140         switch (modemState) {
141             case SatelliteModemState.SATELLITE_MODEM_STATE_IDLE:
142                 return SatelliteManager.SATELLITE_MODEM_STATE_IDLE;
143             case SatelliteModemState.SATELLITE_MODEM_STATE_LISTENING:
144                 return SatelliteManager.SATELLITE_MODEM_STATE_LISTENING;
145             case SatelliteModemState.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING:
146                 return SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING;
147             case SatelliteModemState.SATELLITE_MODEM_STATE_DATAGRAM_RETRYING:
148                 return SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_RETRYING;
149             case SatelliteModemState.SATELLITE_MODEM_STATE_OFF:
150                 return SatelliteManager.SATELLITE_MODEM_STATE_OFF;
151             case SatelliteModemState.SATELLITE_MODEM_STATE_UNAVAILABLE:
152                 return SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE;
153             default:
154                 loge("Received invalid modem state: " + modemState);
155                 return SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN;
156         }
157     }
158 
159     /**
160      * Convert SatelliteCapabilities from service definition to framework definition.
161      * @param capabilities The SatelliteCapabilities from the satellite service.
162      * @return The converted SatelliteCapabilities for the framework.
163      */
fromSatelliteCapabilities( @ullable android.telephony.satellite.stub.SatelliteCapabilities capabilities)164     @Nullable public static SatelliteCapabilities fromSatelliteCapabilities(
165             @Nullable android.telephony.satellite.stub.SatelliteCapabilities capabilities) {
166         if (capabilities == null) return null;
167         int[] radioTechnologies = capabilities.supportedRadioTechnologies == null
168                 ? new int[0] : capabilities.supportedRadioTechnologies;
169 
170         Map<Integer, AntennaPosition> antennaPositionMap = new HashMap<>();
171         int[] antennaPositionKeys = capabilities.antennaPositionKeys;
172         AntennaPosition[] antennaPositionValues = capabilities.antennaPositionValues;
173         if (antennaPositionKeys != null && antennaPositionValues != null &&
174                 antennaPositionKeys.length == antennaPositionValues.length) {
175             for(int i = 0; i < antennaPositionKeys.length; i++) {
176                 antennaPositionMap.put(antennaPositionKeys[i], antennaPositionValues[i]);
177             }
178         }
179 
180         return new SatelliteCapabilities(
181                 Arrays.stream(radioTechnologies)
182                         .map(SatelliteServiceUtils::fromSatelliteRadioTechnology)
183                         .boxed().collect(Collectors.toSet()),
184                 capabilities.isPointingRequired, capabilities.maxBytesPerOutgoingDatagram,
185                 antennaPositionMap);
186     }
187 
188     /**
189      * Convert PointingInfo from service definition to framework definition.
190      * @param pointingInfo The PointingInfo from the satellite service.
191      * @return The converted PointingInfo for the framework.
192      */
fromPointingInfo( android.telephony.satellite.stub.PointingInfo pointingInfo)193     @Nullable public static PointingInfo fromPointingInfo(
194             android.telephony.satellite.stub.PointingInfo pointingInfo) {
195         if (pointingInfo == null) return null;
196         return new PointingInfo(pointingInfo.satelliteAzimuth, pointingInfo.satelliteElevation);
197     }
198 
199     /**
200      * Convert SatelliteDatagram from service definition to framework definition.
201      * @param datagram The SatelliteDatagram from the satellite service.
202      * @return The converted SatelliteDatagram for the framework.
203      */
fromSatelliteDatagram( android.telephony.satellite.stub.SatelliteDatagram datagram)204     @Nullable public static SatelliteDatagram fromSatelliteDatagram(
205             android.telephony.satellite.stub.SatelliteDatagram datagram) {
206         if (datagram == null) return null;
207         byte[] data = datagram.data == null ? new byte[0] : datagram.data;
208         return new SatelliteDatagram(data);
209     }
210 
211     /**
212      * Convert SatelliteDatagram from framework definition to service definition.
213      * @param datagram The SatelliteDatagram from the framework.
214      * @return The converted SatelliteDatagram for the satellite service.
215      */
toSatelliteDatagram( @ullable SatelliteDatagram datagram)216     @Nullable public static android.telephony.satellite.stub.SatelliteDatagram toSatelliteDatagram(
217             @Nullable SatelliteDatagram datagram) {
218         android.telephony.satellite.stub.SatelliteDatagram converted =
219                 new android.telephony.satellite.stub.SatelliteDatagram();
220         converted.data = datagram.getSatelliteDatagram();
221         return converted;
222     }
223 
224     /**
225      * Get the {@link SatelliteManager.SatelliteError} from the provided result.
226      *
227      * @param ar AsyncResult used to determine the error code.
228      * @param caller The satellite request.
229      *
230      * @return The {@link SatelliteManager.SatelliteError} error code from the request.
231      */
getSatelliteError(@onNull AsyncResult ar, @NonNull String caller)232     @SatelliteManager.SatelliteError public static int getSatelliteError(@NonNull AsyncResult ar,
233             @NonNull String caller) {
234         int errorCode;
235         if (ar.exception == null) {
236             errorCode = SatelliteManager.SATELLITE_ERROR_NONE;
237         } else {
238             errorCode = SatelliteManager.SATELLITE_ERROR;
239             if (ar.exception instanceof CommandException) {
240                 CommandException.Error error = ((CommandException) ar.exception).getCommandError();
241                 errorCode = RILUtils.convertToSatelliteError(error);
242                 loge(caller + " CommandException: " + ar.exception);
243             } else if (ar.exception instanceof SatelliteManager.SatelliteException) {
244                 errorCode = ((SatelliteManager.SatelliteException) ar.exception).getErrorCode();
245                 loge(caller + " SatelliteException: " + ar.exception);
246             } else {
247                 loge(caller + " unknown exception: " + ar.exception);
248             }
249         }
250         logd(caller + " error: " + errorCode);
251         return errorCode;
252     }
253 
254     /**
255      * Get valid subscription id for satellite communication.
256      *
257      * @param subId The subscription id.
258      * @return input subId if the subscription is active else return default subscription id.
259      */
getValidSatelliteSubId(int subId, @NonNull Context context)260     public static int getValidSatelliteSubId(int subId, @NonNull Context context) {
261         final long identity = Binder.clearCallingIdentity();
262         try {
263             boolean isActive = SubscriptionManagerService.getInstance().isActiveSubId(subId,
264                     context.getOpPackageName(), context.getAttributionTag());
265 
266             if (isActive) {
267                 return subId;
268             }
269         } finally {
270             Binder.restoreCallingIdentity(identity);
271         }
272         logd("getValidSatelliteSubId: use DEFAULT_SUBSCRIPTION_ID for subId=" + subId);
273         return SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
274     }
275 
276     /**
277      * Expected format of each input string in the array: "PLMN_1:service_1,service_2,..."
278      *
279      * @return The map of supported services with key: PLMN, value: set of services supported by
280      * the PLMN.
281      */
282     @NonNull
283     @NetworkRegistrationInfo.ServiceType
parseSupportedSatelliteServices( String[] supportedSatelliteServicesStrArray)284     public static Map<String, Set<Integer>> parseSupportedSatelliteServices(
285             String[] supportedSatelliteServicesStrArray) {
286         Map<String, Set<Integer>> supportedServicesMap = new HashMap<>();
287         if (supportedSatelliteServicesStrArray == null
288                 || supportedSatelliteServicesStrArray.length == 0) {
289             return supportedServicesMap;
290         }
291 
292         for (String supportedServicesPerPlmnStr : supportedSatelliteServicesStrArray) {
293             String[] pairOfPlmnAndsupportedServicesStr =
294                     supportedServicesPerPlmnStr.split(":");
295             if (pairOfPlmnAndsupportedServicesStr != null
296                     && (pairOfPlmnAndsupportedServicesStr.length == 1
297                     || pairOfPlmnAndsupportedServicesStr.length == 2)) {
298                 String plmn = pairOfPlmnAndsupportedServicesStr[0];
299                 Set<Integer> supportedServicesSet = new HashSet<>();
300                 if (pairOfPlmnAndsupportedServicesStr.length == 2) {
301                     String[] supportedServicesStrArray =
302                             pairOfPlmnAndsupportedServicesStr[1].split(",");
303                     for (String service : supportedServicesStrArray) {
304                         try {
305                             int serviceType = Integer.parseInt(service);
306                             if (isServiceTypeValid(serviceType)) {
307                                 supportedServicesSet.add(serviceType);
308                             } else {
309                                 loge("parseSupportedSatelliteServices: invalid serviceType="
310                                         + serviceType);
311                             }
312                         } catch (NumberFormatException e) {
313                             loge("parseSupportedSatelliteServices: supportedServicesPerPlmnStr="
314                                     + supportedServicesPerPlmnStr + ", service=" + service
315                                     + ", e=" + e);
316                         }
317                     }
318                 }
319                 supportedServicesMap.put(plmn, supportedServicesSet);
320             } else {
321                 loge("parseSupportedSatelliteServices: invalid format input, "
322                         + "supportedServicesPerPlmnStr=" + supportedServicesPerPlmnStr);
323             }
324         }
325         return supportedServicesMap;
326     }
327 
328     /**
329      * Expected format of the input dictionary bundle is:
330      * <ul>
331      *     <li>Key: PLMN string.</li>
332      *     <li>Value: A string with format "service_1,service_2,..."</li>
333      * </ul>
334      * @return The map of supported services with key: PLMN, value: set of services supported by
335      * the PLMN.
336      */
337     @NonNull
338     @NetworkRegistrationInfo.ServiceType
parseSupportedSatelliteServices( PersistableBundle supportedServicesBundle)339     public static Map<String, Set<Integer>> parseSupportedSatelliteServices(
340             PersistableBundle supportedServicesBundle) {
341         Map<String, Set<Integer>> supportedServicesMap = new HashMap<>();
342         if (supportedServicesBundle == null || supportedServicesBundle.isEmpty()) {
343             return supportedServicesMap;
344         }
345 
346         for (String plmn : supportedServicesBundle.keySet()) {
347             Set<Integer> supportedServicesSet = new HashSet<>();
348             for (int serviceType : supportedServicesBundle.getIntArray(plmn)) {
349                 if (isServiceTypeValid(serviceType)) {
350                     supportedServicesSet.add(serviceType);
351                 } else {
352                     loge("parseSupportedSatelliteServices: invalid service type=" + serviceType
353                             + " for plmn=" + plmn);
354                 }
355             }
356             supportedServicesMap.put(plmn, supportedServicesSet);
357         }
358         return supportedServicesMap;
359     }
360 
361     /**
362      * For the PLMN that exists in both {@code providerSupportedServices} and
363      * {@code carrierSupportedServices}, the supported services will be the intersection of the two
364      * sets. For the PLMN that is present in {@code providerSupportedServices} but not in
365      * {@code carrierSupportedServices}, the provider supported services will be used. The rest
366      * will not be used.
367      *
368      * @param providerSupportedServices Satellite provider supported satellite services.
369      * @param carrierSupportedServices Carrier supported satellite services.
370      * @return The supported satellite services by the device for the corresponding carrier and the
371      * satellite provider.
372      */
373     @NonNull
374     @NetworkRegistrationInfo.ServiceType
mergeSupportedSatelliteServices( @onNull @etworkRegistrationInfo.ServiceType Map<String, Set<Integer>> providerSupportedServices, @NonNull @NetworkRegistrationInfo.ServiceType Map<String, Set<Integer>> carrierSupportedServices)375     public static Map<String, Set<Integer>> mergeSupportedSatelliteServices(
376             @NonNull @NetworkRegistrationInfo.ServiceType Map<String, Set<Integer>>
377                     providerSupportedServices,
378             @NonNull @NetworkRegistrationInfo.ServiceType Map<String, Set<Integer>>
379                     carrierSupportedServices) {
380         Map<String, Set<Integer>> supportedServicesMap = new HashMap<>();
381         for (Map.Entry<String, Set<Integer>> entry : providerSupportedServices.entrySet()) {
382             Set<Integer> supportedServices = new HashSet<>(entry.getValue());
383             if (carrierSupportedServices.containsKey(entry.getKey())) {
384                 supportedServices.retainAll(carrierSupportedServices.get(entry.getKey()));
385             }
386             if (!supportedServices.isEmpty()) {
387                 supportedServicesMap.put(entry.getKey(), supportedServices);
388             }
389         }
390         return supportedServicesMap;
391     }
392 
isServiceTypeValid(int serviceType)393     private static boolean isServiceTypeValid(int serviceType) {
394         return (serviceType >= FIRST_SERVICE_TYPE && serviceType <= LAST_SERVICE_TYPE);
395     }
396 
397     /**
398      * Return phone associated with phoneId 0.
399      *
400      * @return phone associated with phoneId 0 or {@code null} if it doesn't exist.
401      */
getPhone()402     public static @Nullable Phone getPhone() {
403         return PhoneFactory.getPhone(0);
404     }
405 
logd(@onNull String log)406     private static void logd(@NonNull String log) {
407         Rlog.d(TAG, log);
408     }
409 
loge(@onNull String log)410     private static void loge(@NonNull String log) {
411         Rlog.e(TAG, log);
412     }
413 }
414