2024年1月10日发(作者:辉童)
case CMD_REEVALUATE: if (1 != mReevaluateToken) return HANDLED; // Don't bother validating networks that don't satisify the default request. // This includes: // - VPNs which can be considered explicitly desired by the user and the // user's desire trumps whether the network validates. // - Networks that don't provide internet access. It's unclear how to // validate such networks. // - Untrusted networks. It's unsafe to prompt the user to sign-in to // such networks and the user didn't express interest in connecting to // such networks (an app did) so the user may be unhappily surprised when // asked to sign-in to a network they didn't want to connect to in the // first place. Validation could be done to adjust the network scores // however these networks are app-requested and may not be intended for // general usage, in which case general validation may not be an accurate // measure of the network's quality. Only the app knows how to evaluate // the network so don't bother validating here. Furthermore sending HTTP // packets over the network may be undesirable, for example an extremely // expensive metered network, or unwanted leaking of the User Agent string. if (!iedByNetworkCapabilities( kCapabilities)) { transitionTo(mValidatedState); return HANDLED; } // Note: This call to isCaptivePortal() could take up to a minute. Resolving the // server's IP addresses could hit the DNS timeout, and attempting connections // to each of the server's several IP addresses (currently one IPv4 and one // IPv6) could each take SOCKET_TIMEOUT_MS. During this time this StateMachine // will be unresponsive. isCaptivePortal() could be executed on another Thread // if this is found to cause problems. int httpResponseCode = isCaptivePortal(); if (httpResponseCode == 204) { transitionTo(mValidatedState); } else if (httpResponseCode >= 200 && httpResponseCode <= 399) { transitionTo(mCaptivePortalState); } else if (++mAttempt > mMaxAttempts) { transitionTo(mOfflineState); } else if (mReevaluateDelayMs >= 0) { Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0); sendMessageDelayed(msg, mReevaluateDelayMs); } return HANDLED;androidframeworksbaseservicescorejavacomandroidserverconnectivity /** * Do a URL fetch on a known server to see if we get the data we expect. * Returns HTTP response code. */ private int isCaptivePortal() { HttpURLConnection urlConnection = null; int httpResponseCode = 599; try { URL url = new URL("http", mServer, "/generate_204"); // On networks with a PAC instead of fetching a URL that should result in a 204 // reponse, we instead simply fetch the PAC script. This is done for a few reasons: // 1. At present our PAC code does not yet handle multiple PACs on multiple networks // until something like /#/c/115180/ lands. // nnection() will ignore network-specific PACs and instead fetch // using NO_PROXY. If a PAC is in place, the only fetch we know will succeed with // NO_PROXY is the fetch of the PAC itself. // 2. To proxy the generate_204 fetch through a PAC would require a number of things // happen before the fetch can commence, namely: // a) the PAC script be fetched // b) a PAC script resolver service be fired up and resolve mServer
// b) a PAC script resolver service be fired up and resolve mServer // Network validation could be delayed until these prerequisities are satisifed or // could simply be left to race them. Neither is an optimal solution. // 3. PAC scripts are sometimes used to block or restrict Internet access and may in // fact block fetching of the generate_204 URL which would lead to false negative // results for network validation. boolean fetchPac = false; { final ProxyInfo proxyInfo = pProxy(); if (proxyInfo != null && !(FileUrl())) { url = new URL(FileUrl().toString()); fetchPac = true; } } if (DBG) { log("Checking " + ng() + " on " + raInfo()); } urlConnection = (HttpURLConnection) nnection(url); tanceFollowRedirects(fetchPac); nectTimeout(SOCKET_TIMEOUT_MS); dTimeout(SOCKET_TIMEOUT_MS); Caches(false); // Time how long it takes to get a response to our request long requestTimestamp = dRealtime(); utStream(); // Time how long it takes to get a response to our request long responseTimestamp = dRealtime(); httpResponseCode = ponseCode(); if (DBG) { log("isCaptivePortal: ret=" + httpResponseCode + " headers=" + derFields()); } // NOTE: We may want to consider an "HTTP/1.0 204" response to be a captive // portal. The only example of this seen so far was a captive portal. For // the time being go with prior behavior of assuming it's not a captive // portal. If it is considered a captive portal, a different sign-in URL // is needed (i.e. can't browse a 204). This could be the result of an HTTP // proxy server. // Consider 200 response with "Content-length=0" to not be a captive portal. // There's no point in considering this a captive portal as the user cannot // sign-in to an empty page. Probably the result of a broken transparent proxy. // See b/9972012. if (httpResponseCode == 200 && tentLength() == 0) { if (DBG) log("Empty 200 response interpreted as 204 response."); httpResponseCode = 204; } if (httpResponseCode == 200 && fetchPac) { if (DBG) log("PAC fetch 200 response interpreted as 204 response."); httpResponseCode = 204; } sendNetworkConditionsBroadcast(true /* response received */, httpResponseCode != 204 /* isCaptivePortal */, requestTimestamp, responseTimestamp); } catch (IOException e) { if (DBG) log("Probably not a portal: exception " + e); if (httpResponseCode == 599) { // TODO: Ping gateway and DNS server and log results. }
raInfo()); } urlConnection = (HttpURLConnection) nnection(url); tanceFollowRedirects(fetchPac); nectTimeout(SOCKET_TIMEOUT_MS); dTimeout(SOCKET_TIMEOUT_MS); Caches(false); // Time how long it takes to get a response to our request long requestTimestamp = dRealtime(); utStream(); // Time how long it takes to get a response to our request long responseTimestamp = dRealtime(); httpResponseCode = ponseCode(); if (DBG) { log("isCaptivePortal: ret=" + httpResponseCode + " headers=" + derFields()); } // NOTE: We may want to consider an "HTTP/1.0 204" response to be a captive // portal. The only example of this seen so far was a captive portal. For // the time being go with prior behavior of assuming it's not a captive // portal. If it is considered a captive portal, a different sign-in URL // is needed (i.e. can't browse a 204). This could be the result of an HTTP // proxy server. // Consider 200 response with "Content-length=0" to not be a captive portal. // There's no point in considering this a captive portal as the user cannot // sign-in to an empty page. Probably the result of a broken transparent proxy. // See b/9972012. if (httpResponseCode == 200) { if (DBG) log(" 200 response interpreted as 204 response."); httpResponseCode = 204; }
2024年1月10日发(作者:辉童)
case CMD_REEVALUATE: if (1 != mReevaluateToken) return HANDLED; // Don't bother validating networks that don't satisify the default request. // This includes: // - VPNs which can be considered explicitly desired by the user and the // user's desire trumps whether the network validates. // - Networks that don't provide internet access. It's unclear how to // validate such networks. // - Untrusted networks. It's unsafe to prompt the user to sign-in to // such networks and the user didn't express interest in connecting to // such networks (an app did) so the user may be unhappily surprised when // asked to sign-in to a network they didn't want to connect to in the // first place. Validation could be done to adjust the network scores // however these networks are app-requested and may not be intended for // general usage, in which case general validation may not be an accurate // measure of the network's quality. Only the app knows how to evaluate // the network so don't bother validating here. Furthermore sending HTTP // packets over the network may be undesirable, for example an extremely // expensive metered network, or unwanted leaking of the User Agent string. if (!iedByNetworkCapabilities( kCapabilities)) { transitionTo(mValidatedState); return HANDLED; } // Note: This call to isCaptivePortal() could take up to a minute. Resolving the // server's IP addresses could hit the DNS timeout, and attempting connections // to each of the server's several IP addresses (currently one IPv4 and one // IPv6) could each take SOCKET_TIMEOUT_MS. During this time this StateMachine // will be unresponsive. isCaptivePortal() could be executed on another Thread // if this is found to cause problems. int httpResponseCode = isCaptivePortal(); if (httpResponseCode == 204) { transitionTo(mValidatedState); } else if (httpResponseCode >= 200 && httpResponseCode <= 399) { transitionTo(mCaptivePortalState); } else if (++mAttempt > mMaxAttempts) { transitionTo(mOfflineState); } else if (mReevaluateDelayMs >= 0) { Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0); sendMessageDelayed(msg, mReevaluateDelayMs); } return HANDLED;androidframeworksbaseservicescorejavacomandroidserverconnectivity /** * Do a URL fetch on a known server to see if we get the data we expect. * Returns HTTP response code. */ private int isCaptivePortal() { HttpURLConnection urlConnection = null; int httpResponseCode = 599; try { URL url = new URL("http", mServer, "/generate_204"); // On networks with a PAC instead of fetching a URL that should result in a 204 // reponse, we instead simply fetch the PAC script. This is done for a few reasons: // 1. At present our PAC code does not yet handle multiple PACs on multiple networks // until something like /#/c/115180/ lands. // nnection() will ignore network-specific PACs and instead fetch // using NO_PROXY. If a PAC is in place, the only fetch we know will succeed with // NO_PROXY is the fetch of the PAC itself. // 2. To proxy the generate_204 fetch through a PAC would require a number of things // happen before the fetch can commence, namely: // a) the PAC script be fetched // b) a PAC script resolver service be fired up and resolve mServer
// b) a PAC script resolver service be fired up and resolve mServer // Network validation could be delayed until these prerequisities are satisifed or // could simply be left to race them. Neither is an optimal solution. // 3. PAC scripts are sometimes used to block or restrict Internet access and may in // fact block fetching of the generate_204 URL which would lead to false negative // results for network validation. boolean fetchPac = false; { final ProxyInfo proxyInfo = pProxy(); if (proxyInfo != null && !(FileUrl())) { url = new URL(FileUrl().toString()); fetchPac = true; } } if (DBG) { log("Checking " + ng() + " on " + raInfo()); } urlConnection = (HttpURLConnection) nnection(url); tanceFollowRedirects(fetchPac); nectTimeout(SOCKET_TIMEOUT_MS); dTimeout(SOCKET_TIMEOUT_MS); Caches(false); // Time how long it takes to get a response to our request long requestTimestamp = dRealtime(); utStream(); // Time how long it takes to get a response to our request long responseTimestamp = dRealtime(); httpResponseCode = ponseCode(); if (DBG) { log("isCaptivePortal: ret=" + httpResponseCode + " headers=" + derFields()); } // NOTE: We may want to consider an "HTTP/1.0 204" response to be a captive // portal. The only example of this seen so far was a captive portal. For // the time being go with prior behavior of assuming it's not a captive // portal. If it is considered a captive portal, a different sign-in URL // is needed (i.e. can't browse a 204). This could be the result of an HTTP // proxy server. // Consider 200 response with "Content-length=0" to not be a captive portal. // There's no point in considering this a captive portal as the user cannot // sign-in to an empty page. Probably the result of a broken transparent proxy. // See b/9972012. if (httpResponseCode == 200 && tentLength() == 0) { if (DBG) log("Empty 200 response interpreted as 204 response."); httpResponseCode = 204; } if (httpResponseCode == 200 && fetchPac) { if (DBG) log("PAC fetch 200 response interpreted as 204 response."); httpResponseCode = 204; } sendNetworkConditionsBroadcast(true /* response received */, httpResponseCode != 204 /* isCaptivePortal */, requestTimestamp, responseTimestamp); } catch (IOException e) { if (DBG) log("Probably not a portal: exception " + e); if (httpResponseCode == 599) { // TODO: Ping gateway and DNS server and log results. }
raInfo()); } urlConnection = (HttpURLConnection) nnection(url); tanceFollowRedirects(fetchPac); nectTimeout(SOCKET_TIMEOUT_MS); dTimeout(SOCKET_TIMEOUT_MS); Caches(false); // Time how long it takes to get a response to our request long requestTimestamp = dRealtime(); utStream(); // Time how long it takes to get a response to our request long responseTimestamp = dRealtime(); httpResponseCode = ponseCode(); if (DBG) { log("isCaptivePortal: ret=" + httpResponseCode + " headers=" + derFields()); } // NOTE: We may want to consider an "HTTP/1.0 204" response to be a captive // portal. The only example of this seen so far was a captive portal. For // the time being go with prior behavior of assuming it's not a captive // portal. If it is considered a captive portal, a different sign-in URL // is needed (i.e. can't browse a 204). This could be the result of an HTTP // proxy server. // Consider 200 response with "Content-length=0" to not be a captive portal. // There's no point in considering this a captive portal as the user cannot // sign-in to an empty page. Probably the result of a broken transparent proxy. // See b/9972012. if (httpResponseCode == 200) { if (DBG) log(" 200 response interpreted as 204 response."); httpResponseCode = 204; }