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

Commit 90864bc8 authored by Yan Yan's avatar Yan Yan
Browse files

Refactor VCN route selection with UnderlyingNetworkEvaluator

This is a preparation CL that allows followup CLs to add network
metric monitors. This CL does a pure refactoring without
introducing any behavior changes

Specific changes include:
- UnderlyingNetworkEvaluator now encapsulates the calculation of
  mPriorityClass
- mIsSelected is moved from UnderlyingNetworkRecord to
  UnderlyingNetworkEvaluator
- UnderlyingNetworkListener is simplified by moving the network
  candidate out to the UnderlyingNetworkController
- NetworkPriorityClassifier now takes a "isSelected" boolean
  instead of the currently selected network candidate

Bug: 282996138
Bug: 315858972
Test: atest FrameworksVcnTests, CtsVcnTestCases
Change-Id: I8461a68f1c4260b253d84d3efed2b09c41116656
parent daf616ad
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -915,9 +915,11 @@ public class VcnGatewayConnection extends StateMachine {
            // TODO(b/180132994): explore safely removing this Thread check
            mVcnContext.ensureRunningOnLooperThread();

            if (!UnderlyingNetworkRecord.isSameNetwork(mUnderlying, underlying)) {
                logInfo(
                        "Selected underlying network changed: "
                                + (underlying == null ? null : underlying.network));
            }

            // TODO(b/179091925): Move the delayed-message handling to BaseState

+10 −19
Original line number Diff line number Diff line
@@ -47,7 +47,6 @@ import com.android.server.vcn.VcnContext;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/** @hide */
@@ -86,7 +85,6 @@ class NetworkPriorityClassifier {
     * <p>VCN MUST never select a non-INTERNET network that are unvalidated or fail to match any
     * template as the underlying network.
     */
    @VisibleForTesting(visibility = Visibility.PRIVATE)
    static final int PRIORITY_INVALID = -1;

    /** Gives networks a priority class, based on configured VcnGatewayConnectionConfig */
@@ -96,7 +94,7 @@ class NetworkPriorityClassifier {
            List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates,
            ParcelUuid subscriptionGroup,
            TelephonySubscriptionSnapshot snapshot,
            UnderlyingNetworkRecord currentlySelected,
            boolean isSelected,
            PersistableBundleWrapper carrierConfig) {
        // mRouteSelectionNetworkRequest requires a network be both VALIDATED and NOT_SUSPENDED

@@ -118,7 +116,7 @@ class NetworkPriorityClassifier {
                    networkRecord,
                    subscriptionGroup,
                    snapshot,
                    currentlySelected,
                    isSelected,
                    carrierConfig)) {
                return priorityIndex;
            }
@@ -140,12 +138,9 @@ class NetworkPriorityClassifier {
            UnderlyingNetworkRecord networkRecord,
            ParcelUuid subscriptionGroup,
            TelephonySubscriptionSnapshot snapshot,
            UnderlyingNetworkRecord currentlySelected,
            boolean isSelected,
            PersistableBundleWrapper carrierConfig) {
        final NetworkCapabilities caps = networkRecord.networkCapabilities;
        final boolean isSelectedUnderlyingNetwork =
                currentlySelected != null
                        && Objects.equals(currentlySelected.network, networkRecord.network);

        final int meteredMatch = networkPriority.getMetered();
        final boolean isMetered = !caps.hasCapability(NET_CAPABILITY_NOT_METERED);
@@ -159,7 +154,7 @@ class NetworkPriorityClassifier {
        if (caps.getLinkUpstreamBandwidthKbps() < networkPriority.getMinExitUpstreamBandwidthKbps()
                || (caps.getLinkUpstreamBandwidthKbps()
                                < networkPriority.getMinEntryUpstreamBandwidthKbps()
                        && !isSelectedUnderlyingNetwork)) {
                        && !isSelected)) {
            return false;
        }

@@ -167,7 +162,7 @@ class NetworkPriorityClassifier {
                        < networkPriority.getMinExitDownstreamBandwidthKbps()
                || (caps.getLinkDownstreamBandwidthKbps()
                                < networkPriority.getMinEntryDownstreamBandwidthKbps()
                        && !isSelectedUnderlyingNetwork)) {
                        && !isSelected)) {
            return false;
        }

@@ -191,7 +186,7 @@ class NetworkPriorityClassifier {
            return checkMatchesWifiPriorityRule(
                    (VcnWifiUnderlyingNetworkTemplate) networkPriority,
                    networkRecord,
                    currentlySelected,
                    isSelected,
                    carrierConfig);
        }

@@ -214,7 +209,7 @@ class NetworkPriorityClassifier {
    public static boolean checkMatchesWifiPriorityRule(
            VcnWifiUnderlyingNetworkTemplate networkPriority,
            UnderlyingNetworkRecord networkRecord,
            UnderlyingNetworkRecord currentlySelected,
            boolean isSelected,
            PersistableBundleWrapper carrierConfig) {
        final NetworkCapabilities caps = networkRecord.networkCapabilities;

@@ -223,7 +218,7 @@ class NetworkPriorityClassifier {
        }

        // TODO: Move the Network Quality check to the network metric monitor framework.
        if (!isWifiRssiAcceptable(networkRecord, currentlySelected, carrierConfig)) {
        if (!isWifiRssiAcceptable(networkRecord, isSelected, carrierConfig)) {
            return false;
        }

@@ -237,15 +232,11 @@ class NetworkPriorityClassifier {

    private static boolean isWifiRssiAcceptable(
            UnderlyingNetworkRecord networkRecord,
            UnderlyingNetworkRecord currentlySelected,
            boolean isSelected,
            PersistableBundleWrapper carrierConfig) {
        final NetworkCapabilities caps = networkRecord.networkCapabilities;
        final boolean isSelectedNetwork =
                currentlySelected != null
                        && networkRecord.network.equals(currentlySelected.network);

        if (isSelectedNetwork
                && caps.getSignalStrength() >= getWifiExitRssiThreshold(carrierConfig)) {
        if (isSelected && caps.getSignalStrength() >= getWifiExitRssiThreshold(carrierConfig)) {
            return true;
        }

+120 −67
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ import android.util.ArraySet;
import android.util.Slog;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import com.android.server.vcn.VcnContext;
@@ -83,6 +84,9 @@ public class UnderlyingNetworkController {
    @NonNull private final TelephonyCallback mActiveDataSubIdListener =
            new VcnActiveDataSubscriptionIdListener();

    private final Map<Network, UnderlyingNetworkEvaluator> mUnderlyingNetworkRecords =
            new ArrayMap<>();

    @NonNull private final List<NetworkCallback> mCellBringupCallbacks = new ArrayList<>();
    @Nullable private NetworkCallback mWifiBringupCallback;
    @Nullable private NetworkCallback mWifiEntryRssiThresholdCallback;
@@ -105,7 +109,8 @@ public class UnderlyingNetworkController {
        this(vcnContext, connectionConfig, subscriptionGroup, snapshot, cb, new Dependencies());
    }

    private UnderlyingNetworkController(
    @VisibleForTesting(visibility = Visibility.PRIVATE)
    UnderlyingNetworkController(
            @NonNull VcnContext vcnContext,
            @NonNull VcnGatewayConnectionConfig connectionConfig,
            @NonNull ParcelUuid subscriptionGroup,
@@ -196,6 +201,7 @@ public class UnderlyingNetworkController {
        NetworkCallback oldWifiExitRssiThresholdCallback = mWifiExitRssiThresholdCallback;
        List<NetworkCallback> oldCellCallbacks = new ArrayList<>(mCellBringupCallbacks);
        mCellBringupCallbacks.clear();
        mUnderlyingNetworkRecords.clear();

        // Register new callbacks. Make-before-break; always register new callbacks before removal
        // of old callbacks
@@ -395,6 +401,18 @@ public class UnderlyingNetworkController {
        // Update carrier config
        mCarrierConfig = mLastSnapshot.getCarrierConfigForSubGrp(mSubscriptionGroup);

        // Make sure all evaluators use the same updated TelephonySubscriptionSnapshot and carrier
        // config to calculate their cached priority classes. For simplicity, the
        // UnderlyingNetworkController does not listen for changes in VCN-related carrier config
        // keys, and changes are applied at restart of the VcnGatewayConnection
        for (UnderlyingNetworkEvaluator evaluator : mUnderlyingNetworkRecords.values()) {
            evaluator.reevaluate(
                    mConnectionConfig.getVcnUnderlyingNetworkPriorities(),
                    mSubscriptionGroup,
                    mLastSnapshot,
                    mCarrierConfig);
        }

        // Only trigger re-registration if subIds in this group have changed
        if (oldSnapshot
                .getAllSubIdsInGroup(mSubscriptionGroup)
@@ -418,32 +436,62 @@ public class UnderlyingNetworkController {
                .unregisterTelephonyCallback(mActiveDataSubIdListener);
    }

    private TreeSet<UnderlyingNetworkEvaluator> getSortedUnderlyingNetworks() {
        TreeSet<UnderlyingNetworkEvaluator> sorted =
                new TreeSet<>(UnderlyingNetworkEvaluator.getComparator());

        for (UnderlyingNetworkEvaluator evaluator : mUnderlyingNetworkRecords.values()) {
            if (evaluator.getPriorityClass() != NetworkPriorityClassifier.PRIORITY_INVALID) {
                sorted.add(evaluator);
            }
        }

        return sorted;
    }

    private void reevaluateNetworks() {
        if (mIsQuitting || mRouteSelectionCallback == null) {
            return; // UnderlyingNetworkController has quit.
        }

        TreeSet<UnderlyingNetworkRecord> sorted =
                mRouteSelectionCallback.getSortedUnderlyingNetworks();
        UnderlyingNetworkRecord candidate = sorted.isEmpty() ? null : sorted.first();
        TreeSet<UnderlyingNetworkEvaluator> sorted = getSortedUnderlyingNetworks();

        UnderlyingNetworkEvaluator candidateEvaluator = sorted.isEmpty() ? null : sorted.first();
        UnderlyingNetworkRecord candidate =
                candidateEvaluator == null ? null : candidateEvaluator.getNetworkRecord();
        if (Objects.equals(mCurrentRecord, candidate)) {
            return;
        }

        String allNetworkPriorities = "";
        for (UnderlyingNetworkRecord record : sorted) {
        for (UnderlyingNetworkEvaluator recordEvaluator : sorted) {
            if (!allNetworkPriorities.isEmpty()) {
                allNetworkPriorities += ", ";
            }
            allNetworkPriorities += record.network + ": " + record.priorityClass;
            allNetworkPriorities +=
                    recordEvaluator.getNetwork() + ": " + recordEvaluator.getPriorityClass();
        }

        if (!UnderlyingNetworkRecord.isSameNetwork(mCurrentRecord, candidate)) {
            logInfo(
                    "Selected network changed to "
                            + (candidate == null ? null : candidate.network)
                            + ", selected from list: "
                            + allNetworkPriorities);
        }

        mCurrentRecord = candidate;
        mCb.onSelectedUnderlyingNetworkChanged(mCurrentRecord);

        // Need to update all evaluators to ensure the previously selected one is unselected
        for (UnderlyingNetworkEvaluator evaluator : mUnderlyingNetworkRecords.values()) {
            evaluator.setIsSelected(
                    candidateEvaluator == evaluator,
                    mConnectionConfig.getVcnUnderlyingNetworkPriorities(),
                    mSubscriptionGroup,
                    mLastSnapshot,
                    mCarrierConfig);
        }
    }

    /**
@@ -463,46 +511,26 @@ public class UnderlyingNetworkController {
     */
    @VisibleForTesting
    class UnderlyingNetworkListener extends NetworkCallback {
        private final Map<Network, UnderlyingNetworkRecord.Builder>
                mUnderlyingNetworkRecordBuilders = new ArrayMap<>();

        UnderlyingNetworkListener() {
            super(NetworkCallback.FLAG_INCLUDE_LOCATION_INFO);
        }

        private TreeSet<UnderlyingNetworkRecord> getSortedUnderlyingNetworks() {
            TreeSet<UnderlyingNetworkRecord> sorted =
                    new TreeSet<>(UnderlyingNetworkRecord.getComparator());

            for (UnderlyingNetworkRecord.Builder builder :
                    mUnderlyingNetworkRecordBuilders.values()) {
                if (builder.isValid()) {
                    final UnderlyingNetworkRecord record =
                            builder.build(
        @Override
        public void onAvailable(@NonNull Network network) {
            mUnderlyingNetworkRecords.put(
                    network,
                    mDeps.newUnderlyingNetworkEvaluator(
                            mVcnContext,
                            network,
                            mConnectionConfig.getVcnUnderlyingNetworkPriorities(),
                            mSubscriptionGroup,
                            mLastSnapshot,
                                    mCurrentRecord,
                                    mCarrierConfig);
                    if (record.priorityClass != NetworkPriorityClassifier.PRIORITY_INVALID) {
                        sorted.add(record);
                    }
                }
            }

            return sorted;
        }

        @Override
        public void onAvailable(@NonNull Network network) {
            mUnderlyingNetworkRecordBuilders.put(
                    network, new UnderlyingNetworkRecord.Builder(network));
                            mCarrierConfig));
        }

        @Override
        public void onLost(@NonNull Network network) {
            mUnderlyingNetworkRecordBuilders.remove(network);
            mUnderlyingNetworkRecords.remove(network);

            reevaluateNetworks();
        }
@@ -510,15 +538,20 @@ public class UnderlyingNetworkController {
        @Override
        public void onCapabilitiesChanged(
                @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
            final UnderlyingNetworkRecord.Builder builder =
                    mUnderlyingNetworkRecordBuilders.get(network);
            if (builder == null) {
            final UnderlyingNetworkEvaluator evaluator = mUnderlyingNetworkRecords.get(network);
            if (evaluator == null) {
                logWtf("Got capabilities change for unknown key: " + network);
                return;
            }

            builder.setNetworkCapabilities(networkCapabilities);
            if (builder.isValid()) {
            evaluator.setNetworkCapabilities(
                    networkCapabilities,
                    mConnectionConfig.getVcnUnderlyingNetworkPriorities(),
                    mSubscriptionGroup,
                    mLastSnapshot,
                    mCarrierConfig);

            if (evaluator.isValid()) {
                reevaluateNetworks();
            }
        }
@@ -526,30 +559,40 @@ public class UnderlyingNetworkController {
        @Override
        public void onLinkPropertiesChanged(
                @NonNull Network network, @NonNull LinkProperties linkProperties) {
            final UnderlyingNetworkRecord.Builder builder =
                    mUnderlyingNetworkRecordBuilders.get(network);
            if (builder == null) {
            final UnderlyingNetworkEvaluator evaluator = mUnderlyingNetworkRecords.get(network);
            if (evaluator == null) {
                logWtf("Got link properties change for unknown key: " + network);
                return;
            }

            builder.setLinkProperties(linkProperties);
            if (builder.isValid()) {
            evaluator.setLinkProperties(
                    linkProperties,
                    mConnectionConfig.getVcnUnderlyingNetworkPriorities(),
                    mSubscriptionGroup,
                    mLastSnapshot,
                    mCarrierConfig);

            if (evaluator.isValid()) {
                reevaluateNetworks();
            }
        }

        @Override
        public void onBlockedStatusChanged(@NonNull Network network, boolean isBlocked) {
            final UnderlyingNetworkRecord.Builder builder =
                    mUnderlyingNetworkRecordBuilders.get(network);
            if (builder == null) {
            final UnderlyingNetworkEvaluator evaluator = mUnderlyingNetworkRecords.get(network);
            if (evaluator == null) {
                logWtf("Got blocked status change for unknown key: " + network);
                return;
            }

            builder.setIsBlocked(isBlocked);
            if (builder.isValid()) {
            evaluator.setIsBlocked(
                    isBlocked,
                    mConnectionConfig.getVcnUnderlyingNetworkPriorities(),
                    mSubscriptionGroup,
                    mLastSnapshot,
                    mCarrierConfig);

            if (evaluator.isValid()) {
                reevaluateNetworks();
            }
        }
@@ -614,16 +657,8 @@ public class UnderlyingNetworkController {
        pw.println("Underlying networks:");
        pw.increaseIndent();
        if (mRouteSelectionCallback != null) {
            for (UnderlyingNetworkRecord record :
                    mRouteSelectionCallback.getSortedUnderlyingNetworks()) {
                record.dump(
                        mVcnContext,
                        pw,
                        mConnectionConfig.getVcnUnderlyingNetworkPriorities(),
                        mSubscriptionGroup,
                        mLastSnapshot,
                        mCurrentRecord,
                        mCarrierConfig);
            for (UnderlyingNetworkEvaluator recordEvaluator : getSortedUnderlyingNetworks()) {
                recordEvaluator.dump(pw);
            }
        }
        pw.decreaseIndent();
@@ -653,5 +688,23 @@ public class UnderlyingNetworkController {
                @Nullable UnderlyingNetworkRecord underlyingNetworkRecord);
    }

    private static class Dependencies {}
    @VisibleForTesting(visibility = Visibility.PRIVATE)
    public static class Dependencies {
        /** Construct a new UnderlyingNetworkEvaluator */
        public UnderlyingNetworkEvaluator newUnderlyingNetworkEvaluator(
                @NonNull VcnContext vcnContext,
                @NonNull Network network,
                @NonNull List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates,
                @NonNull ParcelUuid subscriptionGroup,
                @NonNull TelephonySubscriptionSnapshot lastSnapshot,
                @Nullable PersistableBundleWrapper carrierConfig) {
            return new UnderlyingNetworkEvaluator(
                    vcnContext,
                    network,
                    underlyingNetworkTemplates,
                    subscriptionGroup,
                    lastSnapshot,
                    carrierConfig);
        }
    }
}
+217 −0

File added.

Preview size limit exceeded, changes collapsed.

+11 −114
Original line number Diff line number Diff line
@@ -16,24 +16,17 @@

package com.android.server.vcn.routeselection;

import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.vcn.VcnUnderlyingNetworkTemplate;
import android.os.ParcelUuid;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import com.android.server.vcn.VcnContext;

import java.util.Comparator;
import java.util.List;
import java.util.Objects;

/**
@@ -46,54 +39,17 @@ public class UnderlyingNetworkRecord {
    @NonNull public final NetworkCapabilities networkCapabilities;
    @NonNull public final LinkProperties linkProperties;
    public final boolean isBlocked;
    public final boolean isSelected;
    public final int priorityClass;

    @VisibleForTesting(visibility = Visibility.PRIVATE)
    public UnderlyingNetworkRecord(
            @NonNull Network network,
            @NonNull NetworkCapabilities networkCapabilities,
            @NonNull LinkProperties linkProperties,
            boolean isBlocked,
            VcnContext vcnContext,
            List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates,
            ParcelUuid subscriptionGroup,
            TelephonySubscriptionSnapshot snapshot,
            UnderlyingNetworkRecord currentlySelected,
            PersistableBundleWrapper carrierConfig) {
            boolean isBlocked) {
        this.network = network;
        this.networkCapabilities = networkCapabilities;
        this.linkProperties = linkProperties;
        this.isBlocked = isBlocked;

        this.isSelected = isSelected(this.network, currentlySelected);

        priorityClass =
                NetworkPriorityClassifier.calculatePriorityClass(
                        vcnContext,
                        this,
                        underlyingNetworkTemplates,
                        subscriptionGroup,
                        snapshot,
                        currentlySelected,
                        carrierConfig);
    }

    @VisibleForTesting(visibility = Visibility.PRIVATE)
    public UnderlyingNetworkRecord(
            @NonNull Network network,
            @NonNull NetworkCapabilities networkCapabilities,
            @NonNull LinkProperties linkProperties,
            boolean isBlocked,
            boolean isSelected,
            int priorityClass) {
        this.network = network;
        this.networkCapabilities = networkCapabilities;
        this.linkProperties = linkProperties;
        this.isBlocked = isBlocked;
        this.isSelected = isSelected;

        this.priorityClass = priorityClass;
    }

    @Override
@@ -113,64 +69,20 @@ public class UnderlyingNetworkRecord {
        return Objects.hash(network, networkCapabilities, linkProperties, isBlocked);
    }

    /** Returns if two records are equal including their priority classes. */
    public static boolean isEqualIncludingPriorities(
            UnderlyingNetworkRecord left, UnderlyingNetworkRecord right) {
        if (left != null && right != null) {
            return left.equals(right)
                    && left.isSelected == right.isSelected
                    && left.priorityClass == right.priorityClass;
        }

        return left == right;
    }

    static Comparator<UnderlyingNetworkRecord> getComparator() {
        return (left, right) -> {
            final int leftIndex = left.priorityClass;
            final int rightIndex = right.priorityClass;

            // In the case of networks in the same priority class, prioritize based on other
            // criteria (eg. actively selected network, link metrics, etc)
            if (leftIndex == rightIndex) {
                // TODO: Improve the strategy of network selection when both UnderlyingNetworkRecord
                // fall into the same priority class.
                if (left.isSelected) {
                    return -1;
                }
                if (right.isSelected) {
                    return 1;
                }
            }
            return Integer.compare(leftIndex, rightIndex);
        };
    }

    private static boolean isSelected(
            Network networkToCheck, UnderlyingNetworkRecord currentlySelected) {
        if (currentlySelected == null) {
            return false;
        }
        if (currentlySelected.network.equals(networkToCheck)) {
            return true;
        }
        return false;
    /** Return whether two records represent the same network */
    public static boolean isSameNetwork(
            @Nullable UnderlyingNetworkRecord leftRecord,
            @Nullable UnderlyingNetworkRecord rightRecord) {
        final Network left = leftRecord == null ? null : leftRecord.network;
        final Network right = rightRecord == null ? null : rightRecord.network;
        return Objects.equals(left, right);
    }

    /** Dumps the state of this record for logging and debugging purposes. */
    void dump(
            VcnContext vcnContext,
            IndentingPrintWriter pw,
            List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates,
            ParcelUuid subscriptionGroup,
            TelephonySubscriptionSnapshot snapshot,
            UnderlyingNetworkRecord currentlySelected,
            PersistableBundleWrapper carrierConfig) {
    void dump(IndentingPrintWriter pw) {
        pw.println("UnderlyingNetworkRecord:");
        pw.increaseIndent();

        pw.println("priorityClass: " + priorityClass);
        pw.println("isSelected: " + isSelected);
        pw.println("mNetwork: " + network);
        pw.println("mNetworkCapabilities: " + networkCapabilities);
        pw.println("mLinkProperties: " + linkProperties);
@@ -218,29 +130,14 @@ public class UnderlyingNetworkRecord {
            return mNetworkCapabilities != null && mLinkProperties != null && mWasIsBlockedSet;
        }

        UnderlyingNetworkRecord build(
                VcnContext vcnContext,
                List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates,
                ParcelUuid subscriptionGroup,
                TelephonySubscriptionSnapshot snapshot,
                UnderlyingNetworkRecord currentlySelected,
                PersistableBundleWrapper carrierConfig) {
        UnderlyingNetworkRecord build() {
            if (!isValid()) {
                throw new IllegalArgumentException(
                        "Called build before UnderlyingNetworkRecord was valid");
            }

            return new UnderlyingNetworkRecord(
                    mNetwork,
                    mNetworkCapabilities,
                    mLinkProperties,
                    mIsBlocked,
                    vcnContext,
                    underlyingNetworkTemplates,
                    subscriptionGroup,
                    snapshot,
                    currentlySelected,
                    carrierConfig);
                    mNetwork, mNetworkCapabilities, mLinkProperties, mIsBlocked);
        }
    }
}
Loading