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