Fields Summary |
---|
private static final boolean | DBG |
private static final String | TAG |
private static final String | DEFAULT_SERVER |
private static final int | SOCKET_TIMEOUT_MS |
public static final String | ACTION_NETWORK_CONDITIONS_MEASURED |
public static final String | EXTRA_CONNECTIVITY_TYPE |
public static final String | EXTRA_NETWORK_TYPE |
public static final String | EXTRA_RESPONSE_RECEIVED |
public static final String | EXTRA_IS_CAPTIVE_PORTAL |
public static final String | EXTRA_CELL_ID |
public static final String | EXTRA_SSID |
public static final String | EXTRA_BSSID |
public static final String | EXTRA_REQUEST_TIMESTAMP_MSreal time since boot |
public static final String | EXTRA_RESPONSE_TIMESTAMP_MS |
private static final String | PERMISSION_ACCESS_NETWORK_CONDITIONS |
private static final String | ACTION_CAPTIVE_PORTAL_LOGGED_IN |
private static final String | LOGGED_IN_RESULT |
private static final String | RESPONSE_TOKEN |
public static final int | NETWORK_TEST_RESULT_VALID |
public static final int | NETWORK_TEST_RESULT_INVALID |
private static final int | BASE |
public static final int | CMD_NETWORK_CONNECTEDInform NetworkMonitor that their network is connected.
Initiates Network Validation. |
public static final int | EVENT_NETWORK_TESTEDInform ConnectivityService that the network has been tested.
obj = NetworkAgentInfo
arg1 = One of the NETWORK_TESTED_RESULT_* constants. |
public static final int | CMD_NETWORK_LINGERInform NetworkMonitor to linger a network. The Monitor should
start a timer and/or start watching for zero live connections while
moving towards LINGER_COMPLETE. After the Linger period expires
(or other events mark the end of the linger state) the LINGER_COMPLETE
event should be sent and the network will be shut down. If a
CMD_NETWORK_CONNECTED happens before the LINGER completes
it indicates further desire to keep the network alive and so
the LINGER is aborted. |
private static final int | CMD_LINGER_EXPIREDMessage to self indicating linger delay has expired.
arg1 = Token to ignore old messages. |
public static final int | EVENT_NETWORK_LINGER_COMPLETEInform ConnectivityService that the network LINGER period has
expired.
obj = NetworkAgentInfo |
private static final int | CMD_REEVALUATEMessage to self indicating it's time to evaluate a network's connectivity.
arg1 = Token to ignore old messages. |
public static final int | CMD_NETWORK_DISCONNECTEDInform NetworkMonitor that the network has disconnected. |
public static final int | CMD_FORCE_REEVALUATIONForce evaluation even if it has succeeded in the past.
arg1 = UID responsible for requesting this reeval. Will be billed for data.
arg2 = Number of evaluation attempts to make. (If 0, make INITIAL_ATTEMPTS attempts.) |
private static final int | CMD_CAPTIVE_PORTAL_APP_FINISHEDMessage to self indicating captive portal app finished.
arg1 = one of: CAPTIVE_PORTAL_APP_RETURN_APPEASED,
CAPTIVE_PORTAL_APP_RETURN_UNWANTED,
CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS |
public static final int | EVENT_PROVISIONING_NOTIFICATIONRequest ConnectivityService display provisioning notification.
arg1 = Whether to make the notification visible.
arg2 = NetID.
obj = Intent to be launched when notification selected by user, null if !arg1. |
private static final int | EVENT_APP_BYPASSED_CAPTIVE_PORTALMessage to self indicating sign-in app bypassed captive portal. |
private static final int | EVENT_NO_APP_RESPONSEMessage to self indicating no sign-in app responded. |
private static final int | EVENT_APP_INDICATES_SIGN_IN_IMPOSSIBLEMessage to self indicating sign-in app indicates sign-in is not possible. |
public static final int | CAPTIVE_PORTAL_APP_RETURN_APPEASEDReturn codes from captive portal sign-in app. |
public static final int | CAPTIVE_PORTAL_APP_RETURN_UNWANTED |
public static final int | CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS |
private static final String | LINGER_DELAY_PROPERTY |
private static final int | DEFAULT_LINGER_DELAY_MS |
private final int | mLingerDelayMs |
private int | mLingerToken |
private static final String | REEVALUATE_DELAY_PROPERTY |
private static final int | DEFAULT_REEVALUATE_DELAY_MS |
private static final int | INITIAL_ATTEMPTS |
private static final int | REEVALUATE_PAUSE_MS |
private static final int | PERIODIC_ATTEMPTS |
private static final int | REEVALUATE_ATTEMPTS |
private final int | mReevaluateDelayMs |
private int | mReevaluateToken |
private static final int | INVALID_UID |
private int | mUidResponsibleForReeval |
private final android.content.Context | mContext |
private final android.os.Handler | mConnectivityServiceHandler |
private final com.android.server.connectivity.NetworkAgentInfo | mNetworkAgentInfo |
private final android.telephony.TelephonyManager | mTelephonyManager |
private final android.net.wifi.WifiManager | mWifiManager |
private final android.app.AlarmManager | mAlarmManager |
private final android.net.NetworkRequest | mDefaultRequest |
private String | mServer |
private boolean | mIsCaptivePortalCheckEnabled |
private boolean | mUserDoesNotWant |
private int | mMaxAttempts |
public boolean | systemReady |
private final com.android.internal.util.State | mDefaultState |
private final com.android.internal.util.State | mOfflineState |
private final com.android.internal.util.State | mValidatedState |
private final com.android.internal.util.State | mMaybeNotifyState |
private final com.android.internal.util.State | mEvaluatingState |
private final com.android.internal.util.State | mCaptivePortalState |
private final com.android.internal.util.State | mLingeringState |
private CaptivePortalLoggedInBroadcastReceiver | mCaptivePortalLoggedInBroadcastReceiver |
private String | mCaptivePortalLoggedInResponseToken |
Methods Summary |
---|
private int | isCaptivePortal()Do a URL fetch on a known server to see if we get the data we expect.
Returns HTTP response code.
if (!mIsCaptivePortalCheckEnabled) return 204;
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 https://android-review.googlesource.com/#/c/115180/ lands.
// Network.openConnection() 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
// 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 = mNetworkAgentInfo.linkProperties.getHttpProxy();
if (proxyInfo != null && !Uri.EMPTY.equals(proxyInfo.getPacFileUrl())) {
url = new URL(proxyInfo.getPacFileUrl().toString());
fetchPac = true;
}
}
if (DBG) {
log("Checking " + url.toString() + " on " +
mNetworkAgentInfo.networkInfo.getExtraInfo());
}
urlConnection = (HttpURLConnection) mNetworkAgentInfo.network.openConnection(url);
urlConnection.setInstanceFollowRedirects(fetchPac);
urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
urlConnection.setUseCaches(false);
// Time how long it takes to get a response to our request
long requestTimestamp = SystemClock.elapsedRealtime();
urlConnection.getInputStream();
// Time how long it takes to get a response to our request
long responseTimestamp = SystemClock.elapsedRealtime();
httpResponseCode = urlConnection.getResponseCode();
if (DBG) {
log("isCaptivePortal: ret=" + httpResponseCode +
" headers=" + urlConnection.getHeaderFields());
}
// 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 http://b/9972012.
if (httpResponseCode == 200 && urlConnection.getContentLength() == 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.
}
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
return httpResponseCode;
|
protected void | log(java.lang.String s)
Log.d(TAG + "/" + mNetworkAgentInfo.name(), s);
|
private void | sendNetworkConditionsBroadcast(boolean responseReceived, boolean isCaptivePortal, long requestTimestampMs, long responseTimestampMs)
if (Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 0) {
if (DBG) log("Don't send network conditions - lacking user consent.");
return;
}
if (systemReady == false) return;
Intent latencyBroadcast = new Intent(ACTION_NETWORK_CONDITIONS_MEASURED);
switch (mNetworkAgentInfo.networkInfo.getType()) {
case ConnectivityManager.TYPE_WIFI:
WifiInfo currentWifiInfo = mWifiManager.getConnectionInfo();
if (currentWifiInfo != null) {
// NOTE: getSSID()'s behavior changed in API 17; before that, SSIDs were not
// surrounded by double quotation marks (thus violating the Javadoc), but this
// was changed to match the Javadoc in API 17. Since clients may have started
// sanitizing the output of this method since API 17 was released, we should
// not change it here as it would become impossible to tell whether the SSID is
// simply being surrounded by quotes due to the API, or whether those quotes
// are actually part of the SSID.
latencyBroadcast.putExtra(EXTRA_SSID, currentWifiInfo.getSSID());
latencyBroadcast.putExtra(EXTRA_BSSID, currentWifiInfo.getBSSID());
} else {
if (DBG) logw("network info is TYPE_WIFI but no ConnectionInfo found");
return;
}
break;
case ConnectivityManager.TYPE_MOBILE:
latencyBroadcast.putExtra(EXTRA_NETWORK_TYPE, mTelephonyManager.getNetworkType());
List<CellInfo> info = mTelephonyManager.getAllCellInfo();
if (info == null) return;
int numRegisteredCellInfo = 0;
for (CellInfo cellInfo : info) {
if (cellInfo.isRegistered()) {
numRegisteredCellInfo++;
if (numRegisteredCellInfo > 1) {
if (DBG) log("more than one registered CellInfo. Can't " +
"tell which is active. Bailing.");
return;
}
if (cellInfo instanceof CellInfoCdma) {
CellIdentityCdma cellId = ((CellInfoCdma) cellInfo).getCellIdentity();
latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
} else if (cellInfo instanceof CellInfoGsm) {
CellIdentityGsm cellId = ((CellInfoGsm) cellInfo).getCellIdentity();
latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
} else if (cellInfo instanceof CellInfoLte) {
CellIdentityLte cellId = ((CellInfoLte) cellInfo).getCellIdentity();
latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
} else if (cellInfo instanceof CellInfoWcdma) {
CellIdentityWcdma cellId = ((CellInfoWcdma) cellInfo).getCellIdentity();
latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
} else {
if (DBG) logw("Registered cellinfo is unrecognized");
return;
}
}
}
break;
default:
return;
}
latencyBroadcast.putExtra(EXTRA_CONNECTIVITY_TYPE, mNetworkAgentInfo.networkInfo.getType());
latencyBroadcast.putExtra(EXTRA_RESPONSE_RECEIVED, responseReceived);
latencyBroadcast.putExtra(EXTRA_REQUEST_TIMESTAMP_MS, requestTimestampMs);
if (responseReceived) {
latencyBroadcast.putExtra(EXTRA_IS_CAPTIVE_PORTAL, isCaptivePortal);
latencyBroadcast.putExtra(EXTRA_RESPONSE_TIMESTAMP_MS, responseTimestampMs);
}
mContext.sendBroadcastAsUser(latencyBroadcast, UserHandle.CURRENT,
PERMISSION_ACCESS_NETWORK_CONDITIONS);
|