Loading src/java/com/android/internal/telephony/ServiceStateTracker.java +13 −0 Original line number Diff line number Diff line Loading @@ -97,6 +97,7 @@ import com.android.internal.telephony.data.DataNetworkController.DataNetworkCont import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.metrics.ServiceStateStats; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.satellite.NtnCapabilityResolver; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState; Loading Loading @@ -3425,6 +3426,7 @@ public class ServiceStateTracker extends Handler { updateNrFrequencyRangeFromPhysicalChannelConfigs(mLastPhysicalChannelConfigList, mNewSS); updateNrStateFromPhysicalChannelConfigs(mLastPhysicalChannelConfigList, mNewSS); updateNtnCapability(); if (TelephonyUtils.IS_DEBUGGABLE && mPhone.getTelephonyTester() != null) { mPhone.getTelephonyTester().overrideServiceState(mNewSS); Loading Loading @@ -5554,6 +5556,17 @@ public class ServiceStateTracker extends Handler { } } private void updateNtnCapability() { for (NetworkRegistrationInfo nri : mNewSS.getNetworkRegistrationInfoListForTransportType( AccessNetworkConstants.TRANSPORT_TYPE_WWAN)) { NtnCapabilityResolver.resolveNtnCapability(nri, mSubId); if (nri.isNonTerrestrialNetwork()) { // Replace the existing NRI with the updated NRI. mNewSS.addNetworkRegistrationInfo(nri); } } } /** * Check if device is non-roaming and always on home network. * Loading src/java/com/android/internal/telephony/satellite/NtnCapabilityResolver.java 0 → 100644 +59 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.telephony.satellite; import android.annotation.NonNull; import android.telephony.NetworkRegistrationInfo; import android.telephony.Rlog; import android.text.TextUtils; import java.util.List; /** * This utility class is responsible for resolving NTN capabilities of a * {@link NetworkRegistrationInfo}. */ public class NtnCapabilityResolver { private static final String TAG = "NtnCapabilityResolver"; /** * Resolve NTN capability by updating the input NetworkRegistrationInfo to indicate whether * connecting to a non-terrestrial network and the available services supported by the network. * * @param networkRegistrationInfo The NetworkRegistrationInfo of a network. * @param subId The subscription ID associated with a phone. */ public static void resolveNtnCapability( @NonNull NetworkRegistrationInfo networkRegistrationInfo, int subId) { SatelliteController satelliteController = SatelliteController.getInstance(); List<String> satellitePlmnList = satelliteController.getSatellitePlmnList(); String registeredPlmn = networkRegistrationInfo.getRegisteredPlmn(); for (String satellitePlmn : satellitePlmnList) { if (TextUtils.equals(satellitePlmn, registeredPlmn)) { logd("Registered to satellite PLMN " + satellitePlmn); networkRegistrationInfo.setIsNonTerrestrialNetwork(true); networkRegistrationInfo.setAvailableServices( satelliteController.getSupportedSatelliteServices(subId, satellitePlmn)); break; } } } private static void logd(@NonNull String log) { Rlog.d(TAG, log); } } src/java/com/android/internal/telephony/satellite/SatelliteController.java +162 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.internal.telephony.satellite; import android.annotation.ArrayRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.bluetooth.BluetoothAdapter; Loading @@ -25,6 +26,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.res.Resources; import android.database.ContentObserver; import android.net.wifi.WifiManager; import android.nfc.NfcAdapter; Loading @@ -34,15 +36,18 @@ import android.os.Build; import android.os.Bundle; import android.os.CancellationSignal; import android.os.Handler; import android.os.HandlerExecutor; import android.os.HandlerThread; import android.os.IBinder; import android.os.ICancellationSignal; import android.os.Looper; import android.os.Message; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.SystemProperties; import android.provider.Settings; import android.telephony.CarrierConfigManager; import android.telephony.Rlog; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; Loading @@ -54,8 +59,10 @@ import android.telephony.satellite.SatelliteCapabilities; import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; import android.util.Log; import android.util.SparseArray; import android.uwb.UwbManager; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; Loading @@ -64,10 +71,14 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats; import com.android.internal.telephony.satellite.metrics.ProvisionMetricsStats; import com.android.internal.telephony.satellite.metrics.SessionMetricsStats; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.util.FunctionalUtils; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; Loading Loading @@ -199,6 +210,22 @@ public class SatelliteController extends Handler { private final Object mNeedsSatellitePointingLock = new Object(); @GuardedBy("mNeedsSatellitePointingLock") private boolean mNeedsSatellitePointing = false; /** Key: subId, value: (key: PLMN, value: set of * {@link android.telephony.NetworkRegistrationInfo.ServiceType}) */ @GuardedBy("mSupportedSatelliteServicesLock") @NonNull private final Map<Integer, Map<String, Set<Integer>>> mSupportedSatelliteServices = new HashMap<>(); @NonNull private final Object mSupportedSatelliteServicesLock = new Object(); /** Key: PLMN, value: set of {@link android.telephony.NetworkRegistrationInfo.ServiceType} */ @NonNull private final Map<String, Set<Integer>> mSatelliteServicesSupportedByProviders; @NonNull private final CarrierConfigManager mCarrierConfigManager; @NonNull private final CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; @NonNull private final Object mCarrierConfigArrayLock = new Object(); @GuardedBy("mCarrierConfigArrayLock") @NonNull private final SparseArray<PersistableBundle> mCarrierConfigArray = new SparseArray<>(); @NonNull private final List<String> mSatellitePlmnList; /** * @return The singleton instance of SatelliteController. Loading Loading @@ -266,6 +293,7 @@ public class SatelliteController extends Handler { registerForPendingDatagramCount(); registerForSatelliteModemStateChanged(); mContentResolver = mContext.getContentResolver(); mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class); try { mSharedPreferences = mContext.getSharedPreferences(SATELLITE_SHARED_PREF, Loading @@ -287,6 +315,16 @@ public class SatelliteController extends Handler { Settings.Global.getUriFor(Settings.Global.SATELLITE_MODE_RADIOS), false, satelliteModeRadiosContentObserver); } mSatelliteServicesSupportedByProviders = readSupportedSatelliteServicesFromOverlayConfig(); mSatellitePlmnList = mSatelliteServicesSupportedByProviders.keySet().stream().toList(); updateSupportedSatelliteServicesForActiveSubscriptions(); mCarrierConfigChangeListener = (slotIndex, subId, carrierId, specificCarrierId) -> handleCarrierConfigChanged(slotIndex, subId, carrierId, specificCarrierId); mCarrierConfigManager.registerCarrierConfigChangeListener( new HandlerExecutor(new Handler(looper)), mCarrierConfigChangeListener); } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) Loading Loading @@ -1901,6 +1939,40 @@ public class SatelliteController extends Handler { return (supported != null ? supported : false); } /** * @return The list of satellite PLMNs used for connecting to satellite networks. */ @NonNull public List<String> getSatellitePlmnList() { return new ArrayList<>(mSatellitePlmnList); } /** * @param subId Subscription ID. * @param plmn The satellite roaming plmn. * @return The list of services supported by the carrier associated with the {@code subId} for * the satellite network {@code plmn}. */ @NonNull public List<Integer> getSupportedSatelliteServices(int subId, String plmn) { synchronized (mSupportedSatelliteServicesLock) { if (mSupportedSatelliteServices.containsKey(subId)) { Map<String, Set<Integer>> supportedServices = mSupportedSatelliteServices.get(subId); if (supportedServices != null && supportedServices.containsKey(plmn)) { return new ArrayList<>(supportedServices.get(plmn)); } else { loge("getSupportedSatelliteServices: subId=" + subId + ", supportedServices " + "does not contain key plmn=" + plmn); } } else { loge("getSupportedSatelliteServices: mSupportedSatelliteServices does contain key" + " subId=" + subId); } return new ArrayList<>(); } } /** * If we have not successfully queried the satellite modem for its satellite service support, * we will retry the query one more time. Otherwise, we will return the cached result. Loading Loading @@ -2312,6 +2384,96 @@ public class SatelliteController extends Handler { return (DEBUG || SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false)); } private void updateSupportedSatelliteServicesForActiveSubscriptions() { synchronized (mSupportedSatelliteServicesLock) { mSupportedSatelliteServices.clear(); int[] activeSubIds = SubscriptionManagerService.getInstance().getActiveSubIdList(true); if (activeSubIds != null) { for (int subId : activeSubIds) { updateSupportedSatelliteServices(subId); } } else { loge("updateSupportedSatelliteServicesForActiveSubscriptions: " + "activeSubIds is null"); } } } private void updateSupportedSatelliteServices(int subId) { Map<String, Set<Integer>> carrierSupportedSatelliteServicesPerPlmn = readSupportedSatelliteServicesFromCarrierConfig(subId); synchronized (mSupportedSatelliteServicesLock) { mSupportedSatelliteServices.put(subId, SatelliteServiceUtils.mergeSupportedSatelliteServices( mSatelliteServicesSupportedByProviders, carrierSupportedSatelliteServicesPerPlmn)); } } @NonNull private Map<String, Set<Integer>> readSupportedSatelliteServicesFromOverlayConfig() { String[] supportedServices = readStringArrayFromOverlayConfig( R.array.config_satellite_services_supported_by_providers); return SatelliteServiceUtils.parseSupportedSatelliteServices(supportedServices); } @NonNull private Map<String, Set<Integer>> readSupportedSatelliteServicesFromCarrierConfig(int subId) { synchronized (mCarrierConfigArrayLock) { PersistableBundle config = mCarrierConfigArray.get(subId); if (config == null) { config = getConfigForSubId(subId); mCarrierConfigArray.put(subId, config); } return SatelliteServiceUtils.parseSupportedSatelliteServices( config.getPersistableBundle(CarrierConfigManager .KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE)); } } @NonNull private PersistableBundle getConfigForSubId(int subId) { PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId, CarrierConfigManager .KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE); if (config == null || config.isEmpty()) { config = CarrierConfigManager.getDefaultConfig(); } return config; } private void handleCarrierConfigChanged(int slotIndex, int subId, int carrierId, int specificCarrierId) { logd("handleCarrierConfigChanged(): slotIndex(" + slotIndex + "), subId(" + subId + "), carrierId(" + carrierId + "), specificCarrierId(" + specificCarrierId + ")"); if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { return; } updateCarrierConfig(subId); updateSupportedSatelliteServicesForActiveSubscriptions(); } private void updateCarrierConfig(int subId) { synchronized (mCarrierConfigArrayLock) { mCarrierConfigArray.put(subId, getConfigForSubId(subId)); } } @NonNull private String[] readStringArrayFromOverlayConfig(@ArrayRes int id) { String[] strArray = null; try { strArray = mContext.getResources().getStringArray(id); } catch (Resources.NotFoundException ex) { loge("readStringArrayFromOverlayConfig: id= " + id + ", ex=" + ex); } if (strArray == null) { strArray = new String[0]; } return strArray; } private static void logd(@NonNull String log) { Rlog.d(TAG, log); } Loading src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java +128 −0 Original line number Diff line number Diff line Loading @@ -16,11 +16,16 @@ package com.android.internal.telephony.satellite; import static android.telephony.NetworkRegistrationInfo.FIRST_SERVICE_TYPE; import static android.telephony.NetworkRegistrationInfo.LAST_SERVICE_TYPE; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.os.AsyncResult; import android.os.Binder; import android.os.PersistableBundle; import android.telephony.NetworkRegistrationInfo; import android.telephony.Rlog; import android.telephony.SubscriptionManager; import android.telephony.satellite.AntennaPosition; Loading @@ -40,7 +45,9 @@ import com.android.internal.telephony.subscription.SubscriptionManagerService; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; /** Loading Loading @@ -266,6 +273,127 @@ public class SatelliteServiceUtils { return SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; } /** * Expected format of each input string in the array: "PLMN_1:service_1,service_2,..." * * @return The map of supported services with key: PLMN, value: set of services supported by * the PLMN. */ @NonNull @NetworkRegistrationInfo.ServiceType public static Map<String, Set<Integer>> parseSupportedSatelliteServices( String[] supportedSatelliteServicesStrArray) { Map<String, Set<Integer>> supportedServicesMap = new HashMap<>(); if (supportedSatelliteServicesStrArray == null || supportedSatelliteServicesStrArray.length == 0) { return supportedServicesMap; } for (String supportedServicesPerPlmnStr : supportedSatelliteServicesStrArray) { String[] pairOfPlmnAndsupportedServicesStr = supportedServicesPerPlmnStr.split(":"); if (pairOfPlmnAndsupportedServicesStr != null && (pairOfPlmnAndsupportedServicesStr.length == 1 || pairOfPlmnAndsupportedServicesStr.length == 2)) { String plmn = pairOfPlmnAndsupportedServicesStr[0]; Set<Integer> supportedServicesSet = new HashSet<>(); if (pairOfPlmnAndsupportedServicesStr.length == 2) { String[] supportedServicesStrArray = pairOfPlmnAndsupportedServicesStr[1].split(","); for (String service : supportedServicesStrArray) { try { int serviceType = Integer.parseInt(service); if (isServiceTypeValid(serviceType)) { supportedServicesSet.add(serviceType); } else { loge("parseSupportedSatelliteServices: invalid serviceType=" + serviceType); } } catch (NumberFormatException e) { loge("parseSupportedSatelliteServices: supportedServicesPerPlmnStr=" + supportedServicesPerPlmnStr + ", service=" + service + ", e=" + e); } } } supportedServicesMap.put(plmn, supportedServicesSet); } else { loge("parseSupportedSatelliteServices: invalid format input, " + "supportedServicesPerPlmnStr=" + supportedServicesPerPlmnStr); } } return supportedServicesMap; } /** * Expected format of the input dictionary bundle is: * <ul> * <li>Key: PLMN string.</li> * <li>Value: A string with format "service_1,service_2,..."</li> * </ul> * @return The map of supported services with key: PLMN, value: set of services supported by * the PLMN. */ @NonNull @NetworkRegistrationInfo.ServiceType public static Map<String, Set<Integer>> parseSupportedSatelliteServices( PersistableBundle supportedServicesBundle) { Map<String, Set<Integer>> supportedServicesMap = new HashMap<>(); if (supportedServicesBundle == null || supportedServicesBundle.isEmpty()) { return supportedServicesMap; } for (String plmn : supportedServicesBundle.keySet()) { Set<Integer> supportedServicesSet = new HashSet<>(); for (int serviceType : supportedServicesBundle.getIntArray(plmn)) { if (isServiceTypeValid(serviceType)) { supportedServicesSet.add(serviceType); } else { loge("parseSupportedSatelliteServices: invalid service type=" + serviceType + " for plmn=" + plmn); } } supportedServicesMap.put(plmn, supportedServicesSet); } return supportedServicesMap; } /** * For the PLMN that exists in both {@code providerSupportedServices} and * {@code carrierSupportedServices}, the supported services will be the intersection of the two * sets. For the PLMN that is present in {@code providerSupportedServices} but not in * {@code carrierSupportedServices}, the provider supported services will be used. The rest * will not be used. * * @param providerSupportedServices Satellite provider supported satellite services. * @param carrierSupportedServices Carrier supported satellite services. * @return The supported satellite services by the device for the corresponding carrier and the * satellite provider. */ @NonNull @NetworkRegistrationInfo.ServiceType public static Map<String, Set<Integer>> mergeSupportedSatelliteServices( @NonNull @NetworkRegistrationInfo.ServiceType Map<String, Set<Integer>> providerSupportedServices, @NonNull @NetworkRegistrationInfo.ServiceType Map<String, Set<Integer>> carrierSupportedServices) { Map<String, Set<Integer>> supportedServicesMap = new HashMap<>(); for (Map.Entry<String, Set<Integer>> entry : providerSupportedServices.entrySet()) { Set<Integer> supportedServices = new HashSet<>(entry.getValue()); if (carrierSupportedServices.containsKey(entry.getKey())) { supportedServices.retainAll(carrierSupportedServices.get(entry.getKey())); } if (!supportedServices.isEmpty()) { supportedServicesMap.put(entry.getKey(), supportedServices); } } return supportedServicesMap; } private static boolean isServiceTypeValid(int serviceType) { return (serviceType >= FIRST_SERVICE_TYPE && serviceType <= LAST_SERVICE_TYPE); } /** * Return phone associated with phoneId 0. * Loading tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +62 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
src/java/com/android/internal/telephony/ServiceStateTracker.java +13 −0 Original line number Diff line number Diff line Loading @@ -97,6 +97,7 @@ import com.android.internal.telephony.data.DataNetworkController.DataNetworkCont import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.metrics.ServiceStateStats; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.satellite.NtnCapabilityResolver; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState; Loading Loading @@ -3425,6 +3426,7 @@ public class ServiceStateTracker extends Handler { updateNrFrequencyRangeFromPhysicalChannelConfigs(mLastPhysicalChannelConfigList, mNewSS); updateNrStateFromPhysicalChannelConfigs(mLastPhysicalChannelConfigList, mNewSS); updateNtnCapability(); if (TelephonyUtils.IS_DEBUGGABLE && mPhone.getTelephonyTester() != null) { mPhone.getTelephonyTester().overrideServiceState(mNewSS); Loading Loading @@ -5554,6 +5556,17 @@ public class ServiceStateTracker extends Handler { } } private void updateNtnCapability() { for (NetworkRegistrationInfo nri : mNewSS.getNetworkRegistrationInfoListForTransportType( AccessNetworkConstants.TRANSPORT_TYPE_WWAN)) { NtnCapabilityResolver.resolveNtnCapability(nri, mSubId); if (nri.isNonTerrestrialNetwork()) { // Replace the existing NRI with the updated NRI. mNewSS.addNetworkRegistrationInfo(nri); } } } /** * Check if device is non-roaming and always on home network. * Loading
src/java/com/android/internal/telephony/satellite/NtnCapabilityResolver.java 0 → 100644 +59 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.telephony.satellite; import android.annotation.NonNull; import android.telephony.NetworkRegistrationInfo; import android.telephony.Rlog; import android.text.TextUtils; import java.util.List; /** * This utility class is responsible for resolving NTN capabilities of a * {@link NetworkRegistrationInfo}. */ public class NtnCapabilityResolver { private static final String TAG = "NtnCapabilityResolver"; /** * Resolve NTN capability by updating the input NetworkRegistrationInfo to indicate whether * connecting to a non-terrestrial network and the available services supported by the network. * * @param networkRegistrationInfo The NetworkRegistrationInfo of a network. * @param subId The subscription ID associated with a phone. */ public static void resolveNtnCapability( @NonNull NetworkRegistrationInfo networkRegistrationInfo, int subId) { SatelliteController satelliteController = SatelliteController.getInstance(); List<String> satellitePlmnList = satelliteController.getSatellitePlmnList(); String registeredPlmn = networkRegistrationInfo.getRegisteredPlmn(); for (String satellitePlmn : satellitePlmnList) { if (TextUtils.equals(satellitePlmn, registeredPlmn)) { logd("Registered to satellite PLMN " + satellitePlmn); networkRegistrationInfo.setIsNonTerrestrialNetwork(true); networkRegistrationInfo.setAvailableServices( satelliteController.getSupportedSatelliteServices(subId, satellitePlmn)); break; } } } private static void logd(@NonNull String log) { Rlog.d(TAG, log); } }
src/java/com/android/internal/telephony/satellite/SatelliteController.java +162 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.internal.telephony.satellite; import android.annotation.ArrayRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.bluetooth.BluetoothAdapter; Loading @@ -25,6 +26,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.res.Resources; import android.database.ContentObserver; import android.net.wifi.WifiManager; import android.nfc.NfcAdapter; Loading @@ -34,15 +36,18 @@ import android.os.Build; import android.os.Bundle; import android.os.CancellationSignal; import android.os.Handler; import android.os.HandlerExecutor; import android.os.HandlerThread; import android.os.IBinder; import android.os.ICancellationSignal; import android.os.Looper; import android.os.Message; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.SystemProperties; import android.provider.Settings; import android.telephony.CarrierConfigManager; import android.telephony.Rlog; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; Loading @@ -54,8 +59,10 @@ import android.telephony.satellite.SatelliteCapabilities; import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; import android.util.Log; import android.util.SparseArray; import android.uwb.UwbManager; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; Loading @@ -64,10 +71,14 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats; import com.android.internal.telephony.satellite.metrics.ProvisionMetricsStats; import com.android.internal.telephony.satellite.metrics.SessionMetricsStats; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.util.FunctionalUtils; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; Loading Loading @@ -199,6 +210,22 @@ public class SatelliteController extends Handler { private final Object mNeedsSatellitePointingLock = new Object(); @GuardedBy("mNeedsSatellitePointingLock") private boolean mNeedsSatellitePointing = false; /** Key: subId, value: (key: PLMN, value: set of * {@link android.telephony.NetworkRegistrationInfo.ServiceType}) */ @GuardedBy("mSupportedSatelliteServicesLock") @NonNull private final Map<Integer, Map<String, Set<Integer>>> mSupportedSatelliteServices = new HashMap<>(); @NonNull private final Object mSupportedSatelliteServicesLock = new Object(); /** Key: PLMN, value: set of {@link android.telephony.NetworkRegistrationInfo.ServiceType} */ @NonNull private final Map<String, Set<Integer>> mSatelliteServicesSupportedByProviders; @NonNull private final CarrierConfigManager mCarrierConfigManager; @NonNull private final CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; @NonNull private final Object mCarrierConfigArrayLock = new Object(); @GuardedBy("mCarrierConfigArrayLock") @NonNull private final SparseArray<PersistableBundle> mCarrierConfigArray = new SparseArray<>(); @NonNull private final List<String> mSatellitePlmnList; /** * @return The singleton instance of SatelliteController. Loading Loading @@ -266,6 +293,7 @@ public class SatelliteController extends Handler { registerForPendingDatagramCount(); registerForSatelliteModemStateChanged(); mContentResolver = mContext.getContentResolver(); mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class); try { mSharedPreferences = mContext.getSharedPreferences(SATELLITE_SHARED_PREF, Loading @@ -287,6 +315,16 @@ public class SatelliteController extends Handler { Settings.Global.getUriFor(Settings.Global.SATELLITE_MODE_RADIOS), false, satelliteModeRadiosContentObserver); } mSatelliteServicesSupportedByProviders = readSupportedSatelliteServicesFromOverlayConfig(); mSatellitePlmnList = mSatelliteServicesSupportedByProviders.keySet().stream().toList(); updateSupportedSatelliteServicesForActiveSubscriptions(); mCarrierConfigChangeListener = (slotIndex, subId, carrierId, specificCarrierId) -> handleCarrierConfigChanged(slotIndex, subId, carrierId, specificCarrierId); mCarrierConfigManager.registerCarrierConfigChangeListener( new HandlerExecutor(new Handler(looper)), mCarrierConfigChangeListener); } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) Loading Loading @@ -1901,6 +1939,40 @@ public class SatelliteController extends Handler { return (supported != null ? supported : false); } /** * @return The list of satellite PLMNs used for connecting to satellite networks. */ @NonNull public List<String> getSatellitePlmnList() { return new ArrayList<>(mSatellitePlmnList); } /** * @param subId Subscription ID. * @param plmn The satellite roaming plmn. * @return The list of services supported by the carrier associated with the {@code subId} for * the satellite network {@code plmn}. */ @NonNull public List<Integer> getSupportedSatelliteServices(int subId, String plmn) { synchronized (mSupportedSatelliteServicesLock) { if (mSupportedSatelliteServices.containsKey(subId)) { Map<String, Set<Integer>> supportedServices = mSupportedSatelliteServices.get(subId); if (supportedServices != null && supportedServices.containsKey(plmn)) { return new ArrayList<>(supportedServices.get(plmn)); } else { loge("getSupportedSatelliteServices: subId=" + subId + ", supportedServices " + "does not contain key plmn=" + plmn); } } else { loge("getSupportedSatelliteServices: mSupportedSatelliteServices does contain key" + " subId=" + subId); } return new ArrayList<>(); } } /** * If we have not successfully queried the satellite modem for its satellite service support, * we will retry the query one more time. Otherwise, we will return the cached result. Loading Loading @@ -2312,6 +2384,96 @@ public class SatelliteController extends Handler { return (DEBUG || SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false)); } private void updateSupportedSatelliteServicesForActiveSubscriptions() { synchronized (mSupportedSatelliteServicesLock) { mSupportedSatelliteServices.clear(); int[] activeSubIds = SubscriptionManagerService.getInstance().getActiveSubIdList(true); if (activeSubIds != null) { for (int subId : activeSubIds) { updateSupportedSatelliteServices(subId); } } else { loge("updateSupportedSatelliteServicesForActiveSubscriptions: " + "activeSubIds is null"); } } } private void updateSupportedSatelliteServices(int subId) { Map<String, Set<Integer>> carrierSupportedSatelliteServicesPerPlmn = readSupportedSatelliteServicesFromCarrierConfig(subId); synchronized (mSupportedSatelliteServicesLock) { mSupportedSatelliteServices.put(subId, SatelliteServiceUtils.mergeSupportedSatelliteServices( mSatelliteServicesSupportedByProviders, carrierSupportedSatelliteServicesPerPlmn)); } } @NonNull private Map<String, Set<Integer>> readSupportedSatelliteServicesFromOverlayConfig() { String[] supportedServices = readStringArrayFromOverlayConfig( R.array.config_satellite_services_supported_by_providers); return SatelliteServiceUtils.parseSupportedSatelliteServices(supportedServices); } @NonNull private Map<String, Set<Integer>> readSupportedSatelliteServicesFromCarrierConfig(int subId) { synchronized (mCarrierConfigArrayLock) { PersistableBundle config = mCarrierConfigArray.get(subId); if (config == null) { config = getConfigForSubId(subId); mCarrierConfigArray.put(subId, config); } return SatelliteServiceUtils.parseSupportedSatelliteServices( config.getPersistableBundle(CarrierConfigManager .KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE)); } } @NonNull private PersistableBundle getConfigForSubId(int subId) { PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId, CarrierConfigManager .KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE); if (config == null || config.isEmpty()) { config = CarrierConfigManager.getDefaultConfig(); } return config; } private void handleCarrierConfigChanged(int slotIndex, int subId, int carrierId, int specificCarrierId) { logd("handleCarrierConfigChanged(): slotIndex(" + slotIndex + "), subId(" + subId + "), carrierId(" + carrierId + "), specificCarrierId(" + specificCarrierId + ")"); if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { return; } updateCarrierConfig(subId); updateSupportedSatelliteServicesForActiveSubscriptions(); } private void updateCarrierConfig(int subId) { synchronized (mCarrierConfigArrayLock) { mCarrierConfigArray.put(subId, getConfigForSubId(subId)); } } @NonNull private String[] readStringArrayFromOverlayConfig(@ArrayRes int id) { String[] strArray = null; try { strArray = mContext.getResources().getStringArray(id); } catch (Resources.NotFoundException ex) { loge("readStringArrayFromOverlayConfig: id= " + id + ", ex=" + ex); } if (strArray == null) { strArray = new String[0]; } return strArray; } private static void logd(@NonNull String log) { Rlog.d(TAG, log); } Loading
src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java +128 −0 Original line number Diff line number Diff line Loading @@ -16,11 +16,16 @@ package com.android.internal.telephony.satellite; import static android.telephony.NetworkRegistrationInfo.FIRST_SERVICE_TYPE; import static android.telephony.NetworkRegistrationInfo.LAST_SERVICE_TYPE; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.os.AsyncResult; import android.os.Binder; import android.os.PersistableBundle; import android.telephony.NetworkRegistrationInfo; import android.telephony.Rlog; import android.telephony.SubscriptionManager; import android.telephony.satellite.AntennaPosition; Loading @@ -40,7 +45,9 @@ import com.android.internal.telephony.subscription.SubscriptionManagerService; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; /** Loading Loading @@ -266,6 +273,127 @@ public class SatelliteServiceUtils { return SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; } /** * Expected format of each input string in the array: "PLMN_1:service_1,service_2,..." * * @return The map of supported services with key: PLMN, value: set of services supported by * the PLMN. */ @NonNull @NetworkRegistrationInfo.ServiceType public static Map<String, Set<Integer>> parseSupportedSatelliteServices( String[] supportedSatelliteServicesStrArray) { Map<String, Set<Integer>> supportedServicesMap = new HashMap<>(); if (supportedSatelliteServicesStrArray == null || supportedSatelliteServicesStrArray.length == 0) { return supportedServicesMap; } for (String supportedServicesPerPlmnStr : supportedSatelliteServicesStrArray) { String[] pairOfPlmnAndsupportedServicesStr = supportedServicesPerPlmnStr.split(":"); if (pairOfPlmnAndsupportedServicesStr != null && (pairOfPlmnAndsupportedServicesStr.length == 1 || pairOfPlmnAndsupportedServicesStr.length == 2)) { String plmn = pairOfPlmnAndsupportedServicesStr[0]; Set<Integer> supportedServicesSet = new HashSet<>(); if (pairOfPlmnAndsupportedServicesStr.length == 2) { String[] supportedServicesStrArray = pairOfPlmnAndsupportedServicesStr[1].split(","); for (String service : supportedServicesStrArray) { try { int serviceType = Integer.parseInt(service); if (isServiceTypeValid(serviceType)) { supportedServicesSet.add(serviceType); } else { loge("parseSupportedSatelliteServices: invalid serviceType=" + serviceType); } } catch (NumberFormatException e) { loge("parseSupportedSatelliteServices: supportedServicesPerPlmnStr=" + supportedServicesPerPlmnStr + ", service=" + service + ", e=" + e); } } } supportedServicesMap.put(plmn, supportedServicesSet); } else { loge("parseSupportedSatelliteServices: invalid format input, " + "supportedServicesPerPlmnStr=" + supportedServicesPerPlmnStr); } } return supportedServicesMap; } /** * Expected format of the input dictionary bundle is: * <ul> * <li>Key: PLMN string.</li> * <li>Value: A string with format "service_1,service_2,..."</li> * </ul> * @return The map of supported services with key: PLMN, value: set of services supported by * the PLMN. */ @NonNull @NetworkRegistrationInfo.ServiceType public static Map<String, Set<Integer>> parseSupportedSatelliteServices( PersistableBundle supportedServicesBundle) { Map<String, Set<Integer>> supportedServicesMap = new HashMap<>(); if (supportedServicesBundle == null || supportedServicesBundle.isEmpty()) { return supportedServicesMap; } for (String plmn : supportedServicesBundle.keySet()) { Set<Integer> supportedServicesSet = new HashSet<>(); for (int serviceType : supportedServicesBundle.getIntArray(plmn)) { if (isServiceTypeValid(serviceType)) { supportedServicesSet.add(serviceType); } else { loge("parseSupportedSatelliteServices: invalid service type=" + serviceType + " for plmn=" + plmn); } } supportedServicesMap.put(plmn, supportedServicesSet); } return supportedServicesMap; } /** * For the PLMN that exists in both {@code providerSupportedServices} and * {@code carrierSupportedServices}, the supported services will be the intersection of the two * sets. For the PLMN that is present in {@code providerSupportedServices} but not in * {@code carrierSupportedServices}, the provider supported services will be used. The rest * will not be used. * * @param providerSupportedServices Satellite provider supported satellite services. * @param carrierSupportedServices Carrier supported satellite services. * @return The supported satellite services by the device for the corresponding carrier and the * satellite provider. */ @NonNull @NetworkRegistrationInfo.ServiceType public static Map<String, Set<Integer>> mergeSupportedSatelliteServices( @NonNull @NetworkRegistrationInfo.ServiceType Map<String, Set<Integer>> providerSupportedServices, @NonNull @NetworkRegistrationInfo.ServiceType Map<String, Set<Integer>> carrierSupportedServices) { Map<String, Set<Integer>> supportedServicesMap = new HashMap<>(); for (Map.Entry<String, Set<Integer>> entry : providerSupportedServices.entrySet()) { Set<Integer> supportedServices = new HashSet<>(entry.getValue()); if (carrierSupportedServices.containsKey(entry.getKey())) { supportedServices.retainAll(carrierSupportedServices.get(entry.getKey())); } if (!supportedServices.isEmpty()) { supportedServicesMap.put(entry.getKey(), supportedServices); } } return supportedServicesMap; } private static boolean isServiceTypeValid(int serviceType) { return (serviceType >= FIRST_SERVICE_TYPE && serviceType <= LAST_SERVICE_TYPE); } /** * Return phone associated with phoneId 0. * Loading
tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +62 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes