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

Commit 61642ce8 authored by Robert Greenwalt's avatar Robert Greenwalt Committed by Android (Google) Code Review
Browse files

Merge "Better handling of unvalidated networks." into lmp-dev

parents 69aada9c 2161a8ea
Loading
Loading
Loading
Loading
+90 −52
Original line number Diff line number Diff line
@@ -251,7 +251,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {

    private Context mContext;
    private int mNetworkPreference;
    private int mActiveDefaultNetwork = -1;
    private int mActiveDefaultNetwork = TYPE_NONE;
    // 0 is full bad, 100 is full good
    private int mDefaultInetConditionPublished = 0;

@@ -886,15 +886,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
        return getNetworkInfo(mActiveDefaultNetwork, uid);
    }

    // only called when the default request is satisfied
    private void updateActiveDefaultNetwork(NetworkAgentInfo nai) {
        if (nai != null) {
            mActiveDefaultNetwork = nai.networkInfo.getType();
        } else {
            mActiveDefaultNetwork = TYPE_NONE;
        }
    }

    /**
     * Find the first Provisioning network.
     *
@@ -1936,7 +1927,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                case NetworkMonitor.EVENT_NETWORK_VALIDATED: {
                    NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj;
                    if (isLiveNetworkAgent(nai, "EVENT_NETWORK_VALIDATED")) {
                        handleConnectionValidated(nai);
                        if (DBG) log("Validated " + nai.name());
                        nai.validated = true;
                        rematchNetworkAndRequests(nai);
                    }
                    break;
                }
@@ -2057,7 +2050,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                    if (nri.isRequest == false) continue;
                    NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
                    ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK,
                            (nai != null ? nai.currentScore : 0), 0, nri.request);
                            (nai != null ? nai.getCurrentScore() : 0), 0, nri.request);
                }
            } else {
                loge("Error connecting NetworkFactory");
@@ -2136,7 +2129,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                                request.networkCapabilities.satisfiedByNetworkCapabilities(
                                existing.networkCapabilities) &&
                                (alternative == null ||
                                 alternative.currentScore < existing.currentScore)) {
                                 alternative.getCurrentScore() < existing.getCurrentScore())) {
                            alternative = existing;
                        }
                    }
@@ -2169,8 +2162,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
        for (NetworkAgentInfo network : mNetworkAgentInfos.values()) {
            if (DBG) log("handleRegisterNetworkRequest checking " + network.name());
            if (newCap.satisfiedByNetworkCapabilities(network.networkCapabilities)) {
                if (DBG) log("apparently satisfied.  currentScore=" + network.currentScore);
                if ((bestNetwork == null) || bestNetwork.currentScore < network.currentScore) {
                if (DBG) log("apparently satisfied.  currentScore=" + network.getCurrentScore());
                if ((bestNetwork == null) ||
                        bestNetwork.getCurrentScore() < network.getCurrentScore()) {
                    if (!nri.isRequest) {
                        // Not setting bestNetwork here as a listening NetworkRequest may be
                        // satisfied by multiple Networks.  Instead the request is added to
@@ -2194,7 +2188,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
            bestNetwork.addRequest(nri.request);
            mNetworkForRequestId.put(nri.request.requestId, bestNetwork);
            notifyNetworkCallback(bestNetwork, nri);
            score = bestNetwork.currentScore;
            score = bestNetwork.getCurrentScore();
            if (nri.request.legacyType != TYPE_NONE) {
                mLegacyTypeTracker.add(nri.request.legacyType, bestNetwork);
            }
@@ -4516,19 +4510,34 @@ public class ConnectivityService extends IConnectivityManager.Stub {
        updateTcpBufferSizes(newNetwork);
    }

    private void handleConnectionValidated(NetworkAgentInfo newNetwork) {
        if (newNetwork == null) {
            loge("Unknown NetworkAgentInfo in handleConnectionValidated");
            return;
        }
        if (newNetwork.validated) return;
        newNetwork.validated = true;
    // Handles a network appearing or improving its score.
    //
    // - Evaluates all current NetworkRequests that can be
    //   satisfied by newNetwork, and reassigns to newNetwork
    //   any such requests for which newNetwork is the best.
    //
    // - Tears down any Networks that as a result are no longer
    //   needed. A network is needed if it is the best network for
    //   one or more NetworkRequests, or if it is a VPN.
    //
    // - Tears down newNetwork if it is validated but turns out to be
    //   unneeded. Does not tear down newNetwork if it is
    //   unvalidated, because future validation may improve
    //   newNetwork's score enough that it is needed.
    //
    // NOTE: This function only adds NetworkRequests that "newNetwork" could satisfy,
    // it does not remove NetworkRequests that other Networks could better satisfy.
    // If you need to handle decreases in score, use {@link rematchAllNetworksAndRequests}.
    // This function should be used when possible instead of {@code rematchAllNetworksAndRequests}
    // as it performs better by a factor of the number of Networks.
    private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork) {
        boolean keep = newNetwork.isVPN();
        boolean isNewDefault = false;
        if (DBG) log("handleConnectionValidated for "+newNetwork.name());
        // check if any NetworkRequest wants this NetworkAgent
        if (DBG) log("rematching " + newNetwork.name());
        // Find and migrate to this Network any NetworkRequests for
        // which this network is now the best.
        ArrayList<NetworkAgentInfo> affectedNetworks = new ArrayList<NetworkAgentInfo>();
        if (VDBG) log(" new Network has: " + newNetwork.networkCapabilities);
        if (VDBG) log(" network has: " + newNetwork.networkCapabilities);
        for (NetworkRequestInfo nri : mNetworkRequests.values()) {
            NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
            if (newNetwork == currentNetwork) {
@@ -4543,18 +4552,21 @@ public class ConnectivityService extends IConnectivityManager.Stub {
            if (nri.request.networkCapabilities.satisfiedByNetworkCapabilities(
                    newNetwork.networkCapabilities)) {
                if (!nri.isRequest) {
                    // This is not a request, it's a callback listener.
                    // Add it to newNetwork regardless of score.
                    newNetwork.addRequest(nri.request);
                    continue;
                }

                // next check if it's better than any current network we're using for
                // this request
                if (VDBG) {
                    log("currentScore = " +
                            (currentNetwork != null ? currentNetwork.currentScore : 0) +
                            ", newScore = " + newNetwork.currentScore);
                            (currentNetwork != null ? currentNetwork.getCurrentScore() : 0) +
                            ", newScore = " + newNetwork.getCurrentScore());
                }
                if (currentNetwork == null ||
                        currentNetwork.currentScore < newNetwork.currentScore) {
                        currentNetwork.getCurrentScore() < newNetwork.getCurrentScore()) {
                    if (currentNetwork != null) {
                        if (DBG) log("   accepting network in place of " + currentNetwork.name());
                        currentNetwork.networkRequests.remove(nri.request.requestId);
@@ -4569,13 +4581,16 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                        mLegacyTypeTracker.add(nri.request.legacyType, newNetwork);
                    }
                    keep = true;
                    // Tell NetworkFactories about the new score, so they can stop
                    // trying to connect if they know they cannot match it.
                    // TODO - this could get expensive if we have alot of requests for this
                    // network.  Think about if there is a way to reduce this.  Push
                    // netid->request mapping to each factory?
                    sendUpdatedScoreToFactories(nri.request, newNetwork.currentScore);
                    sendUpdatedScoreToFactories(nri.request, newNetwork.getCurrentScore());
                    if (mDefaultRequest.requestId == nri.request.requestId) {
                        isNewDefault = true;
                        updateActiveDefaultNetwork(newNetwork);
                        // TODO: Remove following line.  It's redundant with makeDefault call.
                        mActiveDefaultNetwork = newNetwork.networkInfo.getType();
                        if (newNetwork.linkProperties != null) {
                            updateTcpBufferSizes(newNetwork);
                            setDefaultDnsSystemProperties(
@@ -4591,12 +4606,13 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                            mLegacyTypeTracker.remove(currentNetwork.networkInfo.getType(),
                                                      currentNetwork);
                        }
                        mDefaultInetConditionPublished = 100;
                        mDefaultInetConditionPublished = newNetwork.validated ? 100 : 0;
                        mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork);
                    }
                }
            }
        }
        // Linger any networks that are no longer needed.
        for (NetworkAgentInfo nai : affectedNetworks) {
            boolean teardown = !nai.isVPN();
            for (int i = 0; i < nai.networkRequests.size() && teardown; i++) {
@@ -4624,6 +4640,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
        }
        if (keep) {
            if (isNewDefault) {
                // Notify system services that this network is up.
                makeDefault(newNetwork);
                synchronized (ConnectivityService.this) {
                    // have a new default network, release the transition wakelock in
@@ -4640,6 +4657,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {

            // Notify battery stats service about this network, both the normal
            // interface and any stacked links.
            // TODO: Avoid redoing this; this must only be done once when a network comes online.
            try {
                final IBatteryStats bs = BatteryStatsService.getService();
                final int type = newNetwork.networkInfo.getType();
@@ -4655,7 +4673,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {
            }

            notifyNetworkCallbacks(newNetwork, ConnectivityManager.CALLBACK_AVAILABLE);
        } else {
        } else if (newNetwork.validated) {
            // Only tear down validated networks here.  Leave unvalidated to either become
            // validated (and get evaluated against peers, one losing here) or
            // NetworkMonitor reports a bad network and we tear it down then.
            // TODO: Could teardown unvalidated networks when their NetworkCapabilities
            // satisfy no NetworkRequests.
            if (DBG && newNetwork.networkRequests.size() != 0) {
                loge("tearing down network with live requests:");
                for (int i=0; i < newNetwork.networkRequests.size(); i++) {
@@ -4667,6 +4690,31 @@ public class ConnectivityService extends IConnectivityManager.Stub {
        }
    }

    // Attempt to rematch all Networks with NetworkRequests.  This may result in Networks
    // being disconnected.
    // If only one Network's score or capabilities have been modified since the last time
    // this function was called, pass this Network in via the "changed" arugment, otherwise
    // pass null.
    // If only one Network has been changed but its NetworkCapabilities have not changed,
    // pass in the Network's score (from getCurrentScore()) prior to the change via
    // "oldScore", otherwise pass changed.getCurrentScore() or 0 if "changed" is null.
    private void rematchAllNetworksAndRequests(NetworkAgentInfo changed, int oldScore) {
        // TODO: This may get slow.  The "changed" parameter is provided for future optimization
        // to avoid the slowness.  It is not simply enough to process just "changed", for
        // example in the case where "changed"'s score decreases and another network should begin
        // satifying a NetworkRequest that "changed" currently satisfies.

        // Optimization: Only reprocess "changed" if its score improved.  This is safe because it
        // can only add more NetworkRequests satisfied by "changed", and this is exactly what
        // rematchNetworkAndRequests() handles.
        if (changed != null && oldScore < changed.getCurrentScore()) {
            rematchNetworkAndRequests(changed);
        } else {
            for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
                rematchNetworkAndRequests(nai);
            }
        }
    }

    private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) {
        NetworkInfo.State state = newInfo.getState();
@@ -4721,12 +4769,14 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                }
                // TODO: support proxy per network.
            }
            // Make default network if we have no default.  Any network is better than no network.
            // Consider network even though it is not yet validated.
            // TODO: All the if-statement conditions can be removed now that validation only confers
            // a score increase.
            if (mNetworkForRequestId.get(mDefaultRequest.requestId) == null &&
                    networkAgent.isVPN() == false &&
                    mDefaultRequest.networkCapabilities.satisfiedByNetworkCapabilities(
                    networkAgent.networkCapabilities)) {
                makeDefault(networkAgent);
                rematchNetworkAndRequests(networkAgent);
            }
        } else if (state == NetworkInfo.State.DISCONNECTED ||
                state == NetworkInfo.State.SUSPENDED) {
@@ -4752,23 +4802,11 @@ public class ConnectivityService extends IConnectivityManager.Stub {
            score = 0;
        }

        nai.currentScore = score;
        final int oldScore = nai.getCurrentScore();
        nai.setCurrentScore(score);

        if (nai.created) rematchAllNetworksAndRequests(nai, oldScore);

        // TODO - This will not do the right thing if this network is lowering
        // its score and has requests that can be served by other
        // currently-active networks, or if the network is increasing its
        // score and other networks have requests that can be better served
        // by this network.
        //
        // Really we want to see if any of our requests migrate to other
        // active/lingered networks and if any other requests migrate to us (depending
        // on increasing/decreasing currentScore.  That's a bit of work and probably our
        // score checking/network allocation code needs to be modularized so we can understand
        // (see handleConnectionValided for an example).
        //
        // As a first order approx, lets just advertise the new score to factories.  If
        // somebody can beat it they will nominate a network and our normal net replacement
        // code will fire.
        for (int i = 0; i < nai.networkRequests.size(); i++) {
            NetworkRequest nr = nai.networkRequests.valueAt(i);
            // Don't send listening requests to factories. b/17393458
+28 −2
Original line number Diff line number Diff line
@@ -43,12 +43,16 @@ public class NetworkAgentInfo {
    public Network network;
    public LinkProperties linkProperties;
    public NetworkCapabilities networkCapabilities;
    public int currentScore;
    public final NetworkMonitor networkMonitor;
    public final NetworkMisc networkMisc;
    public boolean created;
    public boolean validated;

    // This represents the last score received from the NetworkAgent.
    private int currentScore;
    // Penalty applied to scores of Networks that have not been validated.
    private static final int UNVALIDATED_SCORE_PENALTY = 40;

    // The list of NetworkRequests being satisfied by this Network.
    public final SparseArray<NetworkRequest> networkRequests = new SparseArray<NetworkRequest>();
    public final ArrayList<NetworkRequest> networkLingered = new ArrayList<NetworkRequest>();
@@ -80,11 +84,33 @@ public class NetworkAgentInfo {
        return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
    }

    // Get the current score for this Network.  This may be modified from what the
    // NetworkAgent sent, as it has modifiers applied to it.
    public int getCurrentScore() {
        // TODO: We may want to refactor this into a NetworkScore class that takes a base score from
        // the NetworkAgent and signals from the NetworkAgent and uses those signals to modify the
        // score.  The NetworkScore class would provide a nice place to centralize score constants
        // so they are not scattered about the transports.

        int score = currentScore;

        if (!validated) score -= UNVALIDATED_SCORE_PENALTY;

        if (score < 0) score = 0;

        return score;
    }

    public void setCurrentScore(int newScore) {
        currentScore = newScore;
    }

    public String toString() {
        return "NetworkAgentInfo{ ni{" + networkInfo + "}  network{" +
                network + "}  lp{" +
                linkProperties + "}  nc{" +
                networkCapabilities + "}  Score{" + currentScore + "} }";
                networkCapabilities + "}  Score{" + getCurrentScore() + "} " +
                "validated{" + validated + "} created{" + created + "} }";
    }

    public String name() {