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