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

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

Merge "Resolving NTN capability" into udc-qpr-dev

parents 6e20534d 907f9e4e
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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);
@@ -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.
     *
+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