Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6bf4e64b authored by Thomas Nguyen's avatar Thomas Nguyen Committed by Android (Google) Code Review
Browse files

Merge "Resolving NTN capability" into main

parents 95002dcb 740931e5
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -98,6 +98,7 @@ import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.metrics.RadioPowerStateStats;
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;
@@ -3428,6 +3429,7 @@ public class ServiceStateTracker extends Handler {

        updateNrFrequencyRangeFromPhysicalChannelConfigs(mLastPhysicalChannelConfigList, mNewSS);
        updateNrStateFromPhysicalChannelConfigs(mLastPhysicalChannelConfigList, mNewSS);
        updateNtnCapability();

        if (TelephonyUtils.IS_DEBUGGABLE && mPhone.getTelephonyTester() != null) {
            mPhone.getTelephonyTester().overrideServiceState(mNewSS);
@@ -5557,6 +5559,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.
     *
+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);
    }
}
+162 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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.
@@ -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,
@@ -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)
@@ -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.
@@ -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);
    }
+128 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;

/**
@@ -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.
     *
+62 −0

File changed.

Preview size limit exceeded, changes collapsed.

Loading