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

Commit df112354 authored by Lorenzo Colitti's avatar Lorenzo Colitti Committed by Automerger Merge Worker
Browse files

Merge "Generalize support for underlying networks." am: 72c26b88 am: 6731b999 am: c211cbf9

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1513052

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: Ida4e4d7b6d607d6c9f6efc2d06732f7826f7942e
parents c3369c58 c211cbf9
Loading
Loading
Loading
Loading
+54 −42
Original line number Diff line number Diff line
@@ -2823,6 +2823,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
                    break;
                }
                case NetworkAgent.EVENT_UNDERLYING_NETWORKS_CHANGED: {
                    // TODO: prevent loops, e.g., if a network declares itself as underlying.
                    if (!nai.supportsUnderlyingNetworks()) {
                        Log.wtf(TAG, "Non-virtual networks cannot have underlying networks");
                        break;
@@ -3422,6 +3423,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
            }
        }
        nai.clearLingerState();
        propagateUnderlyingNetworkCapabilities(nai.network);
        if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) {
            mDefaultNetworkNai = null;
            updateDataActivityTracking(null /* newNetwork */, nai);
@@ -3429,9 +3431,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
            ensureNetworkTransitionWakelock(nai.toShortString());
        }
        mLegacyTypeTracker.remove(nai, wasDefault);
        if (!nai.networkCapabilities.hasTransport(TRANSPORT_VPN)) {
            propagateUnderlyingNetworkCapabilities();
        }
        rematchAllNetworksAndRequests();
        mLingerMonitor.noteDisconnect(nai);
        if (nai.created) {
@@ -4820,17 +4819,35 @@ public class ConnectivityService extends IConnectivityManager.Stub
        }
    }

    private Network[] underlyingNetworksOrDefault(Network[] underlyingNetworks) {
        final Network defaultNetwork = getNetwork(getDefaultNetwork());
        if (underlyingNetworks == null && defaultNetwork != null) {
            // null underlying networks means to track the default.
            underlyingNetworks = new Network[] { defaultNetwork };
        }
        return underlyingNetworks;
    }

    // Returns true iff |network| is an underlying network of |nai|.
    private boolean hasUnderlyingNetwork(NetworkAgentInfo nai, Network network) {
        // TODO: support more than one level of underlying networks, either via a fixed-depth search
        // (e.g., 2 levels of underlying networks), or via loop detection, or....
        if (!nai.supportsUnderlyingNetworks()) return false;
        final Network[] underlying = underlyingNetworksOrDefault(nai.declaredUnderlyingNetworks);
        return ArrayUtils.contains(underlying, network);
    }

    /**
     * Ask all networks with underlying networks to recompute and update their capabilities.
     * Recompute the capabilities for any networks that had a specific network as underlying.
     *
     * When underlying networks change, such networks may have to update capabilities to reflect
     * things like the metered bit, their transports, and so on. The capabilities are calculated
     * immediately. This method runs on the ConnectivityService thread.
     */
    private void propagateUnderlyingNetworkCapabilities() {
    private void propagateUnderlyingNetworkCapabilities(Network updatedNetwork) {
        ensureRunningOnConnectivityServiceThread();
        for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
            if (nai.supportsUnderlyingNetworks()) {
            if (updatedNetwork == null || hasUnderlyingNetwork(nai, updatedNetwork)) {
                updateCapabilitiesForNetwork(nai);
            }
        }
@@ -6369,27 +6386,28 @@ public class ConnectivityService extends IConnectivityManager.Stub
     * This method should never alter the agent's NetworkCapabilities, only store data in |nai|.
     */
    private void processCapabilitiesFromAgent(NetworkAgentInfo nai, NetworkCapabilities nc) {
        nai.declaredMetered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED);
        // Note: resetting the owner UID before storing the agent capabilities in NAI means that if
        // the agent attempts to change the owner UID, then nai.declaredCapabilities will not
        // actually be the same as the capabilities sent by the agent. Still, it is safer to reset
        // the owner UID here and behave as if the agent had never tried to change it.
        if (nai.networkCapabilities.getOwnerUid() != nc.getOwnerUid()) {
            Log.e(TAG, nai.toShortString() + ": ignoring attempt to change owner from "
                    + nai.networkCapabilities.getOwnerUid() + " to " + nc.getOwnerUid());
            nc.setOwnerUid(nai.networkCapabilities.getOwnerUid());
        }
        nai.declaredCapabilities = new NetworkCapabilities(nc);
    }

    /** Modifies |caps| based on the capabilities of the specified underlying networks. */
    /** Modifies |newNc| based on the capabilities of |underlyingNetworks| and |agentCaps|. */
    @VisibleForTesting
    void applyUnderlyingCapabilities(@Nullable Network[] underlyingNetworks,
            @NonNull NetworkCapabilities caps,  boolean declaredMetered) {
        final Network defaultNetwork = getNetwork(getDefaultNetwork());
        if (underlyingNetworks == null && defaultNetwork != null) {
            // null underlying networks means to track the default.
            underlyingNetworks = new Network[] { defaultNetwork };
        }
        int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN };
            @NonNull NetworkCapabilities agentCaps, @NonNull NetworkCapabilities newNc) {
        underlyingNetworks = underlyingNetworksOrDefault(underlyingNetworks);
        int[] transportTypes = agentCaps.getTransportTypes();
        int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
        int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
        boolean metered = declaredMetered; // metered if any underlying is metered, or agentMetered
        // metered if any underlying is metered, or originally declared metered by the agent.
        boolean metered = !agentCaps.hasCapability(NET_CAPABILITY_NOT_METERED);
        boolean roaming = false; // roaming if any underlying is roaming
        boolean congested = false; // congested if any underlying is congested
        boolean suspended = true; // suspended if all underlying are suspended
@@ -6435,13 +6453,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
            suspended = false;
        }

        caps.setTransportTypes(transportTypes);
        caps.setLinkDownstreamBandwidthKbps(downKbps);
        caps.setLinkUpstreamBandwidthKbps(upKbps);
        caps.setCapability(NET_CAPABILITY_NOT_METERED, !metered);
        caps.setCapability(NET_CAPABILITY_NOT_ROAMING, !roaming);
        caps.setCapability(NET_CAPABILITY_NOT_CONGESTED, !congested);
        caps.setCapability(NET_CAPABILITY_NOT_SUSPENDED, !suspended);
        newNc.setTransportTypes(transportTypes);
        newNc.setLinkDownstreamBandwidthKbps(downKbps);
        newNc.setLinkUpstreamBandwidthKbps(upKbps);
        newNc.setCapability(NET_CAPABILITY_NOT_METERED, !metered);
        newNc.setCapability(NET_CAPABILITY_NOT_ROAMING, !roaming);
        newNc.setCapability(NET_CAPABILITY_NOT_CONGESTED, !congested);
        newNc.setCapability(NET_CAPABILITY_NOT_SUSPENDED, !suspended);
    }

    /**
@@ -6498,7 +6516,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
        }

        if (nai.supportsUnderlyingNetworks()) {
            applyUnderlyingCapabilities(nai.declaredUnderlyingNetworks, newNc, nai.declaredMetered);
            applyUnderlyingCapabilities(nai.declaredUnderlyingNetworks, nai.declaredCapabilities,
                    newNc);
        }

        return newNc;
@@ -6577,11 +6596,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
            }
        }

        if (!newNc.hasTransport(TRANSPORT_VPN)) {
            // Tell VPNs about updated capabilities, since they may need to
            // bubble those changes through.
            propagateUnderlyingNetworkCapabilities();
        }
        // This network might have been underlying another network. Propagate its capabilities.
        propagateUnderlyingNetworkCapabilities(nai.network);

        if (!newNc.equalsTransportTypes(prevNc)) {
            mDnsManager.updateTransportsForNetwork(
@@ -6911,8 +6927,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
        updateTcpBufferSizes(null != newNetwork
                ? newNetwork.linkProperties.getTcpBufferSizes() : null);
        notifyIfacesChangedForNetworkStats();
        // Fix up the NetworkCapabilities of any VPNs that don't specify underlying networks.
        propagateUnderlyingNetworkCapabilities();
        // Fix up the NetworkCapabilities of any networks that have this network as underlying.
        if (newNetwork != null) {
            propagateUnderlyingNetworkCapabilities(newNetwork.network);
        }
    }

    private void processListenRequests(@NonNull final NetworkAgentInfo nai) {
@@ -7368,13 +7386,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
            networkAgent.networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND);

            if (!createNativeNetwork(networkAgent)) return;
            if (networkAgent.isVPN()) {
                // Initialize the VPN capabilities to their starting values according to the
                // underlying networks. This will avoid a spurious callback to
                // onCapabilitiesUpdated being sent in updateAllVpnCapabilities below as
                // the VPN would switch from its default, blank capabilities to those
                // that reflect the capabilities of its underlying networks.
                propagateUnderlyingNetworkCapabilities();
            if (networkAgent.supportsUnderlyingNetworks()) {
                // Initialize the network's capabilities to their starting values according to the
                // underlying networks. This ensures that the capabilities are correct before
                // anything happens to the network.
                updateCapabilitiesForNetwork(networkAgent);
            }
            networkAgent.created = true;
        }
@@ -7416,10 +7432,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
            // doing.
            updateSignalStrengthThresholds(networkAgent, "CONNECT", null);

            if (networkAgent.supportsUnderlyingNetworks()) {
                propagateUnderlyingNetworkCapabilities();
            }

            // Consider network even though it is not yet validated.
            rematchAllNetworksAndRequests();

+4 −3
Original line number Diff line number Diff line
@@ -138,9 +138,10 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
    // not guaranteed to be current or correct, or even to exist.
    public @Nullable Network[] declaredUnderlyingNetworks;

    // Whether this network is always metered even if its underlying networks are unmetered.
    // Only relevant if #supportsUnderlyingNetworks is true.
    public boolean declaredMetered;
    // The capabilities originally announced by the NetworkAgent, regardless of any capabilities
    // that were added or removed due to this network's underlying networks.
    // Only set if #supportsUnderlyingNetworks is true.
    public @Nullable NetworkCapabilities declaredCapabilities;

    // Indicates if netd has been told to create this Network. From this point on the appropriate
    // routing rules are setup and routes are added so packets can begin flowing over the Network.
+13 −11
Original line number Diff line number Diff line
@@ -5471,6 +5471,7 @@ public class ConnectivityServiceTest {
        final Network wifi = mWiFiNetworkAgent.getNetwork();

        final NetworkCapabilities initialCaps = new NetworkCapabilities();
        initialCaps.addTransportType(TRANSPORT_VPN);
        initialCaps.addCapability(NET_CAPABILITY_INTERNET);
        initialCaps.removeCapability(NET_CAPABILITY_NOT_VPN);

@@ -5502,44 +5503,45 @@ public class ConnectivityServiceTest {
        withWifiAndMobileUnderlying.setLinkDownstreamBandwidthKbps(10);
        withWifiAndMobileUnderlying.setLinkUpstreamBandwidthKbps(20);

        final NetworkCapabilities initialCapsNotMetered = new NetworkCapabilities(initialCaps);
        initialCapsNotMetered.addCapability(NET_CAPABILITY_NOT_METERED);

        NetworkCapabilities caps = new NetworkCapabilities(initialCaps);
        final boolean notDeclaredMetered = false;
        mService.applyUnderlyingCapabilities(new Network[]{}, caps, notDeclaredMetered);
        mService.applyUnderlyingCapabilities(new Network[]{}, initialCapsNotMetered, caps);
        assertEquals(withNoUnderlying, caps);

        caps = new NetworkCapabilities(initialCaps);
        mService.applyUnderlyingCapabilities(new Network[]{null}, caps, notDeclaredMetered);
        mService.applyUnderlyingCapabilities(new Network[]{null}, initialCapsNotMetered, caps);
        assertEquals(withNoUnderlying, caps);

        caps = new NetworkCapabilities(initialCaps);
        mService.applyUnderlyingCapabilities(new Network[]{mobile}, caps, notDeclaredMetered);
        mService.applyUnderlyingCapabilities(new Network[]{mobile}, initialCapsNotMetered, caps);
        assertEquals(withMobileUnderlying, caps);

        mService.applyUnderlyingCapabilities(new Network[]{wifi}, caps, notDeclaredMetered);
        mService.applyUnderlyingCapabilities(new Network[]{wifi}, initialCapsNotMetered, caps);
        assertEquals(withWifiUnderlying, caps);

        final boolean isDeclaredMetered = true;
        withWifiUnderlying.removeCapability(NET_CAPABILITY_NOT_METERED);
        caps = new NetworkCapabilities(initialCaps);
        mService.applyUnderlyingCapabilities(new Network[]{wifi}, caps, isDeclaredMetered);
        mService.applyUnderlyingCapabilities(new Network[]{wifi}, initialCaps, caps);
        assertEquals(withWifiUnderlying, caps);

        caps = new NetworkCapabilities(initialCaps);
        mService.applyUnderlyingCapabilities(new Network[]{mobile, wifi}, caps, isDeclaredMetered);
        mService.applyUnderlyingCapabilities(new Network[]{mobile, wifi}, initialCaps, caps);
        assertEquals(withWifiAndMobileUnderlying, caps);

        withWifiUnderlying.addCapability(NET_CAPABILITY_NOT_METERED);
        caps = new NetworkCapabilities(initialCaps);
        mService.applyUnderlyingCapabilities(new Network[]{null, mobile, null, wifi},
                caps, notDeclaredMetered);
                initialCapsNotMetered, caps);
        assertEquals(withWifiAndMobileUnderlying, caps);

        caps = new NetworkCapabilities(initialCaps);
        mService.applyUnderlyingCapabilities(new Network[]{null, mobile, null, wifi},
                caps, notDeclaredMetered);
                initialCapsNotMetered, caps);
        assertEquals(withWifiAndMobileUnderlying, caps);

        mService.applyUnderlyingCapabilities(null, caps, notDeclaredMetered);
        mService.applyUnderlyingCapabilities(null, initialCapsNotMetered, caps);
        assertEquals(withWifiUnderlying, caps);
    }