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

Commit adc4b451 authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 6553159 from 72b7075e to rvc-release

Change-Id: I7fa196d24a8a9e92f9b1525dccf8b7c910a339c9
parents 62c19d7c 72b7075e
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -37,4 +37,9 @@ public class ConstantsShim extends com.android.networkstack.apishim.api29.Consta
            DataStallReport.DETECTION_METHOD_DNS_EVENTS;
    public static final int DETECTION_METHOD_TCP_METRICS =
            DataStallReport.DETECTION_METHOD_TCP_METRICS;

    /**
     * @see android.net.NetworkCapabilities
     */
    public static final int TRANSPORT_TEST = 7;
}
+4 −0
Original line number Diff line number Diff line
@@ -30,4 +30,8 @@ public class ConstantsShim extends com.android.networkstack.apishim.api30.Consta
     */
    @VisibleForTesting
    public static final int VERSION = 31;

    // When removing this shim, the version in NetworkMonitorUtils should be removed too.
    // TODO: add TRANSPORT_TEST to system API in API 31 (it is only a test API as of R)
    public static final int TRANSPORT_TEST = 7;
}
+35 −3
Original line number Diff line number Diff line
@@ -20,11 +20,21 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;

import android.net.NetworkCapabilities;

/** @hide */
public class NetworkMonitorUtils {
    // This class is used by both NetworkMonitor and ConnectivityService, so it cannot use
    // NetworkStack shims, but at the same time cannot use non-system APIs.
    // TRANSPORT_TEST is test API as of R (so it is enforced to always be 7 and can't be changed),
    // and it is being added as a system API in S.
    // TODO: use NetworkCapabilities.TRANSPORT_TEST once NetworkStack builds against API 31.
    private static final int TRANSPORT_TEST = 7;

    // Network conditions broadcast constants
    public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
@@ -47,11 +57,33 @@ public class NetworkMonitorUtils {
     * @param nc Network capabilities of the network to test.
     */
    public static boolean isPrivateDnsValidationRequired(NetworkCapabilities nc) {
        if (nc == null) return false;

        // TODO: Consider requiring validation for DUN networks.
        return nc != null
                && nc.hasCapability(NET_CAPABILITY_INTERNET)
        if (nc.hasCapability(NET_CAPABILITY_INTERNET)
                && nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)
                && nc.hasCapability(NET_CAPABILITY_TRUSTED);
                && nc.hasCapability(NET_CAPABILITY_TRUSTED)) {
            // Real networks
            return true;
        }

        // TODO: once TRANSPORT_TEST is @SystemApi in S and S SDK is stable (so constant shims can
        // be replaced with the SDK constant that will be inlined), replace isTestNetwork with
        // hasTransport(TRANSPORT_TEST)

        // Test networks that also have one of the major transport types are attempting to replicate
        // that transport on a test interface (for example, test ethernet networks with
        // EthernetManager#setIncludeTestInterfaces). Run validation on them for realistic tests.
        // See also comments on EthernetManager#setIncludeTestInterfaces and on TestNetworkManager.
        if (nc.hasTransport(TRANSPORT_TEST) && nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) && (
                nc.hasTransport(TRANSPORT_WIFI)
                || nc.hasTransport(TRANSPORT_CELLULAR)
                || nc.hasTransport(TRANSPORT_BLUETOOTH)
                || nc.hasTransport(TRANSPORT_ETHERNET))) {
            return true;
        }

        return false;
    }

    /**
+17 −3
Original line number Diff line number Diff line
@@ -64,7 +64,6 @@ import android.text.TextUtils;
import android.util.LocalLog;
import android.util.Log;
import android.util.Pair;
import android.util.Patterns;
import android.util.SparseArray;

import androidx.annotation.NonNull;
@@ -86,6 +85,8 @@ import com.android.server.NetworkStackService.NetworkStackServiceManager;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
@@ -1263,9 +1264,9 @@ public class IpClient extends StateMachine {
            }

            final String capportUrl = mDhcpResults.captivePortalApiUrl;
            // Uri.parse does no syntax check; do a simple regex check to eliminate garbage.
            // Uri.parse does no syntax check; do a simple check to eliminate garbage.
            // If the URL is still incorrect data fetching will fail later, which is fine.
            if (capportUrl != null && Patterns.WEB_URL.matcher(capportUrl).matches()) {
            if (isParseableUrl(capportUrl)) {
                NetworkInformationShimImpl.newInstance()
                        .setCaptivePortalApiUrl(newLp, Uri.parse(capportUrl));
            }
@@ -1303,6 +1304,19 @@ public class IpClient extends StateMachine {
        return newLp;
    }

    private static boolean isParseableUrl(String url) {
        // Verify that a URL has a reasonable format that can be parsed as per the URL constructor.
        // This does not use Patterns.WEB_URL as that pattern excludes URLs without TLDs, such as on
        // localhost.
        if (url == null) return false;
        try {
            new URL(url);
            return true;
        } catch (MalformedURLException e) {
            return false;
        }
    }

    private static void addAllReachableDnsServers(
            LinkProperties lp, Iterable<InetAddress> dnses) {
        // TODO: Investigate deleting this reachability check.  We should be
+55 −26
Original line number Diff line number Diff line
@@ -83,6 +83,7 @@ import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY;

import static com.android.networkstack.apishim.ConstantsShim.DETECTION_METHOD_DNS_EVENTS;
import static com.android.networkstack.apishim.ConstantsShim.DETECTION_METHOD_TCP_METRICS;
import static com.android.networkstack.apishim.ConstantsShim.TRANSPORT_TEST;
import static com.android.networkstack.util.DnsUtils.PRIVATE_DNS_PROBE_HOST_SUFFIX;
import static com.android.networkstack.util.DnsUtils.TYPE_ADDRCONFIG;

@@ -387,7 +388,8 @@ public class NetworkMonitor extends StateMachine {
    private static final int CMD_BANDWIDTH_CHECK_TIMEOUT = 24;

    // Start mReevaluateDelayMs at this value and double.
    private static final int INITIAL_REEVALUATE_DELAY_MS = 1000;
    @VisibleForTesting
    static final int INITIAL_REEVALUATE_DELAY_MS = 1000;
    private static final int MAX_REEVALUATE_DELAY_MS = 10 * 60 * 1000;
    // Default timeout of evaluating network bandwidth.
    private static final int DEFAULT_EVALUATING_BANDWIDTH_TIMEOUT_MS = 10_000;
@@ -1090,7 +1092,7 @@ public class NetworkMonitor extends StateMachine {
                    final CaptivePortalProbeResult probeRes = mLastPortalProbeResult;
                    // Use redirect URL from AP if exists.
                    final String portalUrl =
                            (useRedirectUrlForPortal() && probeRes.redirectUrl != null)
                            (useRedirectUrlForPortal() && makeURL(probeRes.redirectUrl) != null)
                            ? probeRes.redirectUrl : probeRes.detectUrl;
                    appExtras.putString(EXTRA_CAPTIVE_PORTAL_URL, portalUrl);
                    if (probeRes.probeSpec != null) {
@@ -1434,8 +1436,9 @@ public class NetworkMonitor extends StateMachine {
            }

            final int token = ++mProbeToken;
            final EvaluationThreadDeps deps = new EvaluationThreadDeps(mNetworkCapabilities);
            mThread = new Thread(() -> sendMessage(obtainMessage(CMD_PROBE_COMPLETE, token, 0,
                    isCaptivePortal())));
                    isCaptivePortal(deps))));
            mThread.start();
        }

@@ -2147,8 +2150,25 @@ public class NetworkMonitor extends StateMachine {
        return mCaptivePortalFallbackSpecs[idx];
    }

    @VisibleForTesting
    protected CaptivePortalProbeResult isCaptivePortal() {
    /**
     * Parameters that can be accessed by the evaluation thread in a thread-safe way.
     *
     * Parameters such as LinkProperties and NetworkCapabilities cannot be accessed by the
     * evaluation thread directly, as they are managed in the state machine thread and not
     * synchronized. This class provides a copy of the required data that is not modified and can be
     * used safely by the evaluation thread.
     */
    private static class EvaluationThreadDeps {
        // TODO: add parameters that are accessed in a non-thread-safe way from the evaluation
        // thread (read from LinkProperties, NetworkCapabilities, useHttps, validationStage)
        private final boolean mIsTestNetwork;

        EvaluationThreadDeps(NetworkCapabilities nc) {
            this.mIsTestNetwork = nc.hasTransport(TRANSPORT_TEST);
        }
    }

    private CaptivePortalProbeResult isCaptivePortal(EvaluationThreadDeps deps) {
        if (!mIsCaptivePortalCheckEnabled) {
            validationLog("Validation disabled.");
            return CaptivePortalProbeResult.success(CaptivePortalProbeResult.PROBE_UNKNOWN);
@@ -2196,11 +2216,11 @@ public class NetworkMonitor extends StateMachine {
            reportHttpProbeResult(NETWORK_VALIDATION_PROBE_HTTP, result);
        } else if (mUseHttps && httpsUrls.length == 1 && httpUrls.length == 1) {
            // Probe results are reported inside sendHttpAndHttpsParallelWithFallbackProbes.
            result = sendHttpAndHttpsParallelWithFallbackProbes(
                    proxyInfo, httpsUrls[0], httpUrls[0]);
            result = sendHttpAndHttpsParallelWithFallbackProbes(deps, proxyInfo,
                    httpsUrls[0], httpUrls[0]);
        } else if (mUseHttps) {
            // Support result aggregation from multiple Urls.
            result = sendMultiParallelHttpAndHttpsProbes(proxyInfo, httpsUrls, httpUrls);
            result = sendMultiParallelHttpAndHttpsProbes(deps, proxyInfo, httpsUrls, httpUrls);
        } else {
            result = sendDnsAndHttpProbes(proxyInfo, httpUrls[0], ValidationProbeEvent.PROBE_HTTP);
            reportHttpProbeResult(NETWORK_VALIDATION_PROBE_HTTP, result);
@@ -2482,12 +2502,12 @@ public class NetworkMonitor extends StateMachine {
        private final CountDownLatch mLatch;
        private final Probe mProbe;

        ProbeThread(CountDownLatch latch, ProxyInfo proxy, URL url, int probeType,
                Uri captivePortalApiUrl) {
        ProbeThread(CountDownLatch latch, EvaluationThreadDeps deps, ProxyInfo proxy, URL url,
                int probeType, Uri captivePortalApiUrl) {
            mLatch = latch;
            mProbe = (probeType == ValidationProbeEvent.PROBE_HTTPS)
                    ? new HttpsProbe(proxy, url, captivePortalApiUrl)
                    : new HttpProbe(proxy, url, captivePortalApiUrl);
                    ? new HttpsProbe(deps, proxy, url, captivePortalApiUrl)
                    : new HttpProbe(deps, proxy, url, captivePortalApiUrl);
            mResult = CaptivePortalProbeResult.failed(probeType);
        }

@@ -2512,11 +2532,14 @@ public class NetworkMonitor extends StateMachine {
    }

    private abstract static class Probe {
        protected final EvaluationThreadDeps mDeps;
        protected final ProxyInfo mProxy;
        protected final URL mUrl;
        protected final Uri mCaptivePortalApiUrl;

        protected Probe(ProxyInfo proxy, URL url, Uri captivePortalApiUrl) {
        protected Probe(EvaluationThreadDeps deps, ProxyInfo proxy, URL url,
                Uri captivePortalApiUrl) {
            mDeps = deps;
            mProxy = proxy;
            mUrl = url;
            mCaptivePortalApiUrl = captivePortalApiUrl;
@@ -2526,8 +2549,8 @@ public class NetworkMonitor extends StateMachine {
    }

    final class HttpsProbe extends Probe {
        HttpsProbe(ProxyInfo proxy, URL url, Uri captivePortalApiUrl) {
            super(proxy, url, captivePortalApiUrl);
        HttpsProbe(EvaluationThreadDeps deps, ProxyInfo proxy, URL url, Uri captivePortalApiUrl) {
            super(deps, proxy, url, captivePortalApiUrl);
        }

        @Override
@@ -2537,8 +2560,8 @@ public class NetworkMonitor extends StateMachine {
    }

    final class HttpProbe extends Probe {
        HttpProbe(ProxyInfo proxy, URL url, Uri captivePortalApiUrl) {
            super(proxy, url, captivePortalApiUrl);
        HttpProbe(EvaluationThreadDeps deps, ProxyInfo proxy, URL url, Uri captivePortalApiUrl) {
            super(deps, proxy, url, captivePortalApiUrl);
        }

        private CaptivePortalDataShim tryCapportApiProbe() {
@@ -2548,7 +2571,12 @@ public class NetworkMonitor extends StateMachine {
            final String apiContent;
            try {
                final URL url = new URL(mCaptivePortalApiUrl.toString());
                if (!"https".equals(url.getProtocol())) {
                // Protocol must be HTTPS
                // (as per https://www.ietf.org/id/draft-ietf-capport-api-07.txt, #4).
                // Only allow HTTP on localhost, for testing.
                final boolean isTestLocalhostHttp = mDeps.mIsTestNetwork
                        && "localhost".equals(url.getHost()) && "http".equals(url.getProtocol());
                if (!"https".equals(url.getProtocol()) && !isTestLocalhostHttp) {
                    validationLog("Invalid captive portal API protocol: " + url.getProtocol());
                    return null;
                }
@@ -2631,8 +2659,9 @@ public class NetworkMonitor extends StateMachine {
                        && captivePortalApiUrl == null);
    }

    private CaptivePortalProbeResult sendMultiParallelHttpAndHttpsProbes(@NonNull ProxyInfo proxy,
            @NonNull URL[] httpsUrls, @NonNull URL[] httpUrls) {
    private CaptivePortalProbeResult sendMultiParallelHttpAndHttpsProbes(
            @NonNull EvaluationThreadDeps deps, @Nullable ProxyInfo proxy, @NonNull URL[] httpsUrls,
            @NonNull URL[] httpUrls) {
        // If multiple URLs are required to ensure the correctness of validation, send parallel
        // probes to explore the result in separate probe threads and aggregate those results into
        // one as the final result for either HTTP or HTTPS.
@@ -2657,13 +2686,13 @@ public class NetworkMonitor extends StateMachine {
            // TODO: Have the capport probe as a different probe for cleanliness.
            final URL urlMaybeWithCapport = httpUrls[0];
            for (final URL url : httpUrls) {
                futures.add(ecs.submit(() -> new HttpProbe(proxy, url,
                futures.add(ecs.submit(() -> new HttpProbe(deps, proxy, url,
                        url.equals(urlMaybeWithCapport) ? capportApiUrl : null).sendProbe()));
            }

            for (final URL url : httpsUrls) {
                futures.add(
                        ecs.submit(() -> new HttpsProbe(proxy, url, capportApiUrl).sendProbe()));
                futures.add(ecs.submit(() -> new HttpsProbe(deps, proxy, url, capportApiUrl)
                        .sendProbe()));
            }

            final ArrayList<CaptivePortalProbeResult> completedProbes = new ArrayList<>();
@@ -2759,15 +2788,15 @@ public class NetworkMonitor extends StateMachine {
    }

    private CaptivePortalProbeResult sendHttpAndHttpsParallelWithFallbackProbes(
            ProxyInfo proxy, URL httpsUrl, URL httpUrl) {
            EvaluationThreadDeps deps, ProxyInfo proxy, URL httpsUrl, URL httpUrl) {
        // Number of probes to wait for. If a probe completes with a conclusive answer
        // it shortcuts the latch immediately by forcing the count to 0.
        final CountDownLatch latch = new CountDownLatch(2);

        final Uri capportApiUrl = getCaptivePortalApiUrl(mLinkProperties);
        final ProbeThread httpsProbe = new ProbeThread(latch, proxy, httpsUrl,
        final ProbeThread httpsProbe = new ProbeThread(latch, deps, proxy, httpsUrl,
                ValidationProbeEvent.PROBE_HTTPS, capportApiUrl);
        final ProbeThread httpProbe = new ProbeThread(latch, proxy, httpUrl,
        final ProbeThread httpProbe = new ProbeThread(latch, deps, proxy, httpUrl,
                ValidationProbeEvent.PROBE_HTTP, capportApiUrl);

        try {
Loading