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 17 package com.android.internal.telephony; 18 19 import android.app.PendingIntent; 20 import android.content.BroadcastReceiver; 21 import android.content.ContentResolver; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.IntentFilter; 25 import android.content.SharedPreferences; 26 import android.database.ContentObserver; 27 import android.net.LinkCapabilities; 28 import android.net.LinkProperties; 29 import android.net.NetworkInfo; 30 import android.net.TrafficStats; 31 import android.net.wifi.WifiManager; 32 import android.os.AsyncResult; 33 import android.os.Bundle; 34 import android.os.Handler; 35 import android.os.Message; 36 import android.os.Messenger; 37 import android.os.SystemClock; 38 import android.os.SystemProperties; 39 import android.preference.PreferenceManager; 40 import android.provider.Settings; 41 import android.provider.Settings.SettingNotFoundException; 42 import android.telephony.ServiceState; 43 import android.text.TextUtils; 44 import android.util.Log; 45 46 import com.android.internal.R; 47 import com.android.internal.telephony.DataConnection.FailCause; 48 import com.android.internal.util.AsyncChannel; 49 import com.android.internal.util.Protocol; 50 51 import java.util.ArrayList; 52 import java.util.HashMap; 53 import java.util.concurrent.ConcurrentHashMap; 54 import java.util.concurrent.atomic.AtomicInteger; 55 56 /** 57 * {@hide} 58 */ 59 public abstract class DataConnectionTracker extends Handler { 60 protected static final boolean DBG = true; 61 protected static final boolean VDBG = false; 62 63 /** 64 * IDLE: ready to start data connection setup, default state 65 * INITING: state of issued setupDefaultPDP() but not finish yet 66 * CONNECTING: state of issued startPppd() but not finish yet 67 * SCANNING: data connection fails with one apn but other apns are available 68 * ready to start data connection on other apns (before INITING) 69 * CONNECTED: IP connection is setup 70 * DISCONNECTING: Connection.disconnect() has been called, but PDP 71 * context is not yet deactivated 72 * FAILED: data connection fail for all apns settings 73 * 74 * getDataConnectionState() maps State to DataState 75 * FAILED or IDLE : DISCONNECTED 76 * INITING or CONNECTING or SCANNING: CONNECTING 77 * CONNECTED : CONNECTED or DISCONNECTING 78 */ 79 public enum State { 80 IDLE, 81 INITING, 82 CONNECTING, 83 SCANNING, 84 CONNECTED, 85 DISCONNECTING, 86 FAILED 87 } 88 89 public enum Activity { 90 NONE, 91 DATAIN, 92 DATAOUT, 93 DATAINANDOUT, 94 DORMANT 95 } 96 97 public static String ACTION_DATA_CONNECTION_TRACKER_MESSENGER = 98 "com.android.internal.telephony"; 99 public static String EXTRA_MESSENGER = "EXTRA_MESSENGER"; 100 101 /***** Event Codes *****/ 102 protected static final int BASE = Protocol.BASE_DATA_CONNECTION_TRACKER; 103 protected static final int EVENT_DATA_SETUP_COMPLETE = BASE + 0; 104 protected static final int EVENT_RADIO_AVAILABLE = BASE + 1; 105 protected static final int EVENT_RECORDS_LOADED = BASE + 2; 106 protected static final int EVENT_TRY_SETUP_DATA = BASE + 3; 107 protected static final int EVENT_DATA_STATE_CHANGED = BASE + 4; 108 protected static final int EVENT_POLL_PDP = BASE + 5; 109 protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = BASE + 6; 110 protected static final int EVENT_VOICE_CALL_STARTED = BASE + 7; 111 protected static final int EVENT_VOICE_CALL_ENDED = BASE + 8; 112 protected static final int EVENT_DATA_CONNECTION_DETACHED = BASE + 9; 113 protected static final int EVENT_LINK_STATE_CHANGED = BASE + 10; 114 protected static final int EVENT_ROAMING_ON = BASE + 11; 115 protected static final int EVENT_ROAMING_OFF = BASE + 12; 116 protected static final int EVENT_ENABLE_NEW_APN = BASE + 13; 117 protected static final int EVENT_RESTORE_DEFAULT_APN = BASE + 14; 118 protected static final int EVENT_DISCONNECT_DONE = BASE + 15; 119 protected static final int EVENT_DATA_CONNECTION_ATTACHED = BASE + 16; 120 protected static final int EVENT_DATA_STALL_ALARM = BASE + 17; 121 protected static final int EVENT_DO_RECOVERY = BASE + 18; 122 protected static final int EVENT_APN_CHANGED = BASE + 19; 123 protected static final int EVENT_CDMA_DATA_DETACHED = BASE + 20; 124 protected static final int EVENT_NV_READY = BASE + 21; 125 protected static final int EVENT_PS_RESTRICT_ENABLED = BASE + 22; 126 protected static final int EVENT_PS_RESTRICT_DISABLED = BASE + 23; 127 public static final int EVENT_CLEAN_UP_CONNECTION = BASE + 24; 128 protected static final int EVENT_CDMA_OTA_PROVISION = BASE + 25; 129 protected static final int EVENT_RESTART_RADIO = BASE + 26; 130 protected static final int EVENT_SET_INTERNAL_DATA_ENABLE = BASE + 27; 131 protected static final int EVENT_RESET_DONE = BASE + 28; 132 public static final int CMD_SET_USER_DATA_ENABLE = BASE + 29; 133 public static final int EVENT_CLEAN_UP_ALL_CONNECTIONS = BASE + 30; 134 public static final int CMD_SET_DEPENDENCY_MET = BASE + 31; 135 public static final int CMD_SET_POLICY_DATA_ENABLE = BASE + 32; 136 137 /***** Constants *****/ 138 139 protected static final int APN_INVALID_ID = -1; 140 protected static final int APN_DEFAULT_ID = 0; 141 protected static final int APN_MMS_ID = 1; 142 protected static final int APN_SUPL_ID = 2; 143 protected static final int APN_DUN_ID = 3; 144 protected static final int APN_HIPRI_ID = 4; 145 protected static final int APN_IMS_ID = 5; 146 protected static final int APN_FOTA_ID = 6; 147 protected static final int APN_CBS_ID = 7; 148 protected static final int APN_NUM_TYPES = 8; 149 150 public static final int DISABLED = 0; 151 public static final int ENABLED = 1; 152 153 public static final String APN_TYPE_KEY = "apnType"; 154 155 /** Delay between APN attempts. 156 Note the property override mechanism is there just for testing purpose only. */ 157 protected static final int APN_DELAY_MILLIS = 158 SystemProperties.getInt("persist.radio.apn_delay", 5000); 159 160 protected Object mDataEnabledLock = new Object(); 161 162 // responds to the setInternalDataEnabled call - used internally to turn off data 163 // for example during emergency calls 164 protected boolean mInternalDataEnabled = true; 165 166 // responds to public (user) API to enable/disable data use 167 // independent of mInternalDataEnabled and requests for APN access 168 // persisted 169 protected boolean mUserDataEnabled = true; 170 171 // TODO: move away from static state once 5587429 is fixed. 172 protected static boolean sPolicyDataEnabled = true; 173 174 private boolean[] dataEnabled = new boolean[APN_NUM_TYPES]; 175 176 private int enabledCount = 0; 177 178 /* Currently requested APN type (TODO: This should probably be a parameter not a member) */ 179 protected String mRequestedApnType = Phone.APN_TYPE_DEFAULT; 180 181 /** Retry configuration: A doubling of retry times from 5secs to 30minutes */ 182 protected static final String DEFAULT_DATA_RETRY_CONFIG = "default_randomization=2000," 183 + "5000,10000,20000,40000,80000:5000,160000:5000," 184 + "320000:5000,640000:5000,1280000:5000,1800000:5000"; 185 186 /** Retry configuration for secondary networks: 4 tries in 20 sec */ 187 protected static final String SECONDARY_DATA_RETRY_CONFIG = 188 "max_retries=3, 5000, 5000, 5000"; 189 190 /** Slow poll when attempting connection recovery. */ 191 protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000; 192 /** Default max failure count before attempting to network re-registration. */ 193 protected static final int DEFAULT_MAX_PDP_RESET_FAIL = 3; 194 195 /** 196 * After detecting a potential connection problem, this is the max number 197 * of subsequent polls before attempting recovery. 198 */ 199 protected static final int NO_RECV_POLL_LIMIT = 24; 200 // 1 sec. default polling interval when screen is on. 201 protected static final int POLL_NETSTAT_MILLIS = 1000; 202 // 10 min. default polling interval when screen is off. 203 protected static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10; 204 // 2 min for round trip time 205 protected static final int POLL_LONGEST_RTT = 120 * 1000; 206 // Default sent packets without ack which triggers initial recovery steps 207 protected static final int NUMBER_SENT_PACKETS_OF_HANG = 10; 208 // how long to wait before switching back to default APN 209 protected static final int RESTORE_DEFAULT_APN_DELAY = 1 * 60 * 1000; 210 // system property that can override the above value 211 protected static final String APN_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore"; 212 // represents an invalid IP address 213 protected static final String NULL_IP = "0.0.0.0"; 214 215 // Default for the data stall alarm while non-aggressive stall detection 216 protected static final int DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60 * 6; 217 // Default for the data stall alarm for aggressive stall detection 218 protected static final int DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60; 219 // If attempt is less than this value we're doing first level recovery 220 protected static final int DATA_STALL_NO_RECV_POLL_LIMIT = 1; 221 // Tag for tracking stale alarms 222 protected static final String DATA_STALL_ALARM_TAG_EXTRA = "data.stall.alram.tag"; 223 224 // TODO: See if we can remove INTENT_RECONNECT_ALARM 225 // having to have different values for GSM and 226 // CDMA. If so we can then remove the need for 227 // getActionIntentReconnectAlarm. 228 protected static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason"; 229 230 // Used for debugging. Send the INTENT with an optional counter value with the number 231 // of times the setup is to fail before succeeding. If the counter isn't passed the 232 // setup will fail once. Example fail two times with FailCause.SIGNAL_LOST(-3) 233 // adb shell am broadcast \ 234 // -a com.android.internal.telephony.dataconnectiontracker.intent_set_fail_data_setup_counter \ 235 // --ei fail_data_setup_counter 3 --ei fail_data_setup_fail_cause -3 236 protected static final String INTENT_SET_FAIL_DATA_SETUP_COUNTER = 237 "com.android.internal.telephony.dataconnectiontracker.intent_set_fail_data_setup_counter"; 238 protected static final String FAIL_DATA_SETUP_COUNTER = "fail_data_setup_counter"; 239 protected int mFailDataSetupCounter = 0; 240 protected static final String FAIL_DATA_SETUP_FAIL_CAUSE = "fail_data_setup_fail_cause"; 241 protected FailCause mFailDataSetupFailCause = FailCause.ERROR_UNSPECIFIED; 242 243 protected static final String DEFALUT_DATA_ON_BOOT_PROP = "net.def_data_on_boot"; 244 245 // member variables 246 protected PhoneBase mPhone; 247 protected Activity mActivity = Activity.NONE; 248 protected State mState = State.IDLE; 249 protected Handler mDataConnectionTracker = null; 250 251 252 protected long mTxPkts; 253 protected long mRxPkts; 254 protected int mNetStatPollPeriod; 255 protected boolean mNetStatPollEnabled = false; 256 257 protected TxRxSum mDataStallTxRxSum = new TxRxSum(0, 0); 258 // Used to track stale data stall alarms. 259 protected int mDataStallAlarmTag = (int) SystemClock.elapsedRealtime(); 260 // The current data stall alarm intent 261 protected PendingIntent mDataStallAlarmIntent = null; 262 // Number of packets sent since the last received packet 263 protected long mSentSinceLastRecv; 264 // Controls when a simple recovery attempt it to be tried 265 protected int mNoRecvPollCount = 0; 266 267 // wifi connection status will be updated by sticky intent 268 protected boolean mIsWifiConnected = false; 269 270 /** Intent sent when the reconnect alarm fires. */ 271 protected PendingIntent mReconnectIntent = null; 272 273 /** CID of active data connection */ 274 protected int mCidActive; 275 276 // When false we will not auto attach and manually attaching is required. 277 protected boolean mAutoAttachOnCreation = false; 278 279 // State of screen 280 // (TODO: Reconsider tying directly to screen, maybe this is 281 // really a lower power mode") 282 protected boolean mIsScreenOn = true; 283 284 /** Allows the generation of unique Id's for DataConnection objects */ 285 protected AtomicInteger mUniqueIdGenerator = new AtomicInteger(0); 286 287 /** The data connections. */ 288 protected HashMap<Integer, DataConnection> mDataConnections = 289 new HashMap<Integer, DataConnection>(); 290 291 /** The data connection async channels */ 292 protected HashMap<Integer, DataConnectionAc> mDataConnectionAsyncChannels = 293 new HashMap<Integer, DataConnectionAc>(); 294 295 /** Convert an ApnType string to Id (TODO: Use "enumeration" instead of String for ApnType) */ 296 protected HashMap<String, Integer> mApnToDataConnectionId = 297 new HashMap<String, Integer>(); 298 299 /** Phone.APN_TYPE_* ===> ApnContext */ 300 protected ConcurrentHashMap<String, ApnContext> mApnContexts; 301 302 /* Currently active APN */ 303 protected ApnSetting mActiveApn; 304 305 /** allApns holds all apns */ 306 protected ArrayList<ApnSetting> mAllApns = null; 307 308 /** preferred apn */ 309 protected ApnSetting mPreferredApn = null; 310 311 /** Is packet service restricted by network */ 312 protected boolean mIsPsRestricted = false; 313 314 /* Once disposed dont handle any messages */ 315 protected boolean mIsDisposed = false; 316 317 protected BroadcastReceiver mIntentReceiver = new BroadcastReceiver () 318 { 319 @Override 320 public void onReceive(Context context, Intent intent) 321 { 322 String action = intent.getAction(); 323 if (DBG) log("onReceive: action=" + action); 324 if (action.equals(Intent.ACTION_SCREEN_ON)) { 325 mIsScreenOn = true; 326 stopNetStatPoll(); 327 startNetStatPoll(); 328 restartDataStallAlarm(); 329 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 330 mIsScreenOn = false; 331 stopNetStatPoll(); 332 startNetStatPoll(); 333 restartDataStallAlarm(); 334 } else if (action.startsWith(getActionIntentReconnectAlarm())) { 335 log("Reconnect alarm. Previous state was " + mState); 336 onActionIntentReconnectAlarm(intent); 337 } else if (action.equals(getActionIntentDataStallAlarm())) { 338 onActionIntentDataStallAlarm(intent); 339 } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { 340 final android.net.NetworkInfo networkInfo = (NetworkInfo) 341 intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); 342 mIsWifiConnected = (networkInfo != null && networkInfo.isConnected()); 343 } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { 344 final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 345 WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; 346 347 if (!enabled) { 348 // when WiFi got disabled, the NETWORK_STATE_CHANGED_ACTION 349 // quit and won't report disconnected until next enabling. 350 mIsWifiConnected = false; 351 } 352 } else if (action.equals(INTENT_SET_FAIL_DATA_SETUP_COUNTER)) { 353 mFailDataSetupCounter = intent.getIntExtra(FAIL_DATA_SETUP_COUNTER, 1); 354 mFailDataSetupFailCause = FailCause.fromInt( 355 intent.getIntExtra(FAIL_DATA_SETUP_FAIL_CAUSE, 356 FailCause.ERROR_UNSPECIFIED.getErrorCode())); 357 if (DBG) log("set mFailDataSetupCounter=" + mFailDataSetupCounter + 358 " mFailDataSetupFailCause=" + mFailDataSetupFailCause); 359 } 360 } 361 }; 362 363 private final DataRoamingSettingObserver mDataRoamingSettingObserver; 364 365 private class DataRoamingSettingObserver extends ContentObserver { 366 public DataRoamingSettingObserver(Handler handler) { 367 super(handler); 368 } 369 370 public void register(Context context) { 371 final ContentResolver resolver = context.getContentResolver(); 372 resolver.registerContentObserver( 373 Settings.Secure.getUriFor(Settings.Secure.DATA_ROAMING), false, this); 374 } 375 376 public void unregister(Context context) { 377 final ContentResolver resolver = context.getContentResolver(); 378 resolver.unregisterContentObserver(this); 379 } 380 381 @Override 382 public void onChange(boolean selfChange) { 383 // already running on mPhone handler thread 384 handleDataOnRoamingChange(); 385 } 386 } 387 388 /** 389 * Maintian the sum of transmit and receive packets. 390 * 391 * The packet counts are initizlied and reset to -1 and 392 * remain -1 until they can be updated. 393 */ 394 public class TxRxSum { 395 public long txPkts; 396 public long rxPkts; 397 398 public TxRxSum() { 399 reset(); 400 } 401 402 public TxRxSum(long txPkts, long rxPkts) { 403 this.txPkts = txPkts; 404 this.rxPkts = rxPkts; 405 } 406 407 public TxRxSum(TxRxSum sum) { 408 txPkts = sum.txPkts; 409 rxPkts = sum.rxPkts; 410 } 411 412 public void reset() { 413 txPkts = -1; 414 rxPkts = -1; 415 } 416 417 public String toString() { 418 return "{txSum=" + txPkts + " rxSum=" + rxPkts + "}"; 419 } 420 421 public void updateTxRxSum() { 422 boolean txUpdated = false, rxUpdated = false; 423 long txSum = 0, rxSum = 0; 424 for (ApnContext apnContext : mApnContexts.values()) { 425 if (apnContext.getState() == State.CONNECTED) { 426 DataConnectionAc dcac = apnContext.getDataConnectionAc(); 427 if (dcac == null) continue; 428 429 LinkProperties linkProp = dcac.getLinkPropertiesSync(); 430 if (linkProp == null) continue; 431 432 String iface = linkProp.getInterfaceName(); 433 434 if (iface != null) { 435 long stats = TrafficStats.getTxPackets(iface); 436 if (stats > 0) { 437 txUpdated = true; 438 txSum += stats; 439 } 440 stats = TrafficStats.getRxPackets(iface); 441 if (stats > 0) { 442 rxUpdated = true; 443 rxSum += stats; 444 } 445 } 446 } 447 } 448 if (txUpdated) this.txPkts = txSum; 449 if (rxUpdated) this.rxPkts = rxSum; 450 } 451 } 452 453 protected boolean isDataSetupCompleteOk(AsyncResult ar) { 454 if (ar.exception != null) { 455 if (DBG) log("isDataSetupCompleteOk return false, ar.result=" + ar.result); 456 return false; 457 } 458 if (mFailDataSetupCounter <= 0) { 459 if (DBG) log("isDataSetupCompleteOk return true"); 460 return true; 461 } 462 ar.result = mFailDataSetupFailCause; 463 if (DBG) { 464 log("isDataSetupCompleteOk return false" + 465 " mFailDataSetupCounter=" + mFailDataSetupCounter + 466 " mFailDataSetupFailCause=" + mFailDataSetupFailCause); 467 } 468 mFailDataSetupCounter -= 1; 469 return false; 470 } 471 472 protected void onActionIntentReconnectAlarm(Intent intent) { 473 String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON); 474 if (mState == State.FAILED) { 475 Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION); 476 msg.arg1 = 0; // tearDown is false 477 msg.arg2 = 0; 478 msg.obj = reason; 479 sendMessage(msg); 480 } 481 sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); 482 } 483 484 protected void onActionIntentDataStallAlarm(Intent intent) { 485 if (VDBG) log("onActionIntentDataStallAlarm: action=" + intent.getAction()); 486 Message msg = obtainMessage(EVENT_DATA_STALL_ALARM, intent.getAction()); 487 msg.arg1 = intent.getIntExtra(DATA_STALL_ALARM_TAG_EXTRA, 0); 488 sendMessage(msg); 489 } 490 491 /** 492 * Default constructor 493 */ 494 protected DataConnectionTracker(PhoneBase phone) { 495 super(); 496 mPhone = phone; 497 498 IntentFilter filter = new IntentFilter(); 499 filter.addAction(getActionIntentReconnectAlarm()); 500 filter.addAction(Intent.ACTION_SCREEN_ON); 501 filter.addAction(Intent.ACTION_SCREEN_OFF); 502 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 503 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 504 filter.addAction(INTENT_SET_FAIL_DATA_SETUP_COUNTER); 505 506 mUserDataEnabled = Settings.Secure.getInt( 507 mPhone.getContext().getContentResolver(), Settings.Secure.MOBILE_DATA, 1) == 1; 508 509 // TODO: Why is this registering the phone as the receiver of the intent 510 // and not its own handler? 511 mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone); 512 513 // This preference tells us 1) initial condition for "dataEnabled", 514 // and 2) whether the RIL will setup the baseband to auto-PS attach. 515 516 dataEnabled[APN_DEFAULT_ID] = SystemProperties.getBoolean(DEFALUT_DATA_ON_BOOT_PROP, 517 true); 518 if (dataEnabled[APN_DEFAULT_ID]) { 519 enabledCount++; 520 } 521 522 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext()); 523 mAutoAttachOnCreation = sp.getBoolean(PhoneBase.DATA_DISABLED_ON_BOOT_KEY, false); 524 525 // watch for changes to Settings.Secure.DATA_ROAMING 526 mDataRoamingSettingObserver = new DataRoamingSettingObserver(mPhone); 527 mDataRoamingSettingObserver.register(mPhone.getContext()); 528 } 529 530 public void dispose() { 531 for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) { 532 dcac.disconnect(); 533 } 534 mDataConnectionAsyncChannels.clear(); 535 mIsDisposed = true; 536 mPhone.getContext().unregisterReceiver(this.mIntentReceiver); 537 mDataRoamingSettingObserver.unregister(mPhone.getContext()); 538 } 539 540 protected void broadcastMessenger() { 541 Intent intent = new Intent(ACTION_DATA_CONNECTION_TRACKER_MESSENGER); 542 intent.putExtra(EXTRA_MESSENGER, new Messenger(this)); 543 mPhone.getContext().sendBroadcast(intent); 544 } 545 546 public Activity getActivity() { 547 return mActivity; 548 } 549 550 public boolean isApnTypeActive(String type) { 551 // TODO: support simultaneous with List instead 552 if (Phone.APN_TYPE_DUN.equals(type)) { 553 ApnSetting dunApn = fetchDunApn(); 554 if (dunApn != null) { 555 return ((mActiveApn != null) && (dunApn.toString().equals(mActiveApn.toString()))); 556 } 557 } 558 return mActiveApn != null && mActiveApn.canHandleType(type); 559 } 560 561 protected ApnSetting fetchDunApn() { 562 Context c = mPhone.getContext(); 563 String apnData = Settings.Secure.getString(c.getContentResolver(), 564 Settings.Secure.TETHER_DUN_APN); 565 ApnSetting dunSetting = ApnSetting.fromString(apnData); 566 if (dunSetting != null) return dunSetting; 567 568 apnData = c.getResources().getString(R.string.config_tether_apndata); 569 return ApnSetting.fromString(apnData); 570 } 571 572 public String[] getActiveApnTypes() { 573 String[] result; 574 if (mActiveApn != null) { 575 result = mActiveApn.types; 576 } else { 577 result = new String[1]; 578 result[0] = Phone.APN_TYPE_DEFAULT; 579 } 580 return result; 581 } 582 583 /** TODO: See if we can remove */ 584 public String getActiveApnString(String apnType) { 585 String result = null; 586 if (mActiveApn != null) { 587 result = mActiveApn.apn; 588 } 589 return result; 590 } 591 592 /** 593 * Modify {@link Settings.Secure#DATA_ROAMING} value. 594 */ 595 public void setDataOnRoamingEnabled(boolean enabled) { 596 if (getDataOnRoamingEnabled() != enabled) { 597 final ContentResolver resolver = mPhone.getContext().getContentResolver(); 598 Settings.Secure.putInt(resolver, Settings.Secure.DATA_ROAMING, enabled ? 1 : 0); 599 // will trigger handleDataOnRoamingChange() through observer 600 } 601 } 602 603 /** 604 * Return current {@link Settings.Secure#DATA_ROAMING} value. 605 */ 606 public boolean getDataOnRoamingEnabled() { 607 try { 608 final ContentResolver resolver = mPhone.getContext().getContentResolver(); 609 return Settings.Secure.getInt(resolver, Settings.Secure.DATA_ROAMING) != 0; 610 } catch (SettingNotFoundException snfe) { 611 return false; 612 } 613 } 614 615 private void handleDataOnRoamingChange() { 616 if (mPhone.getServiceState().getRoaming()) { 617 if (getDataOnRoamingEnabled()) { 618 resetAllRetryCounts(); 619 } 620 sendMessage(obtainMessage(EVENT_ROAMING_ON)); 621 } 622 } 623 624 // abstract methods 625 protected abstract String getActionIntentReconnectAlarm(); 626 protected abstract String getActionIntentDataStallAlarm(); 627 protected abstract void startNetStatPoll(); 628 protected abstract void stopNetStatPoll(); 629 protected abstract void restartDataStallAlarm(); 630 protected abstract void restartRadio(); 631 protected abstract void log(String s); 632 protected abstract void loge(String s); 633 protected abstract boolean isDataAllowed(); 634 protected abstract boolean isApnTypeAvailable(String type); 635 public abstract State getState(String apnType); 636 protected abstract void setState(State s); 637 protected abstract void gotoIdleAndNotifyDataConnection(String reason); 638 639 protected abstract boolean onTrySetupData(String reason); 640 protected abstract void onRoamingOff(); 641 protected abstract void onRoamingOn(); 642 protected abstract void onRadioAvailable(); 643 protected abstract void onRadioOffOrNotAvailable(); 644 protected abstract void onDataSetupComplete(AsyncResult ar); 645 protected abstract void onDisconnectDone(int connId, AsyncResult ar); 646 protected abstract void onVoiceCallStarted(); 647 protected abstract void onVoiceCallEnded(); 648 protected abstract void onCleanUpConnection(boolean tearDown, int apnId, String reason); 649 protected abstract void onCleanUpAllConnections(String cause); 650 protected abstract boolean isDataPossible(String apnType); 651 652 protected void onDataStallAlarm(int tag) { 653 loge("onDataStallAlarm: not impleted tag=" + tag); 654 } 655 656 @Override 657 public void handleMessage(Message msg) { 658 switch (msg.what) { 659 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 660 log("DISCONNECTED_CONNECTED: msg=" + msg); 661 DataConnectionAc dcac = (DataConnectionAc) msg.obj; 662 mDataConnectionAsyncChannels.remove(dcac.dataConnection.getDataConnectionId()); 663 dcac.disconnected(); 664 break; 665 } 666 case EVENT_ENABLE_NEW_APN: 667 onEnableApn(msg.arg1, msg.arg2); 668 break; 669 670 case EVENT_TRY_SETUP_DATA: 671 String reason = null; 672 if (msg.obj instanceof String) { 673 reason = (String) msg.obj; 674 } 675 onTrySetupData(reason); 676 break; 677 678 case EVENT_DATA_STALL_ALARM: 679 onDataStallAlarm(msg.arg1); 680 break; 681 682 case EVENT_ROAMING_OFF: 683 if (getDataOnRoamingEnabled() == false) { 684 resetAllRetryCounts(); 685 } 686 onRoamingOff(); 687 break; 688 689 case EVENT_ROAMING_ON: 690 onRoamingOn(); 691 break; 692 693 case EVENT_RADIO_AVAILABLE: 694 onRadioAvailable(); 695 break; 696 697 case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: 698 onRadioOffOrNotAvailable(); 699 break; 700 701 case EVENT_DATA_SETUP_COMPLETE: 702 mCidActive = msg.arg1; 703 onDataSetupComplete((AsyncResult) msg.obj); 704 break; 705 706 case EVENT_DISCONNECT_DONE: 707 log("DataConnectoinTracker.handleMessage: EVENT_DISCONNECT_DONE msg=" + msg); 708 onDisconnectDone(msg.arg1, (AsyncResult) msg.obj); 709 break; 710 711 case EVENT_VOICE_CALL_STARTED: 712 onVoiceCallStarted(); 713 break; 714 715 case EVENT_VOICE_CALL_ENDED: 716 onVoiceCallEnded(); 717 break; 718 719 case EVENT_CLEAN_UP_ALL_CONNECTIONS: { 720 onCleanUpAllConnections((String) msg.obj); 721 break; 722 } 723 case EVENT_CLEAN_UP_CONNECTION: { 724 boolean tearDown = (msg.arg1 == 0) ? false : true; 725 onCleanUpConnection(tearDown, msg.arg2, (String) msg.obj); 726 break; 727 } 728 case EVENT_SET_INTERNAL_DATA_ENABLE: { 729 boolean enabled = (msg.arg1 == ENABLED) ? true : false; 730 onSetInternalDataEnabled(enabled); 731 break; 732 } 733 case EVENT_RESET_DONE: { 734 if (DBG) log("EVENT_RESET_DONE"); 735 onResetDone((AsyncResult) msg.obj); 736 break; 737 } 738 case CMD_SET_USER_DATA_ENABLE: { 739 final boolean enabled = (msg.arg1 == ENABLED) ? true : false; 740 if (DBG) log("CMD_SET_USER_DATA_ENABLE enabled=" + enabled); 741 onSetUserDataEnabled(enabled); 742 break; 743 } 744 case CMD_SET_DEPENDENCY_MET: { 745 boolean met = (msg.arg1 == ENABLED) ? true : false; 746 if (DBG) log("CMD_SET_DEPENDENCY_MET met=" + met); 747 Bundle bundle = msg.getData(); 748 if (bundle != null) { 749 String apnType = (String)bundle.get(APN_TYPE_KEY); 750 if (apnType != null) { 751 onSetDependencyMet(apnType, met); 752 } 753 } 754 break; 755 } 756 case CMD_SET_POLICY_DATA_ENABLE: { 757 final boolean enabled = (msg.arg1 == ENABLED) ? true : false; 758 onSetPolicyDataEnabled(enabled); 759 break; 760 } 761 default: 762 Log.e("DATA", "Unidentified event msg=" + msg); 763 break; 764 } 765 } 766 767 /** 768 * Report on whether data connectivity is enabled 769 * 770 * @return {@code false} if data connectivity has been explicitly disabled, 771 * {@code true} otherwise. 772 */ 773 public boolean getAnyDataEnabled() { 774 final boolean result; 775 synchronized (mDataEnabledLock) { 776 result = (mInternalDataEnabled && mUserDataEnabled && sPolicyDataEnabled 777 && (enabledCount != 0)); 778 } 779 if (!result && DBG) log("getAnyDataEnabled " + result); 780 return result; 781 } 782 783 protected boolean isEmergency() { 784 final boolean result; 785 synchronized (mDataEnabledLock) { 786 result = mPhone.isInEcm() || mPhone.isInEmergencyCall(); 787 } 788 log("isEmergency: result=" + result); 789 return result; 790 } 791 792 protected int apnTypeToId(String type) { 793 if (TextUtils.equals(type, Phone.APN_TYPE_DEFAULT)) { 794 return APN_DEFAULT_ID; 795 } else if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) { 796 return APN_MMS_ID; 797 } else if (TextUtils.equals(type, Phone.APN_TYPE_SUPL)) { 798 return APN_SUPL_ID; 799 } else if (TextUtils.equals(type, Phone.APN_TYPE_DUN)) { 800 return APN_DUN_ID; 801 } else if (TextUtils.equals(type, Phone.APN_TYPE_HIPRI)) { 802 return APN_HIPRI_ID; 803 } else if (TextUtils.equals(type, Phone.APN_TYPE_IMS)) { 804 return APN_IMS_ID; 805 } else if (TextUtils.equals(type, Phone.APN_TYPE_FOTA)) { 806 return APN_FOTA_ID; 807 } else if (TextUtils.equals(type, Phone.APN_TYPE_CBS)) { 808 return APN_CBS_ID; 809 } else { 810 return APN_INVALID_ID; 811 } 812 } 813 814 protected String apnIdToType(int id) { 815 switch (id) { 816 case APN_DEFAULT_ID: 817 return Phone.APN_TYPE_DEFAULT; 818 case APN_MMS_ID: 819 return Phone.APN_TYPE_MMS; 820 case APN_SUPL_ID: 821 return Phone.APN_TYPE_SUPL; 822 case APN_DUN_ID: 823 return Phone.APN_TYPE_DUN; 824 case APN_HIPRI_ID: 825 return Phone.APN_TYPE_HIPRI; 826 case APN_IMS_ID: 827 return Phone.APN_TYPE_IMS; 828 case APN_FOTA_ID: 829 return Phone.APN_TYPE_FOTA; 830 case APN_CBS_ID: 831 return Phone.APN_TYPE_CBS; 832 default: 833 log("Unknown id (" + id + ") in apnIdToType"); 834 return Phone.APN_TYPE_DEFAULT; 835 } 836 } 837 838 protected LinkProperties getLinkProperties(String apnType) { 839 int id = apnTypeToId(apnType); 840 841 if (isApnIdEnabled(id)) { 842 // TODO - remove this cdma-only hack and support multiple DCs. 843 DataConnectionAc dcac = mDataConnectionAsyncChannels.get(0); 844 return dcac.getLinkPropertiesSync(); 845 } else { 846 return new LinkProperties(); 847 } 848 } 849 850 protected LinkCapabilities getLinkCapabilities(String apnType) { 851 int id = apnTypeToId(apnType); 852 if (isApnIdEnabled(id)) { 853 // TODO - remove this cdma-only hack and support multiple DCs. 854 DataConnectionAc dcac = mDataConnectionAsyncChannels.get(0); 855 return dcac.getLinkCapabilitiesSync(); 856 } else { 857 return new LinkCapabilities(); 858 } 859 } 860 861 // tell all active apns of the current condition 862 protected void notifyDataConnection(String reason) { 863 for (int id = 0; id < APN_NUM_TYPES; id++) { 864 if (dataEnabled[id]) { 865 mPhone.notifyDataConnection(reason, apnIdToType(id)); 866 } 867 } 868 notifyOffApnsOfAvailability(reason); 869 } 870 871 // a new APN has gone active and needs to send events to catch up with the 872 // current condition 873 private void notifyApnIdUpToCurrent(String reason, int apnId) { 874 switch (mState) { 875 case IDLE: 876 case INITING: 877 break; 878 case CONNECTING: 879 case SCANNING: 880 mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTING); 881 break; 882 case CONNECTED: 883 case DISCONNECTING: 884 mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTING); 885 mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTED); 886 break; 887 } 888 } 889 890 // since we normally don't send info to a disconnected APN, we need to do this specially 891 private void notifyApnIdDisconnected(String reason, int apnId) { 892 mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.DISCONNECTED); 893 } 894 895 // disabled apn's still need avail/unavail notificiations - send them out 896 protected void notifyOffApnsOfAvailability(String reason) { 897 if (DBG) log("notifyOffApnsOfAvailability - reason= " + reason); 898 for (int id = 0; id < APN_NUM_TYPES; id++) { 899 if (!isApnIdEnabled(id)) { 900 notifyApnIdDisconnected(reason, id); 901 } 902 } 903 } 904 905 public boolean isApnTypeEnabled(String apnType) { 906 if (apnType == null) { 907 return false; 908 } else { 909 return isApnIdEnabled(apnTypeToId(apnType)); 910 } 911 } 912 913 protected synchronized boolean isApnIdEnabled(int id) { 914 if (id != APN_INVALID_ID) { 915 return dataEnabled[id]; 916 } 917 return false; 918 } 919 920 /** 921 * Ensure that we are connected to an APN of the specified type. 922 * 923 * @param type the APN type (currently the only valid values are 924 * {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}) 925 * @return Success is indicated by {@code Phone.APN_ALREADY_ACTIVE} or 926 * {@code Phone.APN_REQUEST_STARTED}. In the latter case, a 927 * broadcast will be sent by the ConnectivityManager when a 928 * connection to the APN has been established. 929 */ 930 public synchronized int enableApnType(String type) { 931 int id = apnTypeToId(type); 932 if (id == APN_INVALID_ID) { 933 return Phone.APN_REQUEST_FAILED; 934 } 935 936 if (DBG) { 937 log("enableApnType(" + type + "), isApnTypeActive = " + isApnTypeActive(type) 938 + ", isApnIdEnabled =" + isApnIdEnabled(id) + " and state = " + mState); 939 } 940 941 if (!isApnTypeAvailable(type)) { 942 if (DBG) log("type not available"); 943 return Phone.APN_TYPE_NOT_AVAILABLE; 944 } 945 946 if (isApnIdEnabled(id)) { 947 return Phone.APN_ALREADY_ACTIVE; 948 } else { 949 setEnabled(id, true); 950 } 951 return Phone.APN_REQUEST_STARTED; 952 } 953 954 /** 955 * The APN of the specified type is no longer needed. Ensure that if use of 956 * the default APN has not been explicitly disabled, we are connected to the 957 * default APN. 958 * 959 * @param type the APN type. The only valid values are currently 960 * {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}. 961 * @return Success is indicated by {@code Phone.APN_ALREADY_ACTIVE} or 962 * {@code Phone.APN_REQUEST_STARTED}. In the latter case, a 963 * broadcast will be sent by the ConnectivityManager when a 964 * connection to the APN has been disconnected. A {@code 965 * Phone.APN_REQUEST_FAILED} is returned if the type parameter is 966 * invalid or if the apn wasn't enabled. 967 */ 968 public synchronized int disableApnType(String type) { 969 if (DBG) log("disableApnType(" + type + ")"); 970 int id = apnTypeToId(type); 971 if (id == APN_INVALID_ID) { 972 return Phone.APN_REQUEST_FAILED; 973 } 974 if (isApnIdEnabled(id)) { 975 setEnabled(id, false); 976 if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { 977 if (dataEnabled[APN_DEFAULT_ID]) { 978 return Phone.APN_ALREADY_ACTIVE; 979 } else { 980 return Phone.APN_REQUEST_STARTED; 981 } 982 } else { 983 return Phone.APN_REQUEST_STARTED; 984 } 985 } else { 986 return Phone.APN_REQUEST_FAILED; 987 } 988 } 989 990 protected void setEnabled(int id, boolean enable) { 991 if (DBG) { 992 log("setEnabled(" + id + ", " + enable + ") with old state = " + dataEnabled[id] 993 + " and enabledCount = " + enabledCount); 994 } 995 Message msg = obtainMessage(EVENT_ENABLE_NEW_APN); 996 msg.arg1 = id; 997 msg.arg2 = (enable ? ENABLED : DISABLED); 998 sendMessage(msg); 999 } 1000 1001 protected void onEnableApn(int apnId, int enabled) { 1002 if (DBG) { 1003 log("EVENT_APN_ENABLE_REQUEST apnId=" + apnId + ", apnType=" + apnIdToType(apnId) + 1004 ", enabled=" + enabled + ", dataEnabled = " + dataEnabled[apnId] + 1005 ", enabledCount = " + enabledCount + ", isApnTypeActive = " + 1006 isApnTypeActive(apnIdToType(apnId))); 1007 } 1008 if (enabled == ENABLED) { 1009 synchronized (this) { 1010 if (!dataEnabled[apnId]) { 1011 dataEnabled[apnId] = true; 1012 enabledCount++; 1013 } 1014 } 1015 String type = apnIdToType(apnId); 1016 if (!isApnTypeActive(type)) { 1017 mRequestedApnType = type; 1018 onEnableNewApn(); 1019 } else { 1020 notifyApnIdUpToCurrent(Phone.REASON_APN_SWITCHED, apnId); 1021 } 1022 } else { 1023 // disable 1024 boolean didDisable = false; 1025 synchronized (this) { 1026 if (dataEnabled[apnId]) { 1027 dataEnabled[apnId] = false; 1028 enabledCount--; 1029 didDisable = true; 1030 } 1031 } 1032 if (didDisable) { 1033 if ((enabledCount == 0) || (apnId == APN_DUN_ID)) { 1034 mRequestedApnType = Phone.APN_TYPE_DEFAULT; 1035 onCleanUpConnection(true, apnId, Phone.REASON_DATA_DISABLED); 1036 } 1037 1038 // send the disconnect msg manually, since the normal route wont send 1039 // it (it's not enabled) 1040 notifyApnIdDisconnected(Phone.REASON_DATA_DISABLED, apnId); 1041 if (dataEnabled[APN_DEFAULT_ID] == true 1042 && !isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { 1043 // TODO - this is an ugly way to restore the default conn - should be done 1044 // by a real contention manager and policy that disconnects the lower pri 1045 // stuff as enable requests come in and pops them back on as we disable back 1046 // down to the lower pri stuff 1047 mRequestedApnType = Phone.APN_TYPE_DEFAULT; 1048 onEnableNewApn(); 1049 } 1050 } 1051 } 1052 } 1053 1054 /** 1055 * Called when we switch APNs. 1056 * 1057 * mRequestedApnType is set prior to call 1058 * To be overridden. 1059 */ 1060 protected void onEnableNewApn() { 1061 } 1062 1063 /** 1064 * Called when EVENT_RESET_DONE is received so goto 1065 * IDLE state and send notifications to those interested. 1066 * 1067 * TODO - currently unused. Needs to be hooked into DataConnection cleanup 1068 * TODO - needs to pass some notion of which connection is reset.. 1069 */ 1070 protected void onResetDone(AsyncResult ar) { 1071 if (DBG) log("EVENT_RESET_DONE"); 1072 String reason = null; 1073 if (ar.userObj instanceof String) { 1074 reason = (String) ar.userObj; 1075 } 1076 gotoIdleAndNotifyDataConnection(reason); 1077 } 1078 1079 /** 1080 * Prevent mobile data connections from being established, or once again 1081 * allow mobile data connections. If the state toggles, then either tear 1082 * down or set up data, as appropriate to match the new state. 1083 * 1084 * @param enable indicates whether to enable ({@code true}) or disable ( 1085 * {@code false}) data 1086 * @return {@code true} if the operation succeeded 1087 */ 1088 public boolean setInternalDataEnabled(boolean enable) { 1089 if (DBG) 1090 log("setInternalDataEnabled(" + enable + ")"); 1091 1092 Message msg = obtainMessage(EVENT_SET_INTERNAL_DATA_ENABLE); 1093 msg.arg1 = (enable ? ENABLED : DISABLED); 1094 sendMessage(msg); 1095 return true; 1096 } 1097 1098 protected void onSetInternalDataEnabled(boolean enabled) { 1099 synchronized (mDataEnabledLock) { 1100 mInternalDataEnabled = enabled; 1101 if (enabled) { 1102 log("onSetInternalDataEnabled: changed to enabled, try to setup data call"); 1103 resetAllRetryCounts(); 1104 onTrySetupData(Phone.REASON_DATA_ENABLED); 1105 } else { 1106 log("onSetInternalDataEnabled: changed to disabled, cleanUpAllConnections"); 1107 cleanUpAllConnections(null); 1108 } 1109 } 1110 } 1111 1112 public void cleanUpAllConnections(String cause) { 1113 Message msg = obtainMessage(EVENT_CLEAN_UP_ALL_CONNECTIONS); 1114 msg.obj = cause; 1115 sendMessage(msg); 1116 } 1117 1118 public abstract boolean isDisconnected(); 1119 1120 protected void onSetUserDataEnabled(boolean enabled) { 1121 synchronized (mDataEnabledLock) { 1122 final boolean prevEnabled = getAnyDataEnabled(); 1123 if (mUserDataEnabled != enabled) { 1124 mUserDataEnabled = enabled; 1125 Settings.Secure.putInt(mPhone.getContext().getContentResolver(), 1126 Settings.Secure.MOBILE_DATA, enabled ? 1 : 0); 1127 if (prevEnabled != getAnyDataEnabled()) { 1128 if (!prevEnabled) { 1129 resetAllRetryCounts(); 1130 onTrySetupData(Phone.REASON_DATA_ENABLED); 1131 } else { 1132 onCleanUpAllConnections(Phone.REASON_DATA_DISABLED); 1133 } 1134 } 1135 } 1136 } 1137 } 1138 1139 protected void onSetDependencyMet(String apnType, boolean met) { 1140 } 1141 1142 protected void onSetPolicyDataEnabled(boolean enabled) { 1143 synchronized (mDataEnabledLock) { 1144 final boolean prevEnabled = getAnyDataEnabled(); 1145 if (sPolicyDataEnabled != enabled) { 1146 sPolicyDataEnabled = enabled; 1147 if (prevEnabled != getAnyDataEnabled()) { 1148 if (!prevEnabled) { 1149 resetAllRetryCounts(); 1150 onTrySetupData(Phone.REASON_DATA_ENABLED); 1151 } else { 1152 onCleanUpAllConnections(Phone.REASON_DATA_DISABLED); 1153 } 1154 } 1155 } 1156 } 1157 } 1158 1159 protected String getReryConfig(boolean forDefault) { 1160 int rt = mPhone.getServiceState().getRadioTechnology(); 1161 1162 if ((rt == ServiceState.RADIO_TECHNOLOGY_IS95A) || 1163 (rt == ServiceState.RADIO_TECHNOLOGY_IS95B) || 1164 (rt == ServiceState.RADIO_TECHNOLOGY_1xRTT) || 1165 (rt == ServiceState.RADIO_TECHNOLOGY_EVDO_0) || 1166 (rt == ServiceState.RADIO_TECHNOLOGY_EVDO_A) || 1167 (rt == ServiceState.RADIO_TECHNOLOGY_EVDO_B) || 1168 (rt == ServiceState.RADIO_TECHNOLOGY_EHRPD)) { 1169 // CDMA variant 1170 return SystemProperties.get("ro.cdma.data_retry_config"); 1171 } else { 1172 // Use GSM varient for all others. 1173 if (forDefault) { 1174 return SystemProperties.get("ro.gsm.data_retry_config"); 1175 } else { 1176 return SystemProperties.get("ro.gsm.2nd_data_retry_config"); 1177 } 1178 } 1179 } 1180 1181 protected void resetAllRetryCounts() { 1182 for (DataConnection dc : mDataConnections.values()) { 1183 dc.resetRetryCount(); 1184 } 1185 } 1186 } 1187