NetworkMonitor.java revision 49f63fbed4cd84f5da182c85e8b999037dc64f3b
1ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen/* 2ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * Copyright (C) 2014 The Android Open Source Project 3ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * 4ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * Licensed under the Apache License, Version 2.0 (the "License"); 5ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * you may not use this file except in compliance with the License. 6ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * You may obtain a copy of the License at 7ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * 8ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * http://www.apache.org/licenses/LICENSE-2.0 9ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * 10ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * Unless required by applicable law or agreed to in writing, software 11ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * distributed under the License is distributed on an "AS IS" BASIS, 12ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * See the License for the specific language governing permissions and 14ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * limitations under the License. 15ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen */ 16ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 17ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensenpackage com.android.server.connectivity; 18ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 1979a08051c5588d8420656813b21993d490e93dd0Paul Jensenimport android.app.AlarmManager; 20869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport android.app.PendingIntent; 21869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport android.content.BroadcastReceiver; 22869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport android.content.ComponentName; 23ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensenimport android.content.Context; 24869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport android.content.Intent; 25869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport android.content.IntentFilter; 26869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport android.net.ConnectivityManager; 27869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport android.net.Network; 28ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensenimport android.net.NetworkCapabilities; 29ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensenimport android.net.NetworkInfo; 307ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensenimport android.net.TrafficStats; 31306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensenimport android.net.wifi.WifiInfo; 32306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensenimport android.net.wifi.WifiManager; 33ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensenimport android.os.Handler; 34ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensenimport android.os.Message; 35306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensenimport android.os.SystemClock; 36ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensenimport android.os.SystemProperties; 37869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport android.os.UserHandle; 38ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensenimport android.provider.Settings; 39306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensenimport android.telephony.CellIdentityCdma; 40306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensenimport android.telephony.CellIdentityGsm; 41306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensenimport android.telephony.CellIdentityLte; 42306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensenimport android.telephony.CellIdentityWcdma; 43306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensenimport android.telephony.CellInfo; 44306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensenimport android.telephony.CellInfoCdma; 45306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensenimport android.telephony.CellInfoGsm; 46306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensenimport android.telephony.CellInfoLte; 47306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensenimport android.telephony.CellInfoWcdma; 48306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensenimport android.telephony.TelephonyManager; 49ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 50ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensenimport com.android.internal.util.Protocol; 51ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensenimport com.android.internal.util.State; 52ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensenimport com.android.internal.util.StateMachine; 53869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport com.android.server.ConnectivityService; 54ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensenimport com.android.server.connectivity.NetworkAgentInfo; 55ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 56ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensenimport java.io.IOException; 57ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensenimport java.net.HttpURLConnection; 58ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensenimport java.net.URL; 59306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensenimport java.util.List; 60ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 61ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen/** 62ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * {@hide} 63ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen */ 64ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensenpublic class NetworkMonitor extends StateMachine { 65ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private static final boolean DBG = true; 66ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private static final String TAG = "NetworkMonitor"; 67ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private static final String DEFAULT_SERVER = "clients3.google.com"; 68ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private static final int SOCKET_TIMEOUT_MS = 10000; 69306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen public static final String ACTION_NETWORK_CONDITIONS_MEASURED = 70306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen "android.net.conn.NETWORK_CONDITIONS_MEASURED"; 71306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type"; 72306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen public static final String EXTRA_NETWORK_TYPE = "extra_network_type"; 73306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen public static final String EXTRA_RESPONSE_RECEIVED = "extra_response_received"; 74306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen public static final String EXTRA_IS_CAPTIVE_PORTAL = "extra_is_captive_portal"; 75306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen public static final String EXTRA_CELL_ID = "extra_cellid"; 76306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen public static final String EXTRA_SSID = "extra_ssid"; 77306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen public static final String EXTRA_BSSID = "extra_bssid"; 78306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen /** real time since boot */ 79306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen public static final String EXTRA_REQUEST_TIMESTAMP_MS = "extra_request_timestamp_ms"; 80306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen public static final String EXTRA_RESPONSE_TIMESTAMP_MS = "extra_response_timestamp_ms"; 81306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen 82306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen private static final String PERMISSION_ACCESS_NETWORK_CONDITIONS = 83306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen "android.permission.ACCESS_NETWORK_CONDITIONS"; 84ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 85869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen // Intent broadcast when user selects sign-in notification. 86869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen private static final String ACTION_SIGN_IN_REQUESTED = 87869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen "android.net.netmon.sign_in_requested"; 88869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 89869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen // Keep these in sync with CaptivePortalLoginActivity.java. 90869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen // Intent broadcast from CaptivePortalLogin indicating sign-in is complete. 91869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen // Extras: 92869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen // EXTRA_TEXT = netId 93869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen // LOGGED_IN_RESULT = "1" if we should use network, "0" if not. 94869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen private static final String ACTION_CAPTIVE_PORTAL_LOGGED_IN = 95869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen "android.net.netmon.captive_portal_logged_in"; 96869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen private static final String LOGGED_IN_RESULT = "result"; 97869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 98ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen // After a network has been tested this result can be sent with EVENT_NETWORK_TESTED. 99ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen // The network should be used as a default internet connection. It was found to be: 100ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen // 1. a functioning network providing internet access, or 101ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen // 2. a captive portal and the user decided to use it as is. 102ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen public static final int NETWORK_TEST_RESULT_VALID = 0; 103ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen // After a network has been tested this result can be sent with EVENT_NETWORK_TESTED. 104ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen // The network should not be used as a default internet connection. It was found to be: 105ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen // 1. a captive portal and the user is prompted to sign-in, or 106ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen // 2. a captive portal and the user did not want to use it, or 107ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen // 3. a broken network (e.g. DNS failed, connect failed, HTTP request failed). 108ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen public static final int NETWORK_TEST_RESULT_INVALID = 1; 109ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen 110ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private static final int BASE = Protocol.BASE_NETWORK_MONITOR; 111ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 112ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen /** 113ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * Inform NetworkMonitor that their network is connected. 114ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * Initiates Network Validation. 115ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen */ 116ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen public static final int CMD_NETWORK_CONNECTED = BASE + 1; 117ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 118ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen /** 119ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen * Inform ConnectivityService that the network has been tested. 120ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * obj = NetworkAgentInfo 121ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen * arg1 = One of the NETWORK_TESTED_RESULT_* constants. 122ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen */ 123ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen public static final int EVENT_NETWORK_TESTED = BASE + 2; 124ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 125ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen /** 126ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * Inform NetworkMonitor to linger a network. The Monitor should 127ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * start a timer and/or start watching for zero live connections while 128ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * moving towards LINGER_COMPLETE. After the Linger period expires 129ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * (or other events mark the end of the linger state) the LINGER_COMPLETE 130ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * event should be sent and the network will be shut down. If a 131ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * CMD_NETWORK_CONNECTED happens before the LINGER completes 132ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * it indicates further desire to keep the network alive and so 133ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * the LINGER is aborted. 134ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen */ 135ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen public static final int CMD_NETWORK_LINGER = BASE + 3; 136ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 137ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen /** 138ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * Message to self indicating linger delay has expired. 139ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * arg1 = Token to ignore old messages. 140ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen */ 141ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private static final int CMD_LINGER_EXPIRED = BASE + 4; 142ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 143ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen /** 144ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * Inform ConnectivityService that the network LINGER period has 145ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * expired. 146ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * obj = NetworkAgentInfo 147ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen */ 148ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen public static final int EVENT_NETWORK_LINGER_COMPLETE = BASE + 5; 149ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 150ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen /** 151ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * Message to self indicating it's time to evaluate a network's connectivity. 152ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * arg1 = Token to ignore old messages. 153ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen */ 154869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen private static final int CMD_REEVALUATE = BASE + 6; 155ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 156ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen /** 157ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * Inform NetworkMonitor that the network has disconnected. 158ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen */ 1597ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen public static final int CMD_NETWORK_DISCONNECTED = BASE + 7; 160ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 161ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen /** 162ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * Force evaluation even if it has succeeded in the past. 1637ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen * arg1 = UID responsible for requesting this reeval. Will be billed for data. 164ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen */ 1657ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen public static final int CMD_FORCE_REEVALUATION = BASE + 8; 166869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 167869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen /** 168869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * Message to self indicating captive portal login is complete. 169869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * arg1 = Token to ignore old messages. 170869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * arg2 = 1 if we should use this network, 0 otherwise. 171869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen */ 1727ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen private static final int CMD_CAPTIVE_PORTAL_LOGGED_IN = BASE + 9; 173869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 174869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen /** 175869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * Message to self indicating user desires to log into captive portal. 176869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * arg1 = Token to ignore old messages. 177869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen */ 1787ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen private static final int CMD_USER_WANTS_SIGN_IN = BASE + 10; 179869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 180869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen /** 181869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * Request ConnectivityService display provisioning notification. 182869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * arg1 = Whether to make the notification visible. 183fdc4e4af7305514359e041dbec742f4b6561e393Paul Jensen * arg2 = NetID. 184fdc4e4af7305514359e041dbec742f4b6561e393Paul Jensen * obj = Intent to be launched when notification selected by user, null if !arg1. 185869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen */ 1867ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen public static final int EVENT_PROVISIONING_NOTIFICATION = BASE + 11; 187869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 188869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen /** 189869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * Message to self indicating sign-in app bypassed captive portal. 190869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen */ 1917ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen private static final int EVENT_APP_BYPASSED_CAPTIVE_PORTAL = BASE + 12; 192869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 193869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen /** 194869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * Message to self indicating no sign-in app responded. 195869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen */ 1967ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen private static final int EVENT_NO_APP_RESPONSE = BASE + 13; 197869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 198869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen /** 199869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * Message to self indicating sign-in app indicates sign-in is not possible. 200869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen */ 2017ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen private static final int EVENT_APP_INDICATES_SIGN_IN_IMPOSSIBLE = BASE + 14; 202ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 203ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private static final String LINGER_DELAY_PROPERTY = "persist.netmon.linger"; 204ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen // Default to 30s linger time-out. 205ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private static final int DEFAULT_LINGER_DELAY_MS = 30000; 206ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private final int mLingerDelayMs; 207ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private int mLingerToken = 0; 208ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 209ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen // Negative values disable reevaluation. 210ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private static final String REEVALUATE_DELAY_PROPERTY = "persist.netmon.reeval_delay"; 211ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen // Default to 5s reevaluation delay. 212ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private static final int DEFAULT_REEVALUATE_DELAY_MS = 5000; 213869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen private static final int MAX_RETRIES = 10; 214ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private final int mReevaluateDelayMs; 215ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private int mReevaluateToken = 0; 2167ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen private static final int INVALID_UID = -1; 2177ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen private int mUidResponsibleForReeval = INVALID_UID; 218ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 219869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen private int mCaptivePortalLoggedInToken = 0; 220869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen private int mUserPromptedToken = 0; 221869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 222ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private final Context mContext; 223ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private final Handler mConnectivityServiceHandler; 224ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private final NetworkAgentInfo mNetworkAgentInfo; 225306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen private final TelephonyManager mTelephonyManager; 226306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen private final WifiManager mWifiManager; 22779a08051c5588d8420656813b21993d490e93dd0Paul Jensen private final AlarmManager mAlarmManager; 228ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 229ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private String mServer; 230ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private boolean mIsCaptivePortalCheckEnabled = false; 231ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 232ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen // Set if the user explicitly selected "Do not use this network" in captive portal sign-in app. 233ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen private boolean mUserDoesNotWant = false; 234ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen 235fb68f8fbe0213841f393f8bdb5313e4e44f4f116Robert Greenwalt public boolean systemReady = false; 236fb68f8fbe0213841f393f8bdb5313e4e44f4f116Robert Greenwalt 237ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private State mDefaultState = new DefaultState(); 238ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private State mOfflineState = new OfflineState(); 239ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private State mValidatedState = new ValidatedState(); 240ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private State mEvaluatingState = new EvaluatingState(); 241869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen private State mUserPromptedState = new UserPromptedState(); 242ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private State mCaptivePortalState = new CaptivePortalState(); 243ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private State mLingeringState = new LingeringState(); 244ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 245ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen public NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo) { 246ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen // Add suffix indicating which NetworkMonitor we're talking about. 247ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen super(TAG + networkAgentInfo.name()); 248ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 249ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen mContext = context; 250ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen mConnectivityServiceHandler = handler; 251ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen mNetworkAgentInfo = networkAgentInfo; 252306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 253306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); 25479a08051c5588d8420656813b21993d490e93dd0Paul Jensen mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 255ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 256ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen addState(mDefaultState); 257ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen addState(mOfflineState, mDefaultState); 258ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen addState(mValidatedState, mDefaultState); 259ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen addState(mEvaluatingState, mDefaultState); 260869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen addState(mUserPromptedState, mDefaultState); 261ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen addState(mCaptivePortalState, mDefaultState); 262ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen addState(mLingeringState, mDefaultState); 26349f63fbed4cd84f5da182c85e8b999037dc64f3bRobert Greenwalt setInitialState(mDefaultState); 264ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 265ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen mServer = Settings.Global.getString(mContext.getContentResolver(), 266ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen Settings.Global.CAPTIVE_PORTAL_SERVER); 267ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen if (mServer == null) mServer = DEFAULT_SERVER; 268ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 269ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen mLingerDelayMs = SystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS); 270ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen mReevaluateDelayMs = SystemProperties.getInt(REEVALUATE_DELAY_PROPERTY, 271ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen DEFAULT_REEVALUATE_DELAY_MS); 272ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 273869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen mIsCaptivePortalCheckEnabled = Settings.Global.getInt(mContext.getContentResolver(), 274869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED, 1) == 1; 275ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 276ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen start(); 277ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 278ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 279ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private class DefaultState extends State { 280ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen @Override 281ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen public boolean processMessage(Message message) { 282ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen if (DBG) log(getName() + message.toString()); 283ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen switch (message.what) { 284ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen case CMD_NETWORK_LINGER: 285ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen if (DBG) log("Lingering"); 286ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen transitionTo(mLingeringState); 287d6a3f7ed90d7fa861f579968f12cc30015b3a989Paul Jensen return HANDLED; 288ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen case CMD_NETWORK_CONNECTED: 289ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen if (DBG) log("Connected"); 290ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen transitionTo(mEvaluatingState); 291d6a3f7ed90d7fa861f579968f12cc30015b3a989Paul Jensen return HANDLED; 292ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen case CMD_NETWORK_DISCONNECTED: 2931fd9aeef08fac363ec3ef2eb61cea519a04c51fdRobert Greenwalt if (DBG) log("Disconnected - quitting"); 2941fd9aeef08fac363ec3ef2eb61cea519a04c51fdRobert Greenwalt quit(); 295d6a3f7ed90d7fa861f579968f12cc30015b3a989Paul Jensen return HANDLED; 296ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen case CMD_FORCE_REEVALUATION: 297ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen if (DBG) log("Forcing reevaluation"); 2987ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen mUidResponsibleForReeval = message.arg1; 299ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen transitionTo(mEvaluatingState); 300d6a3f7ed90d7fa861f579968f12cc30015b3a989Paul Jensen return HANDLED; 301ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen default: 302d6a3f7ed90d7fa861f579968f12cc30015b3a989Paul Jensen return HANDLED; 303ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 304ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 305ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 306ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 307ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private class OfflineState extends State { 308ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen @Override 309ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen public void enter() { 310ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED, 311ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen NETWORK_TEST_RESULT_INVALID, 0, mNetworkAgentInfo)); 312ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen } 313ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen 314ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen @Override 315ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen public boolean processMessage(Message message) { 316ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen if (DBG) log(getName() + message.toString()); 317ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen switch (message.what) { 318ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen case CMD_FORCE_REEVALUATION: 319ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen // If the user has indicated they explicitly do not want to use this network, 320ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen // don't allow a reevaluation as this will be pointless and could result in 321ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen // the user being annoyed with repeated unwanted notifications. 322ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen return mUserDoesNotWant ? HANDLED : NOT_HANDLED; 323ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen default: 324ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen return NOT_HANDLED; 325ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen } 326ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 327ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 328ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 329ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private class ValidatedState extends State { 330ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen @Override 331ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen public void enter() { 332ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen if (DBG) log("Validated"); 333ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED, 334ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen NETWORK_TEST_RESULT_VALID, 0, mNetworkAgentInfo)); 335ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 336ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 337ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen @Override 338ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen public boolean processMessage(Message message) { 339ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen if (DBG) log(getName() + message.toString()); 340ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen switch (message.what) { 341ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen case CMD_NETWORK_CONNECTED: 342ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen transitionTo(mValidatedState); 343d6a3f7ed90d7fa861f579968f12cc30015b3a989Paul Jensen return HANDLED; 344ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen default: 345ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen return NOT_HANDLED; 346ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 347ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 348ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 349ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 350ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private class EvaluatingState extends State { 351869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen private int mRetries; 352869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 353ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen @Override 354ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen public void enter() { 355869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen mRetries = 0; 356ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen sendMessage(CMD_REEVALUATE, ++mReevaluateToken, 0); 3577ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen if (mUidResponsibleForReeval != INVALID_UID) { 3587ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen TrafficStats.setThreadStatsUid(mUidResponsibleForReeval); 3597ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen mUidResponsibleForReeval = INVALID_UID; 3607ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen } 361ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 362ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 363ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen @Override 364ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen public boolean processMessage(Message message) { 365ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen if (DBG) log(getName() + message.toString()); 366ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen switch (message.what) { 367ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen case CMD_REEVALUATE: 368ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen if (message.arg1 != mReevaluateToken) 369d6a3f7ed90d7fa861f579968f12cc30015b3a989Paul Jensen return HANDLED; 3706bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen if (mNetworkAgentInfo.isVPN()) { 3716bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen transitionTo(mValidatedState); 372d6a3f7ed90d7fa861f579968f12cc30015b3a989Paul Jensen return HANDLED; 3736bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 374ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen // If network provides no internet connectivity adjust evaluation. 375869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen if (!mNetworkAgentInfo.networkCapabilities.hasCapability( 376ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen NetworkCapabilities.NET_CAPABILITY_INTERNET)) { 377ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen // TODO: Try to verify something works. Do all gateways respond to pings? 378ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen transitionTo(mValidatedState); 379d6a3f7ed90d7fa861f579968f12cc30015b3a989Paul Jensen return HANDLED; 380ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 3817ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen int httpResponseCode = isCaptivePortal(); 382ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen if (httpResponseCode == 204) { 383ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen transitionTo(mValidatedState); 384ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } else if (httpResponseCode >= 200 && httpResponseCode <= 399) { 385a68d21350266a6abc16aeb3fec84eafd85b77cc8Paul Jensen transitionTo(mUserPromptedState); 386869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } else if (++mRetries > MAX_RETRIES) { 387869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen transitionTo(mOfflineState); 388869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } else if (mReevaluateDelayMs >= 0) { 389869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0); 390869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen sendMessageDelayed(msg, mReevaluateDelayMs); 391ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 392d6a3f7ed90d7fa861f579968f12cc30015b3a989Paul Jensen return HANDLED; 3937ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen case CMD_FORCE_REEVALUATION: 3947ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen // Ignore duplicate requests. 3957ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen return HANDLED; 396ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen default: 397ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen return NOT_HANDLED; 398ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 399ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 4007ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen 4017ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen @Override 4027ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen public void exit() { 4037ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen TrafficStats.clearThreadStatsUid(); 4047ccd3dfd53d8d45c447398ff137f052865dfd3b3Paul Jensen } 405ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 406ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 407869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen private class UserPromptedState extends State { 408869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen private class UserRespondedBroadcastReceiver extends BroadcastReceiver { 409869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen private final int mToken; 410869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen UserRespondedBroadcastReceiver(int token) { 411869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen mToken = token; 412869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 413869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen @Override 414869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen public void onReceive(Context context, Intent intent) { 415869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen if (Integer.parseInt(intent.getStringExtra(Intent.EXTRA_TEXT)) == 416869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen mNetworkAgentInfo.network.netId) { 417869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen sendMessage(obtainMessage(CMD_USER_WANTS_SIGN_IN, mToken)); 418869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 419869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 420869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 421869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 422869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen private UserRespondedBroadcastReceiver mUserRespondedBroadcastReceiver; 423869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 424869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen @Override 425869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen public void enter() { 426ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED, 427ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen NETWORK_TEST_RESULT_INVALID, 0, mNetworkAgentInfo)); 428869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen // Wait for user to select sign-in notifcation. 429869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen mUserRespondedBroadcastReceiver = new UserRespondedBroadcastReceiver( 430869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen ++mUserPromptedToken); 431869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen IntentFilter filter = new IntentFilter(ACTION_SIGN_IN_REQUESTED); 432869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen mContext.registerReceiver(mUserRespondedBroadcastReceiver, filter); 433869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen // Initiate notification to sign-in. 434869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen Intent intent = new Intent(ACTION_SIGN_IN_REQUESTED); 435869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen intent.putExtra(Intent.EXTRA_TEXT, String.valueOf(mNetworkAgentInfo.network.netId)); 436fdc4e4af7305514359e041dbec742f4b6561e393Paul Jensen Message message = obtainMessage(EVENT_PROVISIONING_NOTIFICATION, 1, 437fdc4e4af7305514359e041dbec742f4b6561e393Paul Jensen mNetworkAgentInfo.network.netId, 438869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)); 439869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen mConnectivityServiceHandler.sendMessage(message); 440869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 441869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 442869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen @Override 443869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen public boolean processMessage(Message message) { 444869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen if (DBG) log(getName() + message.toString()); 445869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen switch (message.what) { 446869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen case CMD_USER_WANTS_SIGN_IN: 447869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen if (message.arg1 != mUserPromptedToken) 448d6a3f7ed90d7fa861f579968f12cc30015b3a989Paul Jensen return HANDLED; 449a68d21350266a6abc16aeb3fec84eafd85b77cc8Paul Jensen transitionTo(mCaptivePortalState); 450d6a3f7ed90d7fa861f579968f12cc30015b3a989Paul Jensen return HANDLED; 451869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen default: 452869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen return NOT_HANDLED; 453869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 454869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 455869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 456869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen @Override 457869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen public void exit() { 458fdc4e4af7305514359e041dbec742f4b6561e393Paul Jensen Message message = obtainMessage(EVENT_PROVISIONING_NOTIFICATION, 0, 459fdc4e4af7305514359e041dbec742f4b6561e393Paul Jensen mNetworkAgentInfo.network.netId, null); 460869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen mConnectivityServiceHandler.sendMessage(message); 461869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen mContext.unregisterReceiver(mUserRespondedBroadcastReceiver); 462869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen mUserRespondedBroadcastReceiver = null; 463869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 464869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 465869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 466ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private class CaptivePortalState extends State { 467869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen private class CaptivePortalLoggedInBroadcastReceiver extends BroadcastReceiver { 468869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen private final int mToken; 469869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 470869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen CaptivePortalLoggedInBroadcastReceiver(int token) { 471869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen mToken = token; 472869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 473869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 474869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen @Override 475869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen public void onReceive(Context context, Intent intent) { 476869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen if (Integer.parseInt(intent.getStringExtra(Intent.EXTRA_TEXT)) == 477869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen mNetworkAgentInfo.network.netId) { 478869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen sendMessage(obtainMessage(CMD_CAPTIVE_PORTAL_LOGGED_IN, mToken, 479869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen Integer.parseInt(intent.getStringExtra(LOGGED_IN_RESULT)))); 480869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 481869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 482869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 483869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 484869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen private CaptivePortalLoggedInBroadcastReceiver mCaptivePortalLoggedInBroadcastReceiver; 485869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 486ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen @Override 487ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen public void enter() { 488869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen Intent intent = new Intent(Intent.ACTION_SEND); 489869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen intent.putExtra(Intent.EXTRA_TEXT, String.valueOf(mNetworkAgentInfo.network.netId)); 490869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen intent.setType("text/plain"); 491869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen intent.setComponent(new ComponentName("com.android.captiveportallogin", 492869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen "com.android.captiveportallogin.CaptivePortalLoginActivity")); 493869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK); 494869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 495869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen // Wait for result. 496869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen mCaptivePortalLoggedInBroadcastReceiver = new CaptivePortalLoggedInBroadcastReceiver( 497869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen ++mCaptivePortalLoggedInToken); 498869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen IntentFilter filter = new IntentFilter(ACTION_CAPTIVE_PORTAL_LOGGED_IN); 499869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen mContext.registerReceiver(mCaptivePortalLoggedInBroadcastReceiver, filter); 500869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen // Initiate app to log in. 501869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen mContext.startActivityAsUser(intent, UserHandle.CURRENT); 502ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 503ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 504ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen @Override 505ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen public boolean processMessage(Message message) { 506ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen if (DBG) log(getName() + message.toString()); 507ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen switch (message.what) { 508869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen case CMD_CAPTIVE_PORTAL_LOGGED_IN: 509869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen if (message.arg1 != mCaptivePortalLoggedInToken) 510d6a3f7ed90d7fa861f579968f12cc30015b3a989Paul Jensen return HANDLED; 511869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen if (message.arg2 == 0) { 512ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen mUserDoesNotWant = true; 513869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen // TODO: Should teardown network. 514869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen transitionTo(mOfflineState); 515869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } else { 516869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen transitionTo(mValidatedState); 517869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 518d6a3f7ed90d7fa861f579968f12cc30015b3a989Paul Jensen return HANDLED; 519ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen default: 520ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen return NOT_HANDLED; 521ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 522ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 523869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 524869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen @Override 525869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen public void exit() { 526869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen mContext.unregisterReceiver(mCaptivePortalLoggedInBroadcastReceiver); 527869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen mCaptivePortalLoggedInBroadcastReceiver = null; 528869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 529ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 530ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 531ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private class LingeringState extends State { 53279a08051c5588d8420656813b21993d490e93dd0Paul Jensen private static final String ACTION_LINGER_EXPIRED = "android.net.netmon.lingerExpired"; 53379a08051c5588d8420656813b21993d490e93dd0Paul Jensen private static final String EXTRA_NETID = "lingerExpiredNetId"; 53479a08051c5588d8420656813b21993d490e93dd0Paul Jensen private static final String EXTRA_TOKEN = "lingerExpiredToken"; 53579a08051c5588d8420656813b21993d490e93dd0Paul Jensen 53679a08051c5588d8420656813b21993d490e93dd0Paul Jensen private class LingerExpiredBroadcastReceiver extends BroadcastReceiver { 53779a08051c5588d8420656813b21993d490e93dd0Paul Jensen @Override 53879a08051c5588d8420656813b21993d490e93dd0Paul Jensen public void onReceive(Context context, Intent intent) { 53979a08051c5588d8420656813b21993d490e93dd0Paul Jensen if (intent.getAction().equals(ACTION_LINGER_EXPIRED) && 54079a08051c5588d8420656813b21993d490e93dd0Paul Jensen Integer.parseInt(intent.getStringExtra(EXTRA_NETID)) == 54179a08051c5588d8420656813b21993d490e93dd0Paul Jensen mNetworkAgentInfo.network.netId) { 54279a08051c5588d8420656813b21993d490e93dd0Paul Jensen sendMessage(CMD_LINGER_EXPIRED, 54379a08051c5588d8420656813b21993d490e93dd0Paul Jensen Integer.parseInt(intent.getStringExtra(EXTRA_TOKEN))); 54479a08051c5588d8420656813b21993d490e93dd0Paul Jensen } 54579a08051c5588d8420656813b21993d490e93dd0Paul Jensen } 54679a08051c5588d8420656813b21993d490e93dd0Paul Jensen } 54779a08051c5588d8420656813b21993d490e93dd0Paul Jensen 54879a08051c5588d8420656813b21993d490e93dd0Paul Jensen private BroadcastReceiver mBroadcastReceiver; 54979a08051c5588d8420656813b21993d490e93dd0Paul Jensen private PendingIntent mIntent; 55079a08051c5588d8420656813b21993d490e93dd0Paul Jensen 551ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen @Override 552ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen public void enter() { 55379a08051c5588d8420656813b21993d490e93dd0Paul Jensen mBroadcastReceiver = new LingerExpiredBroadcastReceiver(); 55479a08051c5588d8420656813b21993d490e93dd0Paul Jensen mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(ACTION_LINGER_EXPIRED)); 55579a08051c5588d8420656813b21993d490e93dd0Paul Jensen 55679a08051c5588d8420656813b21993d490e93dd0Paul Jensen Intent intent = new Intent(ACTION_LINGER_EXPIRED, null); 55779a08051c5588d8420656813b21993d490e93dd0Paul Jensen intent.putExtra(EXTRA_NETID, String.valueOf(mNetworkAgentInfo.network.netId)); 55879a08051c5588d8420656813b21993d490e93dd0Paul Jensen intent.putExtra(EXTRA_TOKEN, String.valueOf(++mLingerToken)); 55979a08051c5588d8420656813b21993d490e93dd0Paul Jensen mIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); 56079a08051c5588d8420656813b21993d490e93dd0Paul Jensen long wakeupTime = SystemClock.elapsedRealtime() + mLingerDelayMs; 56179a08051c5588d8420656813b21993d490e93dd0Paul Jensen mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, wakeupTime, 56279a08051c5588d8420656813b21993d490e93dd0Paul Jensen // Give a specific window so we aren't subject to unknown inexactitude. 56379a08051c5588d8420656813b21993d490e93dd0Paul Jensen mLingerDelayMs / 6, mIntent); 564ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 565ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 566ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen @Override 567ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen public boolean processMessage(Message message) { 568ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen if (DBG) log(getName() + message.toString()); 569ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen switch (message.what) { 570ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen case CMD_NETWORK_CONNECTED: 571ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen // Go straight to active as we've already evaluated. 572ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen transitionTo(mValidatedState); 573d6a3f7ed90d7fa861f579968f12cc30015b3a989Paul Jensen return HANDLED; 574ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen case CMD_LINGER_EXPIRED: 575ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen if (message.arg1 != mLingerToken) 576d6a3f7ed90d7fa861f579968f12cc30015b3a989Paul Jensen return HANDLED; 577ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen mConnectivityServiceHandler.sendMessage( 578ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen obtainMessage(EVENT_NETWORK_LINGER_COMPLETE, mNetworkAgentInfo)); 579d6a3f7ed90d7fa861f579968f12cc30015b3a989Paul Jensen return HANDLED; 580ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen case CMD_FORCE_REEVALUATION: 581ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen // Ignore reevaluation attempts when lingering. A reevaluation could result 582ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen // in a transition to the validated state which would abort the linger 583ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen // timeout. Lingering is the result of score assessment; validity is 584ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen // irrelevant. 585ad50a1fed01e7c24531ad26d9de70c7b0127ea76Paul Jensen return HANDLED; 586ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen default: 587ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen return NOT_HANDLED; 588ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 589ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 59079a08051c5588d8420656813b21993d490e93dd0Paul Jensen 59179a08051c5588d8420656813b21993d490e93dd0Paul Jensen @Override 59279a08051c5588d8420656813b21993d490e93dd0Paul Jensen public void exit() { 59379a08051c5588d8420656813b21993d490e93dd0Paul Jensen mAlarmManager.cancel(mIntent); 59479a08051c5588d8420656813b21993d490e93dd0Paul Jensen mContext.unregisterReceiver(mBroadcastReceiver); 59579a08051c5588d8420656813b21993d490e93dd0Paul Jensen } 596ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 597ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 598ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen /** 599ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * Do a URL fetch on a known server to see if we get the data we expect. 600ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen * Returns HTTP response code. 601ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen */ 602ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen private int isCaptivePortal() { 603ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen if (!mIsCaptivePortalCheckEnabled) return 204; 604ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen 605ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen HttpURLConnection urlConnection = null; 606869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen int httpResponseCode = 599; 607ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen try { 608e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen URL url = new URL("http", mServer, "/generate_204"); 609e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen if (DBG) { 610e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen log("Checking " + url.toString() + " on " + 611e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen mNetworkAgentInfo.networkInfo.getExtraInfo()); 612e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen } 6139f1274b7e43d14c7e3a42148ebfda3905fec8b06Lorenzo Colitti urlConnection = (HttpURLConnection) mNetworkAgentInfo.network.openConnection(url); 614e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen urlConnection.setInstanceFollowRedirects(false); 615e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS); 616e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS); 617e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen urlConnection.setUseCaches(false); 618306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen 619306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen // Time how long it takes to get a response to our request 620306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen long requestTimestamp = SystemClock.elapsedRealtime(); 621306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen 622e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen urlConnection.getInputStream(); 623306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen 624306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen // Time how long it takes to get a response to our request 625306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen long responseTimestamp = SystemClock.elapsedRealtime(); 626306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen 627e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen httpResponseCode = urlConnection.getResponseCode(); 628e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen if (DBG) { 629e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen log("isCaptivePortal: ret=" + httpResponseCode + 630e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen " headers=" + urlConnection.getHeaderFields()); 631e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen } 632e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen // NOTE: We may want to consider an "HTTP/1.0 204" response to be a captive 633e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen // portal. The only example of this seen so far was a captive portal. For 634e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen // the time being go with prior behavior of assuming it's not a captive 635e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen // portal. If it is considered a captive portal, a different sign-in URL 636e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen // is needed (i.e. can't browse a 204). This could be the result of an HTTP 637e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen // proxy server. 638e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen 639e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen // Consider 200 response with "Content-length=0" to not be a captive portal. 640e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen // There's no point in considering this a captive portal as the user cannot 641e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen // sign-in to an empty page. Probably the result of a broken transparent proxy. 642e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen // See http://b/9972012. 643e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen if (httpResponseCode == 200 && urlConnection.getContentLength() == 0) { 644e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen if (DBG) log("Empty 200 response interpreted as 204 response."); 645e547ff281020b08eb51ef7b2786831f7aacdd73cPaul Jensen httpResponseCode = 204; 646ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 647306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen 648306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen sendNetworkConditionsBroadcast(true /* response received */, httpResponseCode == 204, 649306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen requestTimestamp, responseTimestamp); 650ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } catch (IOException e) { 651ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen if (DBG) log("Probably not a portal: exception " + e); 652869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen if (httpResponseCode == 599) { 653869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen // TODO: Ping gateway and DNS server and log results. 654869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 655ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } finally { 656ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen if (urlConnection != null) { 657ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen urlConnection.disconnect(); 658ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 659ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 660ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen return httpResponseCode; 661ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen } 662306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen 663306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen /** 664306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen * @param responseReceived - whether or not we received a valid HTTP response to our request. 665306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen * If false, isCaptivePortal and responseTimestampMs are ignored 666306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen * TODO: This should be moved to the transports. The latency could be passed to the transports 667306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen * along with the captive portal result. Currently the TYPE_MOBILE broadcasts appear unused so 668306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen * perhaps this could just be added to the WiFi transport only. 669306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen */ 670306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen private void sendNetworkConditionsBroadcast(boolean responseReceived, boolean isCaptivePortal, 671306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen long requestTimestampMs, long responseTimestampMs) { 672306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen if (Settings.Global.getInt(mContext.getContentResolver(), 673306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 0) { 674306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen if (DBG) log("Don't send network conditions - lacking user consent."); 675306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen return; 676306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen } 677306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen 678fb68f8fbe0213841f393f8bdb5313e4e44f4f116Robert Greenwalt if (systemReady == false) return; 679fb68f8fbe0213841f393f8bdb5313e4e44f4f116Robert Greenwalt 680306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen Intent latencyBroadcast = new Intent(ACTION_NETWORK_CONDITIONS_MEASURED); 681306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen switch (mNetworkAgentInfo.networkInfo.getType()) { 682306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen case ConnectivityManager.TYPE_WIFI: 683306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen WifiInfo currentWifiInfo = mWifiManager.getConnectionInfo(); 684306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen if (currentWifiInfo != null) { 685306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen // NOTE: getSSID()'s behavior changed in API 17; before that, SSIDs were not 686306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen // surrounded by double quotation marks (thus violating the Javadoc), but this 687306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen // was changed to match the Javadoc in API 17. Since clients may have started 688306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen // sanitizing the output of this method since API 17 was released, we should 689306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen // not change it here as it would become impossible to tell whether the SSID is 690306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen // simply being surrounded by quotes due to the API, or whether those quotes 691306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen // are actually part of the SSID. 692306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen latencyBroadcast.putExtra(EXTRA_SSID, currentWifiInfo.getSSID()); 693306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen latencyBroadcast.putExtra(EXTRA_BSSID, currentWifiInfo.getBSSID()); 694306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen } else { 695306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen if (DBG) logw("network info is TYPE_WIFI but no ConnectionInfo found"); 696306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen return; 697306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen } 698306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen break; 699306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen case ConnectivityManager.TYPE_MOBILE: 700306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen latencyBroadcast.putExtra(EXTRA_NETWORK_TYPE, mTelephonyManager.getNetworkType()); 701306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen List<CellInfo> info = mTelephonyManager.getAllCellInfo(); 702306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen if (info == null) return; 703306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen int numRegisteredCellInfo = 0; 704306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen for (CellInfo cellInfo : info) { 705306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen if (cellInfo.isRegistered()) { 706306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen numRegisteredCellInfo++; 707306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen if (numRegisteredCellInfo > 1) { 708306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen if (DBG) log("more than one registered CellInfo. Can't " + 709306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen "tell which is active. Bailing."); 710306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen return; 711306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen } 712306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen if (cellInfo instanceof CellInfoCdma) { 713306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen CellIdentityCdma cellId = ((CellInfoCdma) cellInfo).getCellIdentity(); 714306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId); 715306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen } else if (cellInfo instanceof CellInfoGsm) { 716306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen CellIdentityGsm cellId = ((CellInfoGsm) cellInfo).getCellIdentity(); 717306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId); 718306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen } else if (cellInfo instanceof CellInfoLte) { 719306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen CellIdentityLte cellId = ((CellInfoLte) cellInfo).getCellIdentity(); 720306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId); 721306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen } else if (cellInfo instanceof CellInfoWcdma) { 722306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen CellIdentityWcdma cellId = ((CellInfoWcdma) cellInfo).getCellIdentity(); 723306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId); 724306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen } else { 725306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen if (DBG) logw("Registered cellinfo is unrecognized"); 726306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen return; 727306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen } 728306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen } 729306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen } 730306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen break; 731306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen default: 732306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen return; 733306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen } 734306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen latencyBroadcast.putExtra(EXTRA_CONNECTIVITY_TYPE, mNetworkAgentInfo.networkInfo.getType()); 735306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen latencyBroadcast.putExtra(EXTRA_RESPONSE_RECEIVED, responseReceived); 736306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen latencyBroadcast.putExtra(EXTRA_REQUEST_TIMESTAMP_MS, requestTimestampMs); 737306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen 738306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen if (responseReceived) { 739306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen latencyBroadcast.putExtra(EXTRA_IS_CAPTIVE_PORTAL, isCaptivePortal); 740306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen latencyBroadcast.putExtra(EXTRA_RESPONSE_TIMESTAMP_MS, responseTimestampMs); 741306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen } 74255298581a0750505bc7da0539fe94255f95326a4Paul Jensen mContext.sendBroadcastAsUser(latencyBroadcast, UserHandle.CURRENT, 74355298581a0750505bc7da0539fe94255f95326a4Paul Jensen PERMISSION_ACCESS_NETWORK_CONDITIONS); 744306f1a45c636e3721ae4b84b8797e6349ae6ff57Paul Jensen } 745ca8f16ad14819ba17f5ff3d2e2bf6fbc9bbaa9f7Paul Jensen} 746