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

Commit 59634a7f authored by Chalard Jean's avatar Chalard Jean Committed by Android (Google) Code Review
Browse files

Merge changes Id7ee1bd3,I5ea44a94 into sc-dev

* changes:
  [NS08] Expose public NetworkScore API
  [NS07] Add the rest of the scoring policy
parents a154af88 8f98eb9c
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -341,6 +341,8 @@ package android.net {
    method public int describeContents();
    method public int getKeepConnectedReason();
    method public int getLegacyInt();
    method public boolean isExiting();
    method public boolean isTransportPrimary();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkScore> CREATOR;
    field public static final int KEEP_CONNECTED_FOR_HANDOVER = 1; // 0x1
@@ -350,8 +352,10 @@ package android.net {
  public static final class NetworkScore.Builder {
    ctor public NetworkScore.Builder();
    method @NonNull public android.net.NetworkScore build();
    method @NonNull public android.net.NetworkScore.Builder setExiting(boolean);
    method @NonNull public android.net.NetworkScore.Builder setKeepConnectedReason(int);
    method @NonNull public android.net.NetworkScore.Builder setLegacyInt(int);
    method @NonNull public android.net.NetworkScore.Builder setTransportPrimary(boolean);
  }

  public final class OemNetworkPreferences implements android.os.Parcelable {
+144 −4
Original line number Diff line number Diff line
@@ -52,11 +52,27 @@ public final class NetworkScore implements Parcelable {
    public static final int KEEP_CONNECTED_FOR_HANDOVER = 1;

    // Agent-managed policies
    // TODO : add them here, starting from 1
    // This network should lose to a wifi that has ever been validated
    // NOTE : temporarily this policy is managed by ConnectivityService, because of legacy. The
    // legacy design has this bit global to the system and tacked on WiFi which means it will affect
    // networks from carriers who don't want it and non-carrier networks, which is bad for users.
    // The S design has this on mobile networks only, so this can be fixed eventually ; as CS
    // doesn't know what carriers need this bit, the initial S implementation will continue to
    // affect other carriers but will at least leave non-mobile networks alone. Eventually Telephony
    // should set this on networks from carriers that require it.
    /** @hide */
    public static final int MIN_AGENT_MANAGED_POLICY = 0;
    public static final int POLICY_YIELD_TO_BAD_WIFI = 1;
    // This network is primary for this transport.
    /** @hide */
    public static final int MAX_AGENT_MANAGED_POLICY = -1;
    public static final int POLICY_TRANSPORT_PRIMARY = 2;
    // This network is exiting : it will likely disconnect in a few seconds.
    /** @hide */
    public static final int POLICY_EXITING = 3;

    /** @hide */
    public static final int MIN_AGENT_MANAGED_POLICY = POLICY_YIELD_TO_BAD_WIFI;
    /** @hide */
    public static final int MAX_AGENT_MANAGED_POLICY = POLICY_EXITING;

    // Bitmask of all the policies applied to this score.
    private final long mPolicies;
@@ -98,6 +114,60 @@ public final class NetworkScore implements Parcelable {
        return 0 != (mPolicies & (1L << policy));
    }

    /**
     * To the exclusive usage of FullScore
     * @hide
     */
    public long getPolicies() {
        return mPolicies;
    }

    /**
     * Whether this network should yield to a previously validated wifi gone bad.
     *
     * If this policy is set, other things being equal, the device will prefer a previously
     * validated WiFi even if this network is validated and the WiFi is not.
     * If this policy is not set, the device prefers the validated network.
     *
     * @hide
     */
    // TODO : Unhide this for telephony and have telephony call it on the relevant carriers.
    // In the mean time this is handled by Connectivity in a backward-compatible manner.
    public boolean shouldYieldToBadWifi() {
        return hasPolicy(POLICY_YIELD_TO_BAD_WIFI);
    }

    /**
     * Whether this network is primary for this transport.
     *
     * When multiple networks of the same transport are active, the device prefers the ones that
     * are primary. This is meant in particular for DS-DA devices with a user setting to choose the
     * default SIM card, or for WiFi STA+STA and make-before-break cases.
     *
     * @hide
     */
    @SystemApi
    public boolean isTransportPrimary() {
        return hasPolicy(POLICY_TRANSPORT_PRIMARY);
    }

    /**
     * Whether this network is exiting.
     *
     * If this policy is set, the device will expect this network to disconnect within seconds.
     * It will try to migrate to some other network if any is available, policy permitting, to
     * avoid service disruption.
     * This is useful in particular when a good cellular network is available and WiFi is getting
     * weak and risks disconnecting soon. The WiFi network should be marked as exiting so that
     * the device will prefer the reliable mobile network over this soon-to-be-lost WiFi.
     *
     * @hide
     */
    @SystemApi
    public boolean isExiting() {
        return hasPolicy(POLICY_EXITING);
    }

    @Override
    public String toString() {
        return "Score(" + mLegacyInt + ")";
@@ -137,6 +207,7 @@ public final class NetworkScore implements Parcelable {
        private static final int INVALID_LEGACY_INT = Integer.MIN_VALUE;
        private int mLegacyInt = INVALID_LEGACY_INT;
        private int mKeepConnectedReason = KEEP_CONNECTED_NONE;
        private int mPolicies = 0;

        /**
         * Sets the legacy int for this score.
@@ -152,6 +223,75 @@ public final class NetworkScore implements Parcelable {
            return this;
        }


        /**
         * Set for a network that should never be preferred to a wifi that has ever been validated
         *
         * If this policy is set, other things being equal, the device will prefer a previously
         * validated WiFi even if this network is validated and the WiFi is not.
         * If this policy is not set, the device prefers the validated network.
         *
         * @return this builder
         * @hide
         */
        // TODO : Unhide this for telephony and have telephony call it on the relevant carriers.
        // In the mean time this is handled by Connectivity in a backward-compatible manner.
        @NonNull
        public Builder setShouldYieldToBadWifi(final boolean val) {
            if (val) {
                mPolicies |= (1L << POLICY_YIELD_TO_BAD_WIFI);
            } else {
                mPolicies &= ~(1L << POLICY_YIELD_TO_BAD_WIFI);
            }
            return this;
        }

        /**
         * Set for a network that is primary for this transport.
         *
         * When multiple networks of the same transport are active, the device prefers the ones that
         * are primary. This is meant in particular for DS-DA devices with a user setting to choose
         * the default SIM card, or for WiFi STA+STA and make-before-break cases.
         *
         * @return this builder
         * @hide
         */
        @SystemApi
        @NonNull
        public Builder setTransportPrimary(final boolean val) {
            if (val) {
                mPolicies |= (1L << POLICY_TRANSPORT_PRIMARY);
            } else {
                mPolicies &= ~(1L << POLICY_TRANSPORT_PRIMARY);
            }
            return this;
        }

        /**
         * Set for a network that will likely disconnect in a few seconds.
         *
         * If this policy is set, the device will expect this network to disconnect within seconds.
         * It will try to migrate to some other network if any is available, policy permitting, to
         * avoid service disruption.
         * This is useful in particular when a good cellular network is available and WiFi is
         * getting weak and risks disconnecting soon. The WiFi network should be marked as exiting
         * so that the device will prefer the reliable mobile network over this soon-to-be-lost
         * WiFi.
         *
         * @return this builder
         * @hide
         */
        @SystemApi
        @NonNull
        public Builder setExiting(final boolean val) {
            if (val) {
                mPolicies |= (1L << POLICY_EXITING);
            } else {
                mPolicies &= ~(1L << POLICY_EXITING);
            }
            return this;
        }

        /**
         * Set the keep-connected reason.
         *
@@ -169,7 +309,7 @@ public final class NetworkScore implements Parcelable {
         */
        @NonNull
        public NetworkScore build() {
            return new NetworkScore(mLegacyInt, POLICY_NONE, mKeepConnectedReason);
            return new NetworkScore(mLegacyInt, mPolicies, mKeepConnectedReason);
        }
    }
}
+5 −3
Original line number Diff line number Diff line
@@ -1329,7 +1329,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
        mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit);

        mMultinetworkPolicyTracker = mDeps.makeMultinetworkPolicyTracker(
                mContext, mHandler, () -> rematchForAvoidBadWifiUpdate());
                mContext, mHandler, () -> updateAvoidBadWifi());
        mMultinetworkPolicyTracker.start();

        mDnsManager = new DnsManager(mContext, mDnsResolver);
@@ -4389,8 +4389,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
        return avoidBadWifi();
    }

    // TODO : this function is now useless.
    private void rematchForAvoidBadWifiUpdate() {
    private void updateAvoidBadWifi() {
        for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
            nai.updateScoreForNetworkAgentConfigUpdate();
        }
        rematchAllNetworksAndRequests();
    }

+60 −15
Original line number Diff line number Diff line
@@ -17,9 +17,13 @@
package com.android.server.connectivity;

import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkScore.KEEP_CONNECTED_NONE;
import static android.net.NetworkScore.POLICY_EXITING;
import static android.net.NetworkScore.POLICY_TRANSPORT_PRIMARY;
import static android.net.NetworkScore.POLICY_YIELD_TO_BAD_WIFI;

import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -52,7 +56,8 @@ public class FullScore {
            POLICY_IS_VALIDATED,
            POLICY_IS_VPN,
            POLICY_EVER_USER_SELECTED,
            POLICY_ACCEPT_UNVALIDATED
            POLICY_ACCEPT_UNVALIDATED,
            POLICY_IS_UNMETERED
    })
    public @interface Policy {
    }
@@ -77,12 +82,22 @@ public class FullScore {
    /** @hide */
    public static final int POLICY_ACCEPT_UNVALIDATED = 60;

    // This network is unmetered. {@see NetworkCapabilities.NET_CAPABILITY_NOT_METERED}.
    /** @hide */
    public static final int POLICY_IS_UNMETERED = 59;

    // To help iterate when printing
    @VisibleForTesting
    static final int MIN_CS_MANAGED_POLICY = POLICY_ACCEPT_UNVALIDATED;
    static final int MIN_CS_MANAGED_POLICY = POLICY_IS_UNMETERED;
    @VisibleForTesting
    static final int MAX_CS_MANAGED_POLICY = POLICY_IS_VALIDATED;

    // Mask for policies in NetworkScore. This should have all bits managed by NetworkScore set
    // and all bits managed by FullScore unset. As bits are handled from 0 up in NetworkScore and
    // from 63 down in FullScore, cut at the 32rd bit for simplicity, but change this if some day
    // there are more than 32 bits handled on either side.
    private static final int EXTERNAL_POLICIES_MASK = 0x0000FFFF;

    @VisibleForTesting
    static @NonNull String policyNameOf(final int policy) {
        switch (policy) {
@@ -90,6 +105,10 @@ public class FullScore {
            case POLICY_IS_VPN: return "IS_VPN";
            case POLICY_EVER_USER_SELECTED: return "EVER_USER_SELECTED";
            case POLICY_ACCEPT_UNVALIDATED: return "ACCEPT_UNVALIDATED";
            case POLICY_IS_UNMETERED: return "IS_UNMETERED";
            case POLICY_YIELD_TO_BAD_WIFI: return "YIELD_TO_BAD_WIFI";
            case POLICY_TRANSPORT_PRIMARY: return "TRANSPORT_PRIMARY";
            case POLICY_EXITING: return "EXITING";
        }
        throw new IllegalArgumentException("Unknown policy : " + policy);
    }
@@ -112,15 +131,23 @@ public class FullScore {
     * @param score the score supplied by the agent
     * @param caps the NetworkCapabilities of the network
     * @param config the NetworkAgentConfig of the network
     * @return an FullScore that is appropriate to use for ranking.
     * @param yieldToBadWiFi whether this network yields to a previously validated wifi gone bad
     * @return a FullScore that is appropriate to use for ranking.
     */
    // TODO : this shouldn't manage bad wifi avoidance – instead this should be done by the
    // telephony factory, so that it depends on the carrier. For now this is handled by
    // connectivity for backward compatibility.
    public static FullScore fromNetworkScore(@NonNull final NetworkScore score,
            @NonNull final NetworkCapabilities caps, @NonNull final NetworkAgentConfig config) {
        return withPolicies(score.getLegacyInt(), score.getKeepConnectedReason(),
            @NonNull final NetworkCapabilities caps, @NonNull final NetworkAgentConfig config,
            final boolean yieldToBadWiFi) {
        return withPolicies(score.getLegacyInt(), score.getPolicies(),
                score.getKeepConnectedReason(),
                caps.hasCapability(NET_CAPABILITY_VALIDATED),
                caps.hasTransport(TRANSPORT_VPN),
                caps.hasCapability(NET_CAPABILITY_NOT_METERED),
                config.explicitlySelected,
                config.acceptUnvalidated);
                config.acceptUnvalidated,
                yieldToBadWiFi);
    }

    /**
@@ -142,12 +169,17 @@ public class FullScore {
        final boolean mayValidate = caps.hasCapability(NET_CAPABILITY_INTERNET);
        // VPN transports are known in advance.
        final boolean vpn = caps.hasTransport(TRANSPORT_VPN);
        // Prospective scores are always unmetered, because unmetered networks are stronger
        // than metered networks, and it's not known in advance whether the network is metered.
        final boolean unmetered = true;
        // The network hasn't been chosen by the user (yet, at least).
        final boolean everUserSelected = false;
        // Don't assume the user will accept unvalidated connectivity.
        final boolean acceptUnvalidated = false;
        return withPolicies(score.getLegacyInt(), KEEP_CONNECTED_NONE,
                mayValidate, vpn, everUserSelected, acceptUnvalidated);
        // Don't assume clinging to bad wifi
        final boolean yieldToBadWiFi = false;
        return withPolicies(score.getLegacyInt(), score.getPolicies(), KEEP_CONNECTED_NONE,
                mayValidate, vpn, unmetered, everUserSelected, acceptUnvalidated, yieldToBadWiFi);
    }

    /**
@@ -157,26 +189,39 @@ public class FullScore {
     * @param config the NetworkAgentConfig of the network
     * @return a score with the policies from the arguments reset
     */
    // TODO : this shouldn't manage bad wifi avoidance – instead this should be done by the
    // telephony factory, so that it depends on the carrier. For now this is handled by
    // connectivity for backward compatibility.
    public FullScore mixInScore(@NonNull final NetworkCapabilities caps,
            @NonNull final NetworkAgentConfig config) {
        return withPolicies(mLegacyInt, mKeepConnectedReason,
            @NonNull final NetworkAgentConfig config, final boolean avoidBadWiFi) {
        return withPolicies(mLegacyInt, mPolicies, mKeepConnectedReason,
                caps.hasCapability(NET_CAPABILITY_VALIDATED),
                caps.hasTransport(TRANSPORT_VPN),
                caps.hasCapability(NET_CAPABILITY_NOT_METERED),
                config.explicitlySelected,
                config.acceptUnvalidated);
                config.acceptUnvalidated,
                avoidBadWiFi);
    }

    // TODO : this shouldn't manage bad wifi avoidance – instead this should be done by the
    // telephony factory, so that it depends on the carrier. For now this is handled by
    // connectivity for backward compatibility.
    private static FullScore withPolicies(@NonNull final int legacyInt,
            final long externalPolicies,
            @KeepConnectedReason final int keepConnectedReason,
            final boolean isValidated,
            final boolean isVpn,
            final boolean isUnmetered,
            final boolean everUserSelected,
            final boolean acceptUnvalidated) {
        return new FullScore(legacyInt,
                (isValidated         ? 1L << POLICY_IS_VALIDATED : 0)
            final boolean acceptUnvalidated,
            final boolean yieldToBadWiFi) {
        return new FullScore(legacyInt, (externalPolicies & EXTERNAL_POLICIES_MASK)
                | (isValidated       ? 1L << POLICY_IS_VALIDATED : 0)
                | (isVpn             ? 1L << POLICY_IS_VPN : 0)
                | (isUnmetered       ? 1L << POLICY_IS_UNMETERED : 0)
                | (everUserSelected  ? 1L << POLICY_EVER_USER_SELECTED : 0)
                | (acceptUnvalidated ? 1L << POLICY_ACCEPT_UNVALIDATED : 0),
                | (acceptUnvalidated ? 1L << POLICY_ACCEPT_UNVALIDATED : 0)
                | (yieldToBadWiFi    ? 1L << POLICY_YIELD_TO_BAD_WIFI : 0),
                keepConnectedReason);
    }

+13 −15
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.connectivity;

import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.transportNamesOf;

import android.annotation.NonNull;
@@ -362,9 +363,9 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
        linkProperties = lp;
        networkCapabilities = nc;
        networkAgentConfig = config;
        setScore(score); // uses members networkCapabilities and networkAgentConfig
        clatd = new Nat464Xlat(this, netd, dnsResolver, deps);
        mConnService = connService;
        setScore(score); // uses members connService, networkCapabilities and networkAgentConfig
        clatd = new Nat464Xlat(this, netd, dnsResolver, deps);
        mContext = context;
        mHandler = handler;
        this.factorySerialNumber = factorySerialNumber;
@@ -706,7 +707,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
            @NonNull final NetworkCapabilities nc) {
        final NetworkCapabilities oldNc = networkCapabilities;
        networkCapabilities = nc;
        mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig);
        mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig, yieldToBadWiFi());
        final NetworkMonitorManager nm = mNetworkMonitor;
        if (nm != null) {
            nm.notifyNetworkCapabilitiesChanged(nc);
@@ -714,6 +715,11 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
        return oldNc;
    }

    private boolean yieldToBadWiFi() {
        // Only cellular networks yield to bad wifi
        return networkCapabilities.hasTransport(TRANSPORT_CELLULAR) && !mConnService.avoidBadWifi();
    }

    public ConnectivityService connService() {
        return mConnService;
    }
@@ -884,15 +890,6 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
        return isVPN();
    }

    // Return true on devices configured to ignore score penalty for wifi networks
    // that become unvalidated (b/31075769).
    private boolean ignoreWifiUnvalidationPenalty() {
        boolean isWifi = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) &&
                networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
        boolean avoidBadWifi = mConnService.avoidBadWifi() || avoidUnvalidated;
        return isWifi && !avoidBadWifi && everValidated;
    }

    public FullScore getScore() {
        return mScore;
    }
@@ -913,7 +910,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
     * Mix-in the ConnectivityService-managed bits in the score.
     */
    public void setScore(final NetworkScore score) {
        mScore = FullScore.fromNetworkScore(score, networkCapabilities, networkAgentConfig);
        mScore = FullScore.fromNetworkScore(score, networkCapabilities, networkAgentConfig,
                yieldToBadWiFi());
    }

    /**
@@ -922,7 +920,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
     * Call this after updating the network agent config.
     */
    public void updateScoreForNetworkAgentConfigUpdate() {
        mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig);
        mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig, yieldToBadWiFi());
    }

    /**
@@ -1085,7 +1083,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
        return "NetworkAgentInfo{"
                + "network{" + network + "}  handle{" + network.getNetworkHandle() + "}  ni{"
                + networkInfo.toShortString() + "} "
                + "  Score{" + getCurrentScore() + "} "
                + mScore + " "
                + (isNascent() ? " nascent" : (isLingering() ? " lingering" : ""))
                + (everValidated ? " everValidated" : "")
                + (lastValidated ? " lastValidated" : "")
Loading