DataConnectionTracker.java revision 0badd0b700ed618dac421cb6cde4654b51acb3a4
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.internal.telephony; 18 19import android.app.PendingIntent; 20import android.os.AsyncResult; 21import android.os.Handler; 22import android.os.INetStatService; 23import android.os.Message; 24import android.os.RemoteException; 25import android.provider.Settings; 26import android.provider.Settings.SettingNotFoundException; 27import android.text.TextUtils; 28import android.util.Log; 29 30import java.util.ArrayList; 31 32/** 33 * {@hide} 34 * 35 */ 36public abstract class DataConnectionTracker extends Handler { 37 protected static final boolean DBG = true; 38 protected final String LOG_TAG = "DataConnectionTracker"; 39 40 /** 41 * IDLE: ready to start data connection setup, default state 42 * INITING: state of issued setupDefaultPDP() but not finish yet 43 * CONNECTING: state of issued startPppd() but not finish yet 44 * SCANNING: data connection fails with one apn but other apns are available 45 * ready to start data connection on other apns (before INITING) 46 * CONNECTED: IP connection is setup 47 * DISCONNECTING: Connection.disconnect() has been called, but PDP 48 * context is not yet deactivated 49 * FAILED: data connection fail for all apns settings 50 * 51 * getDataConnectionState() maps State to DataState 52 * FAILED or IDLE : DISCONNECTED 53 * INITING or CONNECTING or SCANNING: CONNECTING 54 * CONNECTED : CONNECTED or DISCONNECTING 55 */ 56 public enum State { 57 IDLE, 58 INITING, 59 CONNECTING, 60 SCANNING, 61 CONNECTED, 62 DISCONNECTING, 63 FAILED 64 } 65 66 public enum Activity { 67 NONE, 68 DATAIN, 69 DATAOUT, 70 DATAINANDOUT, 71 DORMANT 72 } 73 74 //***** Event Codes 75 protected static final int EVENT_DATA_SETUP_COMPLETE = 1; 76 protected static final int EVENT_RADIO_AVAILABLE = 3; 77 protected static final int EVENT_RECORDS_LOADED = 4; 78 protected static final int EVENT_TRY_SETUP_DATA = 5; 79 protected static final int EVENT_DATA_STATE_CHANGED = 6; 80 protected static final int EVENT_POLL_PDP = 7; 81 protected static final int EVENT_GET_PDP_LIST_COMPLETE = 11; 82 protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 12; 83 protected static final int EVENT_VOICE_CALL_STARTED = 14; 84 protected static final int EVENT_VOICE_CALL_ENDED = 15; 85 protected static final int EVENT_GPRS_DETACHED = 19; 86 protected static final int EVENT_LINK_STATE_CHANGED = 20; 87 protected static final int EVENT_ROAMING_ON = 21; 88 protected static final int EVENT_ROAMING_OFF = 22; 89 protected static final int EVENT_ENABLE_NEW_APN = 23; 90 protected static final int EVENT_RESTORE_DEFAULT_APN = 24; 91 protected static final int EVENT_DISCONNECT_DONE = 25; 92 protected static final int EVENT_GPRS_ATTACHED = 26; 93 protected static final int EVENT_START_NETSTAT_POLL = 27; 94 protected static final int EVENT_START_RECOVERY = 28; 95 protected static final int EVENT_APN_CHANGED = 29; 96 protected static final int EVENT_CDMA_DATA_DETACHED = 30; 97 protected static final int EVENT_NV_READY = 31; 98 protected static final int EVENT_PS_RESTRICT_ENABLED = 32; 99 protected static final int EVENT_PS_RESTRICT_DISABLED = 33; 100 public static final int EVENT_CLEAN_UP_CONNECTION = 34; 101 protected static final int EVENT_CDMA_OTA_PROVISION = 35; 102 protected static final int EVENT_RESTART_RADIO = 36; 103 104 //***** Constants 105 106 protected static final int APN_INVALID_ID = -1; 107 protected static final int APN_DEFAULT_ID = 0; 108 protected static final int APN_MMS_ID = 1; 109 protected static final int APN_SUPL_ID = 2; 110 protected static final int APN_DUN_ID = 3; 111 protected static final int APN_HIPRI_ID = 4; 112 protected static final int APN_NUM_TYPES = 5; 113 114 protected boolean[] dataEnabled = new boolean[APN_NUM_TYPES]; 115 protected int enabledCount = 0; 116 117 /* Currently requested APN type */ 118 protected String mRequestedApnType = Phone.APN_TYPE_DEFAULT; 119 120 /** Retry configuration: A doubling of retry times from 5secs to 30minutes */ 121 protected static final String DEFAULT_DATA_RETRY_CONFIG = "default_randomization=2000," 122 + "5000,10000,20000,40000,80000:5000,160000:5000," 123 + "320000:5000,640000:5000,1280000:5000,1800000:5000"; 124 125 /** Slow poll when attempting connection recovery. */ 126 protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000; 127 /** Default ping deadline, in seconds. */ 128 protected static final int DEFAULT_PING_DEADLINE = 5; 129 /** Default max failure count before attempting to network re-registration. */ 130 protected static final int DEFAULT_MAX_PDP_RESET_FAIL = 3; 131 132 /** 133 * After detecting a potential connection problem, this is the max number 134 * of subsequent polls before attempting a radio reset. At this point, 135 * poll interval is 5 seconds (POLL_NETSTAT_SLOW_MILLIS), so set this to 136 * poll for about 2 more minutes. 137 */ 138 protected static final int NO_RECV_POLL_LIMIT = 24; 139 140 // 1 sec. default polling interval when screen is on. 141 protected static final int POLL_NETSTAT_MILLIS = 1000; 142 // 10 min. default polling interval when screen is off. 143 protected static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10; 144 // 2 min for round trip time 145 protected static final int POLL_LONGEST_RTT = 120 * 1000; 146 // 10 for packets without ack 147 protected static final int NUMBER_SENT_PACKETS_OF_HANG = 10; 148 // how long to wait before switching back to default APN 149 protected static final int RESTORE_DEFAULT_APN_DELAY = 1 * 60 * 1000; 150 // system property that can override the above value 151 protected static final String APN_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore"; 152 // represents an invalid IP address 153 protected static final String NULL_IP = "0.0.0.0"; 154 155 156 // member variables 157 protected PhoneBase phone; 158 protected Activity activity = Activity.NONE; 159 protected State state = State.IDLE; 160 protected Handler mDataConnectionTracker = null; 161 162 163 protected INetStatService netstat; 164 protected long txPkts, rxPkts, sentSinceLastRecv; 165 protected int netStatPollPeriod; 166 protected int mNoRecvPollCount = 0; 167 protected boolean netStatPollEnabled = false; 168 169 /** Manage the behavior of data retry after failure */ 170 protected final RetryManager mRetryMgr = new RetryManager(); 171 172 // wifi connection status will be updated by sticky intent 173 protected boolean mIsWifiConnected = false; 174 175 /** Intent sent when the reconnect alarm fires. */ 176 protected PendingIntent mReconnectIntent = null; 177 178 /** CID of active data connection */ 179 protected int cidActive; 180 181 /** 182 * Default constructor 183 */ 184 protected DataConnectionTracker(PhoneBase phone) { 185 super(); 186 this.phone = phone; 187 } 188 189 public abstract void dispose(); 190 191 public Activity getActivity() { 192 return activity; 193 } 194 195 public State getState() { 196 return state; 197 } 198 199 public String getStateInString() { 200 switch (state) { 201 case IDLE: return "IDLE"; 202 case INITING: return "INIT"; 203 case CONNECTING: return "CING"; 204 case SCANNING: return "SCAN"; 205 case CONNECTED: return "CNTD"; 206 case DISCONNECTING: return "DING"; 207 case FAILED: return "FAIL"; 208 default: return "ERRO"; 209 } 210 } 211 212 /** 213 * The data connection is expected to be setup while device 214 * 1. has Icc card 215 * 2. registered for data service 216 * 3. user doesn't explicitly disable data service 217 * 4. wifi is not on 218 * 219 * @return false while no data connection if all above requirements are met. 220 */ 221 public abstract boolean isDataConnectionAsDesired(); 222 223 //The data roaming setting is now located in the shared preferences. 224 // See if the requested preference value is the same as that stored in 225 // the shared values. If it is not, then update it. 226 public void setDataOnRoamingEnabled(boolean enabled) { 227 if (getDataOnRoamingEnabled() != enabled) { 228 Settings.Secure.putInt(phone.getContext().getContentResolver(), 229 Settings.Secure.DATA_ROAMING, enabled ? 1 : 0); 230 if (phone.getServiceState().getRoaming()) { 231 if (enabled) { 232 mRetryMgr.resetRetryCount(); 233 } 234 sendMessage(obtainMessage(EVENT_ROAMING_ON)); 235 } 236 } 237 } 238 239 //Retrieve the data roaming setting from the shared preferences. 240 public boolean getDataOnRoamingEnabled() { 241 try { 242 return Settings.Secure.getInt(phone.getContext().getContentResolver(), 243 Settings.Secure.DATA_ROAMING) > 0; 244 } catch (SettingNotFoundException snfe) { 245 return false; 246 } 247 } 248 249 // abstract handler methods 250 protected abstract void onTrySetupData(String reason); 251 protected abstract void onRoamingOff(); 252 protected abstract void onRoamingOn(); 253 protected abstract void onRadioAvailable(); 254 protected abstract void onRadioOffOrNotAvailable(); 255 protected abstract void onDataSetupComplete(AsyncResult ar); 256 protected abstract void onDisconnectDone(AsyncResult ar); 257 protected abstract void onVoiceCallStarted(); 258 protected abstract void onVoiceCallEnded(); 259 protected abstract void onCleanUpConnection(boolean tearDown, String reason); 260 261 //***** Overridden from Handler 262 public void handleMessage (Message msg) { 263 switch (msg.what) { 264 265 case EVENT_TRY_SETUP_DATA: 266 String reason = null; 267 if (msg.obj instanceof String) { 268 reason = (String)msg.obj; 269 } 270 onTrySetupData(reason); 271 break; 272 273 case EVENT_ROAMING_OFF: 274 if (getDataOnRoamingEnabled() == false) { 275 mRetryMgr.resetRetryCount(); 276 } 277 onRoamingOff(); 278 break; 279 280 case EVENT_ROAMING_ON: 281 onRoamingOn(); 282 break; 283 284 case EVENT_RADIO_AVAILABLE: 285 onRadioAvailable(); 286 break; 287 288 case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: 289 onRadioOffOrNotAvailable(); 290 break; 291 292 case EVENT_DATA_SETUP_COMPLETE: 293 cidActive = msg.arg1; 294 onDataSetupComplete((AsyncResult) msg.obj); 295 break; 296 297 case EVENT_DISCONNECT_DONE: 298 onDisconnectDone((AsyncResult) msg.obj); 299 break; 300 301 case EVENT_VOICE_CALL_STARTED: 302 onVoiceCallStarted(); 303 break; 304 305 case EVENT_VOICE_CALL_ENDED: 306 onVoiceCallEnded(); 307 break; 308 309 case EVENT_CLEAN_UP_CONNECTION: 310 boolean tearDown = (msg.arg1 == 0) ? false : true; 311 onCleanUpConnection(tearDown, (String)msg.obj); 312 break; 313 314 default: 315 Log.e("DATA", "Unidentified event = " + msg.what); 316 break; 317 } 318 } 319 320 /** 321 * Report the current state of data connectivity (enabled or disabled) 322 * @return {@code false} if data connectivity has been explicitly disabled, 323 * {@code true} otherwise. 324 */ 325 public boolean getDataEnabled() { 326 return dataEnabled[APN_DEFAULT_ID]; 327 } 328 329 /** 330 * Report on whether data connectivity is enabled 331 * @return {@code false} if data connectivity has been explicitly disabled, 332 * {@code true} otherwise. 333 */ 334 public boolean getAnyDataEnabled() { 335 return (enabledCount != 0); 336 } 337 338 protected abstract void startNetStatPoll(); 339 340 protected abstract void stopNetStatPoll(); 341 342 protected abstract void restartRadio(); 343 344 protected abstract void log(String s); 345 346 protected int apnTypeToId(String type) { 347 if (TextUtils.equals(type, Phone.APN_TYPE_DEFAULT)) { 348 return APN_DEFAULT_ID; 349 } else if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) { 350 return APN_MMS_ID; 351 } else if (TextUtils.equals(type, Phone.APN_TYPE_SUPL)) { 352 return APN_SUPL_ID; 353 } else if (TextUtils.equals(type, Phone.APN_TYPE_DUN)) { 354 return APN_DUN_ID; 355 } else if (TextUtils.equals(type, Phone.APN_TYPE_HIPRI)) { 356 return APN_HIPRI_ID; 357 } else { 358 return APN_INVALID_ID; 359 } 360 } 361 362 protected abstract boolean isApnTypeActive(String type); 363 364 protected abstract boolean isApnTypeAvailable(String type); 365 366 protected abstract String[] getActiveApnTypes(); 367 368 protected abstract String getActiveApnString(); 369 370 public abstract ArrayList<DataConnection> getAllDataConnections(); 371 372 protected abstract String getInterfaceName(String apnType); 373 374 protected abstract String getIpAddress(String apnType); 375 376 protected abstract String getGateway(String apnType); 377 378 protected abstract String[] getDnsServers(String apnType); 379 380 protected abstract void setState(State s); 381 382 protected boolean isEnabled(int id) { 383 if (id != APN_INVALID_ID) { 384 return dataEnabled[id]; 385 } 386 return false; 387 } 388 389 /** 390 * Ensure that we are connected to an APN of the specified type. 391 * @param type the APN type (currently the only valid values 392 * are {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}) 393 * @return the result of the operation. Success is indicated by 394 * a return value of either {@code Phone.APN_ALREADY_ACTIVE} or 395 * {@code Phone.APN_REQUEST_STARTED}. In the latter case, a broadcast 396 * will be sent by the ConnectivityManager when a connection to 397 * the APN has been established. 398 */ 399 public int enableApnType(String type) { 400 int id = apnTypeToId(type); 401 if (id == APN_INVALID_ID) { 402 return Phone.APN_REQUEST_FAILED; 403 } 404 405 // If already active, return 406 if(DBG) Log.d(LOG_TAG, "enableApnType("+type+"), isApnTypeActive = " 407 + isApnTypeActive(type) + " and state = " + state); 408 409 if (isApnTypeActive(type)) { 410 if (state == State.INITING) return Phone.APN_REQUEST_STARTED; 411 else if (state == State.CONNECTED) return Phone.APN_ALREADY_ACTIVE; 412 } 413 414 if (!isApnTypeAvailable(type)) { 415 return Phone.APN_TYPE_NOT_AVAILABLE; 416 } 417 418 setEnabled(id, true); 419 mRequestedApnType = type; 420 sendMessage(obtainMessage(EVENT_ENABLE_NEW_APN)); 421 return Phone.APN_REQUEST_STARTED; 422 } 423 424 /** 425 * The APN of the specified type is no longer needed. Ensure that if 426 * use of the default APN has not been explicitly disabled, we are connected 427 * to the default APN. 428 * @param type the APN type. The only valid values are currently 429 * {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}. 430 * @return 431 */ 432 public int disableApnType(String type) { 433 if (DBG) Log.d(LOG_TAG, "disableApnType("+type+")"); 434 int id = apnTypeToId(type); 435 if (id == APN_INVALID_ID) { 436 return Phone.APN_REQUEST_FAILED; 437 } 438 if (isEnabled(id)) { 439 setEnabled(id, false); 440 if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { 441 mRequestedApnType = Phone.APN_TYPE_DEFAULT; 442 if (dataEnabled[APN_DEFAULT_ID]) { 443 return Phone.APN_ALREADY_ACTIVE; 444 } else { 445 return Phone.APN_REQUEST_STARTED; 446 } 447 } else { 448 return Phone.APN_REQUEST_STARTED; 449 } 450 } else { 451 return Phone.APN_REQUEST_FAILED; 452 } 453 } 454 455 protected synchronized void setEnabled(int id, boolean enable) { 456 if (DBG) Log.d(LOG_TAG, "setEnabled(" + id + ", " + enable + ") with old state = " + 457 dataEnabled[id] + " and enabledCount = " + enabledCount); 458 if (dataEnabled[id] != enable) { 459 dataEnabled[id] = enable; 460 461 // count the total number of enabled APN's 462 // if we just enabled the first APN, start our Data connection, 463 // if we disabled the last, stop our data connection 464 if (enable) { 465 enabledCount++; 466 if (enabledCount == 1) { 467 setPrivateDataEnabled(true); 468 } 469 } else { 470 enabledCount--; 471 if (enabledCount == 0) { 472 setPrivateDataEnabled(false); 473 } 474 } 475 } 476 } 477 478 /** 479 * Prevent mobile data connections from being established, 480 * or once again allow mobile data connections. If the state 481 * toggles, then either tear down or set up data, as 482 * appropriate to match the new state. 483 * <p>This operation only affects the default APN, and if the same APN is 484 * currently being used for MMS traffic, the teardown will not happen 485 * even when {@code enable} is {@code false}.</p> 486 * @param enable indicates whether to enable ({@code true}) or disable ({@code false}) data 487 * @return {@code true} if the operation succeeded 488 */ 489 public boolean setDataEnabled(boolean enable) { 490 if (DBG) Log.d(LOG_TAG, "setDataEnabled("+enable+")"); 491 setEnabled(APN_DEFAULT_ID, enable); 492 return true; 493 } 494 495 private void setPrivateDataEnabled(boolean enable) { 496 if (DBG) Log.d(LOG_TAG, "setPrivateDataEnabled("+enable+")"); 497 if (enable) { 498 sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); 499 } else { 500 Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION); 501 msg.arg1 = 1; // tearDown is true 502 msg.obj = Phone.REASON_DATA_DISABLED; 503 sendMessage(msg); 504 } 505 } 506 507} 508