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

Commit 8e2fe256 authored by Yan Yan's avatar Yan Yan Committed by Automerger Merge Worker
Browse files

Merge changes I6eca0331,I346323cb am: c9af6cf3 am: 63dde898 am: 9b88d26d

parents 41389ccd 9b88d26d
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -353,6 +353,11 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork
        return mCapabilitiesMatchCriteria.get(NET_CAPABILITY_RCS);
    }

    /** @hide */
    public Map<Integer, Integer> getCapabilitiesMatchCriteria() {
        return Collections.unmodifiableMap(new HashMap<>(mCapabilitiesMatchCriteria));
    }

    @Override
    public int hashCode() {
        return Objects.hash(
+39 −5
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */
package com.android.server.vcn.routeselection;

import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -45,6 +46,7 @@ import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscription
import com.android.server.vcn.VcnContext;

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

@@ -69,9 +71,23 @@ class NetworkPriorityClassifier {
    @VisibleForTesting(visibility = Visibility.PRIVATE)
    static final int WIFI_EXIT_RSSI_THRESHOLD_DEFAULT = -74;

    /** Priority for any other networks (including unvalidated, etc) */
    /**
     * Priority for networks that VCN can fall back to.
     *
     * <p>If none of the network candidates are validated or match any template, VCN will fall back
     * to any INTERNET network.
     */
    @VisibleForTesting(visibility = Visibility.PRIVATE)
    static final int PRIORITY_ANY = Integer.MAX_VALUE;
    static final int PRIORITY_FALLBACK = Integer.MAX_VALUE;

    /**
     * Priority for networks that cannot be selected as VCN's underlying networks.
     *
     * <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 */
    public static int calculatePriorityClass(
@@ -86,12 +102,12 @@ class NetworkPriorityClassifier {

        if (networkRecord.isBlocked) {
            logWtf("Network blocked for System Server: " + networkRecord.network);
            return PRIORITY_ANY;
            return PRIORITY_INVALID;
        }

        if (snapshot == null) {
            logWtf("Got null snapshot");
            return PRIORITY_ANY;
            return PRIORITY_INVALID;
        }

        int priorityIndex = 0;
@@ -108,7 +124,13 @@ class NetworkPriorityClassifier {
            }
            priorityIndex++;
        }
        return PRIORITY_ANY;

        final NetworkCapabilities caps = networkRecord.networkCapabilities;
        if (caps.hasCapability(NET_CAPABILITY_INTERNET)
                || (vcnContext.isInTestMode() && caps.hasTransport(TRANSPORT_TEST))) {
            return PRIORITY_FALLBACK;
        }
        return PRIORITY_INVALID;
    }

    @VisibleForTesting(visibility = Visibility.PRIVATE)
@@ -297,6 +319,18 @@ class NetworkPriorityClassifier {
            return false;
        }

        for (Map.Entry<Integer, Integer> entry :
                networkPriority.getCapabilitiesMatchCriteria().entrySet()) {
            final int cap = entry.getKey();
            final int matchCriteria = entry.getValue();

            if (matchCriteria == MATCH_REQUIRED && !caps.hasCapability(cap)) {
                return false;
            } else if (matchCriteria == MATCH_FORBIDDEN && caps.hasCapability(cap)) {
                return false;
            }
        }

        return true;
    }

+111 −29
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.server.vcn.routeselection;

import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY;
import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN;
import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED;
import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener;

import static com.android.server.VcnManagementService.LOCAL_LOG;
@@ -32,6 +35,7 @@ import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.TelephonyNetworkSpecifier;
import android.net.vcn.VcnCellUnderlyingNetworkTemplate;
import android.net.vcn.VcnGatewayConnectionConfig;
import android.net.vcn.VcnUnderlyingNetworkTemplate;
import android.os.Handler;
@@ -40,6 +44,7 @@ import android.os.ParcelUuid;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;

import com.android.internal.annotations.VisibleForTesting;
@@ -49,6 +54,7 @@ import com.android.server.vcn.VcnContext;
import com.android.server.vcn.util.LogUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -126,6 +132,63 @@ public class UnderlyingNetworkController {
        registerOrUpdateNetworkRequests();
    }

    private static class CapabilityMatchCriteria {
        public final int capability;
        public final int matchCriteria;

        CapabilityMatchCriteria(int capability, int matchCriteria) {
            this.capability = capability;
            this.matchCriteria = matchCriteria;
        }

        @Override
        public int hashCode() {
            return Objects.hash(capability, matchCriteria);
        }

        @Override
        public boolean equals(@Nullable Object other) {
            if (!(other instanceof CapabilityMatchCriteria)) {
                return false;
            }

            final CapabilityMatchCriteria rhs = (CapabilityMatchCriteria) other;
            return capability == rhs.capability && matchCriteria == rhs.matchCriteria;
        }
    }

    private static Set<Set<CapabilityMatchCriteria>> dedupAndGetCapRequirementsForCell(
            VcnGatewayConnectionConfig connectionConfig) {
        final Set<Set<CapabilityMatchCriteria>> dedupedCapsMatchSets = new ArraySet<>();

        for (VcnUnderlyingNetworkTemplate template :
                connectionConfig.getVcnUnderlyingNetworkPriorities()) {
            if (template instanceof VcnCellUnderlyingNetworkTemplate) {
                final Set<CapabilityMatchCriteria> capsMatchSet = new ArraySet<>();

                for (Map.Entry<Integer, Integer> entry :
                        ((VcnCellUnderlyingNetworkTemplate) template)
                                .getCapabilitiesMatchCriteria()
                                .entrySet()) {

                    final int capability = entry.getKey();
                    final int matchCriteria = entry.getValue();
                    if (matchCriteria != MATCH_ANY) {
                        capsMatchSet.add(new CapabilityMatchCriteria(capability, matchCriteria));
                    }
                }

                dedupedCapsMatchSets.add(capsMatchSet);
            }
        }

        dedupedCapsMatchSets.add(
                Collections.singleton(
                        new CapabilityMatchCriteria(
                                NetworkCapabilities.NET_CAPABILITY_INTERNET, MATCH_REQUIRED)));
        return dedupedCapsMatchSets;
    }

    private void registerOrUpdateNetworkRequests() {
        NetworkCallback oldRouteSelectionCallback = mRouteSelectionCallback;
        NetworkCallback oldWifiCallback = mWifiBringupCallback;
@@ -158,11 +221,14 @@ public class UnderlyingNetworkController {
                    getWifiNetworkRequest(), mWifiBringupCallback, mHandler);

            for (final int subId : mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) {
                for (Set<CapabilityMatchCriteria> capsMatchCriteria :
                        dedupAndGetCapRequirementsForCell(mConnectionConfig)) {
                    final NetworkBringupCallback cb = new NetworkBringupCallback();
                    mCellBringupCallbacks.add(cb);

                    mConnectivityManager.requestBackgroundNetwork(
                        getCellNetworkRequestForSubId(subId), cb, mHandler);
                            getCellNetworkRequestForSubId(subId, capsMatchCriteria), cb, mHandler);
                }
            }
        } else {
            mRouteSelectionCallback = null;
@@ -214,6 +280,13 @@ public class UnderlyingNetworkController {
                .build();
    }

    private NetworkRequest.Builder getBaseWifiNetworkRequestBuilder() {
        return getBaseNetworkRequestBuilder()
                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup));
    }

    /**
     * Builds the WiFi bringup request
     *
@@ -224,10 +297,7 @@ public class UnderlyingNetworkController {
     * but will NEVER bring up a Carrier WiFi network itself.
     */
    private NetworkRequest getWifiNetworkRequest() {
        return getBaseNetworkRequestBuilder()
                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))
                .build();
        return getBaseWifiNetworkRequestBuilder().build();
    }

    /**
@@ -238,9 +308,7 @@ public class UnderlyingNetworkController {
     * pace to effectively select a short-lived WiFi offload network.
     */
    private NetworkRequest getWifiEntryRssiThresholdNetworkRequest() {
        return getBaseNetworkRequestBuilder()
                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))
        return getBaseWifiNetworkRequestBuilder()
                // Ensure wifi updates signal strengths when crossing this threshold.
                .setSignalStrength(getWifiEntryRssiThreshold(mCarrierConfig))
                .build();
@@ -254,9 +322,7 @@ public class UnderlyingNetworkController {
     * pace to effectively select away from a failing WiFi network.
     */
    private NetworkRequest getWifiExitRssiThresholdNetworkRequest() {
        return getBaseNetworkRequestBuilder()
                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))
        return getBaseWifiNetworkRequestBuilder()
                // Ensure wifi updates signal strengths when crossing this threshold.
                .setSignalStrength(getWifiExitRssiThreshold(mCarrierConfig))
                .build();
@@ -273,11 +339,25 @@ public class UnderlyingNetworkController {
     * <p>Since this request MUST make it to the TelephonyNetworkFactory, subIds are not specified
     * in the NetworkCapabilities, but rather in the TelephonyNetworkSpecifier.
     */
    private NetworkRequest getCellNetworkRequestForSubId(int subId) {
        return getBaseNetworkRequestBuilder()
    private NetworkRequest getCellNetworkRequestForSubId(
            int subId, Set<CapabilityMatchCriteria> capsMatchCriteria) {
        final NetworkRequest.Builder nrBuilder =
                getBaseNetworkRequestBuilder()
                        .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId))
                .build();
                        .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId));

        for (CapabilityMatchCriteria capMatchCriteria : capsMatchCriteria) {
            final int cap = capMatchCriteria.capability;
            final int matchCriteria = capMatchCriteria.matchCriteria;

            if (matchCriteria == MATCH_REQUIRED) {
                nrBuilder.addCapability(cap);
            } else if (matchCriteria == MATCH_FORBIDDEN) {
                nrBuilder.addForbiddenCapability(cap);
            }
        }

        return nrBuilder.build();
    }

    /**
@@ -285,7 +365,6 @@ public class UnderlyingNetworkController {
     */
    private NetworkRequest.Builder getBaseNetworkRequestBuilder() {
        return new NetworkRequest.Builder()
                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
                .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
                .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
@@ -356,7 +435,7 @@ public class UnderlyingNetworkController {
            if (!allNetworkPriorities.isEmpty()) {
                allNetworkPriorities += ", ";
            }
            allNetworkPriorities += record.network + ": " + record.getPriorityClass();
            allNetworkPriorities += record.network + ": " + record.priorityClass;
        }
        logInfo(
                "Selected network changed to "
@@ -393,19 +472,22 @@ public class UnderlyingNetworkController {

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

            for (UnderlyingNetworkRecord.Builder builder :
                    mUnderlyingNetworkRecordBuilders.values()) {
                if (builder.isValid()) {
                    final UnderlyingNetworkRecord record =
                            builder.build(
                                    mVcnContext,
                                    mConnectionConfig.getVcnUnderlyingNetworkPriorities(),
                                    mSubscriptionGroup,
                                    mLastSnapshot,
                                    mCurrentRecord,
                                    mCarrierConfig));

            for (UnderlyingNetworkRecord.Builder builder :
                    mUnderlyingNetworkRecordBuilders.values()) {
                if (builder.isValid()) {
                    sorted.add(builder.build());
                                    mCarrierConfig);
                    if (record.priorityClass != NetworkPriorityClassifier.PRIORITY_INVALID) {
                        sorted.add(record);
                    }
                }
            }

+72 −78
Original line number Diff line number Diff line
@@ -42,37 +42,33 @@ import java.util.Objects;
 * @hide
 */
public class UnderlyingNetworkRecord {
    private static final int PRIORITY_CLASS_INVALID = Integer.MAX_VALUE;

    @NonNull public final Network network;
    @NonNull public final NetworkCapabilities networkCapabilities;
    @NonNull public final LinkProperties linkProperties;
    public final boolean isBlocked;

    private int mPriorityClass = PRIORITY_CLASS_INVALID;
    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) {
        this.network = network;
        this.networkCapabilities = networkCapabilities;
        this.linkProperties = linkProperties;
        this.isBlocked = isBlocked;
    }

    private int getOrCalculatePriorityClass(
            boolean isBlocked,
            VcnContext vcnContext,
            List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates,
            ParcelUuid subscriptionGroup,
            TelephonySubscriptionSnapshot snapshot,
            UnderlyingNetworkRecord currentlySelected,
            PersistableBundleWrapper carrierConfig) {
        // Never changes after the underlying network record is created.
        if (mPriorityClass == PRIORITY_CLASS_INVALID) {
            mPriorityClass =
        this.network = network;
        this.networkCapabilities = networkCapabilities;
        this.linkProperties = linkProperties;
        this.isBlocked = isBlocked;

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

        priorityClass =
                NetworkPriorityClassifier.calculatePriorityClass(
                        vcnContext,
                        this,
@@ -83,12 +79,21 @@ public class UnderlyingNetworkRecord {
                        carrierConfig);
    }

        return mPriorityClass;
    }
    @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;

    // Used in UnderlyingNetworkController
    int getPriorityClass() {
        return mPriorityClass;
        this.priorityClass = priorityClass;
    }

    @Override
@@ -108,40 +113,32 @@ public class UnderlyingNetworkRecord {
        return Objects.hash(network, networkCapabilities, linkProperties, isBlocked);
    }

    static Comparator<UnderlyingNetworkRecord> getComparator(
            VcnContext vcnContext,
            List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates,
            ParcelUuid subscriptionGroup,
            TelephonySubscriptionSnapshot snapshot,
            UnderlyingNetworkRecord currentlySelected,
            PersistableBundleWrapper carrierConfig) {
    /** 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.getOrCalculatePriorityClass(
                            vcnContext,
                            underlyingNetworkTemplates,
                            subscriptionGroup,
                            snapshot,
                            currentlySelected,
                            carrierConfig);
            final int rightIndex =
                    right.getOrCalculatePriorityClass(
                            vcnContext,
                            underlyingNetworkTemplates,
                            subscriptionGroup,
                            snapshot,
                            currentlySelected,
                            carrierConfig);
            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 (isSelected(left, currentlySelected)) {
                if (left.isSelected) {
                    return -1;
                }
                if (isSelected(left, currentlySelected)) {
                if (right.isSelected) {
                    return 1;
                }
            }
@@ -150,11 +147,11 @@ public class UnderlyingNetworkRecord {
    }

    private static boolean isSelected(
            UnderlyingNetworkRecord recordToCheck, UnderlyingNetworkRecord currentlySelected) {
            Network networkToCheck, UnderlyingNetworkRecord currentlySelected) {
        if (currentlySelected == null) {
            return false;
        }
        if (currentlySelected.network == recordToCheck.network) {
        if (currentlySelected.network.equals(networkToCheck)) {
            return true;
        }
        return false;
@@ -172,16 +169,8 @@ public class UnderlyingNetworkRecord {
        pw.println("UnderlyingNetworkRecord:");
        pw.increaseIndent();

        final int priorityIndex =
                getOrCalculatePriorityClass(
                        vcnContext,
                        underlyingNetworkTemplates,
                        subscriptionGroup,
                        snapshot,
                        currentlySelected,
                        carrierConfig);

        pw.println("Priority index: " + priorityIndex);
        pw.println("priorityClass: " + priorityClass);
        pw.println("isSelected: " + isSelected);
        pw.println("mNetwork: " + network);
        pw.println("mNetworkCapabilities: " + networkCapabilities);
        pw.println("mLinkProperties: " + linkProperties);
@@ -198,8 +187,6 @@ public class UnderlyingNetworkRecord {
        boolean mIsBlocked;
        boolean mWasIsBlockedSet;

        @Nullable private UnderlyingNetworkRecord mCached;

        Builder(@NonNull Network network) {
            mNetwork = network;
        }
@@ -211,7 +198,6 @@ public class UnderlyingNetworkRecord {

        void setNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) {
            mNetworkCapabilities = networkCapabilities;
            mCached = null;
        }

        @Nullable
@@ -221,32 +207,40 @@ public class UnderlyingNetworkRecord {

        void setLinkProperties(@NonNull LinkProperties linkProperties) {
            mLinkProperties = linkProperties;
            mCached = null;
        }

        void setIsBlocked(boolean isBlocked) {
            mIsBlocked = isBlocked;
            mWasIsBlockedSet = true;
            mCached = null;
        }

        boolean isValid() {
            return mNetworkCapabilities != null && mLinkProperties != null && mWasIsBlockedSet;
        }

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

            if (mCached == null) {
                mCached =
                        new UnderlyingNetworkRecord(
                                mNetwork, mNetworkCapabilities, mLinkProperties, mIsBlocked);
            }

            return mCached;
            return new UnderlyingNetworkRecord(
                    mNetwork,
                    mNetworkCapabilities,
                    mLinkProperties,
                    mIsBlocked,
                    vcnContext,
                    underlyingNetworkTemplates,
                    subscriptionGroup,
                    snapshot,
                    currentlySelected,
                    carrierConfig);
        }
    }
}
+2 −1
Original line number Diff line number Diff line
@@ -32,7 +32,8 @@ public class VcnCellUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTe
    private static final Set<String> ALLOWED_PLMN_IDS = new HashSet<>();
    private static final Set<Integer> ALLOWED_CARRIER_IDS = new HashSet<>();

    private static VcnCellUnderlyingNetworkTemplate.Builder getTestNetworkTemplateBuilder() {
    // Public for use in UnderlyingNetworkControllerTest
    public static VcnCellUnderlyingNetworkTemplate.Builder getTestNetworkTemplateBuilder() {
        return new VcnCellUnderlyingNetworkTemplate.Builder()
                .setMetered(MATCH_FORBIDDEN)
                .setMinUpstreamBandwidthKbps(
Loading