1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.net; 18 19import android.content.BroadcastReceiver; 20import android.content.Context; 21import android.content.Intent; 22import android.content.IntentFilter; 23import android.net.NetworkInfo.DetailedState; 24import android.os.Bundle; 25import android.os.Handler; 26import android.os.Looper; 27import android.os.Message; 28import android.os.Messenger; 29import android.os.RemoteException; 30import android.os.ServiceManager; 31import android.telephony.PhoneStateListener; 32import android.telephony.SignalStrength; 33import android.telephony.TelephonyManager; 34import android.text.TextUtils; 35import android.util.Slog; 36 37import com.android.internal.telephony.DctConstants; 38import com.android.internal.telephony.ITelephony; 39import com.android.internal.telephony.PhoneConstants; 40import com.android.internal.telephony.TelephonyIntents; 41import com.android.internal.util.AsyncChannel; 42 43import java.io.CharArrayWriter; 44import java.io.PrintWriter; 45import java.util.concurrent.atomic.AtomicBoolean; 46 47/** 48 * Track the state of mobile data connectivity. This is done by 49 * receiving broadcast intents from the Phone process whenever 50 * the state of data connectivity changes. 51 * 52 * {@hide} 53 */ 54public class MobileDataStateTracker extends BaseNetworkStateTracker { 55 56 private static final String TAG = "MobileDataStateTracker"; 57 private static final boolean DBG = false; 58 private static final boolean VDBG = false; 59 60 private PhoneConstants.DataState mMobileDataState; 61 private ITelephony mPhoneService; 62 63 private String mApnType; 64 private NetworkInfo mNetworkInfo; 65 private boolean mTeardownRequested = false; 66 private Handler mTarget; 67 private Context mContext; 68 private LinkProperties mLinkProperties; 69 private boolean mPrivateDnsRouteSet = false; 70 private boolean mDefaultRouteSet = false; 71 72 // NOTE: these are only kept for debugging output; actual values are 73 // maintained in DataConnectionTracker. 74 protected boolean mUserDataEnabled = true; 75 protected boolean mPolicyDataEnabled = true; 76 77 private Handler mHandler; 78 private AsyncChannel mDataConnectionTrackerAc; 79 80 private AtomicBoolean mIsCaptivePortal = new AtomicBoolean(false); 81 82 private SignalStrength mSignalStrength; 83 84 private SamplingDataTracker mSamplingDataTracker = new SamplingDataTracker(); 85 86 private static final int UNKNOWN = LinkQualityInfo.UNKNOWN_INT; 87 88 /** 89 * Create a new MobileDataStateTracker 90 * @param netType the ConnectivityManager network type 91 * @param tag the name of this network 92 */ 93 public MobileDataStateTracker(int netType, String tag) { 94 mNetworkInfo = new NetworkInfo(netType, 95 TelephonyManager.getDefault().getNetworkType(), tag, 96 TelephonyManager.getDefault().getNetworkTypeName()); 97 mApnType = networkTypeToApnType(netType); 98 } 99 100 /** 101 * Begin monitoring data connectivity. 102 * 103 * @param context is the current Android context 104 * @param target is the Hander to which to return the events. 105 */ 106 public void startMonitoring(Context context, Handler target) { 107 mTarget = target; 108 mContext = context; 109 110 mHandler = new MdstHandler(target.getLooper(), this); 111 112 IntentFilter filter = new IntentFilter(); 113 filter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); 114 filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN); 115 filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED); 116 117 mContext.registerReceiver(new MobileDataStateReceiver(), filter); 118 mMobileDataState = PhoneConstants.DataState.DISCONNECTED; 119 120 TelephonyManager tm = (TelephonyManager)mContext.getSystemService( 121 Context.TELEPHONY_SERVICE); 122 tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS); 123 } 124 125 private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() { 126 @Override 127 public void onSignalStrengthsChanged(SignalStrength signalStrength) { 128 mSignalStrength = signalStrength; 129 } 130 }; 131 132 static class MdstHandler extends Handler { 133 private MobileDataStateTracker mMdst; 134 135 MdstHandler(Looper looper, MobileDataStateTracker mdst) { 136 super(looper); 137 mMdst = mdst; 138 } 139 140 @Override 141 public void handleMessage(Message msg) { 142 switch (msg.what) { 143 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 144 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 145 if (VDBG) { 146 mMdst.log("MdstHandler connected"); 147 } 148 mMdst.mDataConnectionTrackerAc = (AsyncChannel) msg.obj; 149 } else { 150 if (VDBG) { 151 mMdst.log("MdstHandler %s NOT connected error=" + msg.arg1); 152 } 153 } 154 break; 155 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 156 if (VDBG) mMdst.log("Disconnected from DataStateTracker"); 157 mMdst.mDataConnectionTrackerAc = null; 158 break; 159 default: { 160 if (VDBG) mMdst.log("Ignorning unknown message=" + msg); 161 break; 162 } 163 } 164 } 165 } 166 167 public boolean isPrivateDnsRouteSet() { 168 return mPrivateDnsRouteSet; 169 } 170 171 public void privateDnsRouteSet(boolean enabled) { 172 mPrivateDnsRouteSet = enabled; 173 } 174 175 public NetworkInfo getNetworkInfo() { 176 return mNetworkInfo; 177 } 178 179 public boolean isDefaultRouteSet() { 180 return mDefaultRouteSet; 181 } 182 183 public void defaultRouteSet(boolean enabled) { 184 mDefaultRouteSet = enabled; 185 } 186 187 /** 188 * This is not implemented. 189 */ 190 public void releaseWakeLock() { 191 } 192 193 private void updateLinkProperitesAndCapatilities(Intent intent) { 194 mLinkProperties = intent.getParcelableExtra( 195 PhoneConstants.DATA_LINK_PROPERTIES_KEY); 196 if (mLinkProperties == null) { 197 loge("CONNECTED event did not supply link properties."); 198 mLinkProperties = new LinkProperties(); 199 } 200 mLinkProperties.setMtu(mContext.getResources().getInteger( 201 com.android.internal.R.integer.config_mobile_mtu)); 202 mNetworkCapabilities = intent.getParcelableExtra( 203 PhoneConstants.DATA_NETWORK_CAPABILITIES_KEY); 204 if (mNetworkCapabilities == null) { 205 loge("CONNECTED event did not supply network capabilities."); 206 mNetworkCapabilities = new NetworkCapabilities(); 207 } 208 } 209 210 private class MobileDataStateReceiver extends BroadcastReceiver { 211 @Override 212 public void onReceive(Context context, Intent intent) { 213 if (intent.getAction().equals(TelephonyIntents. 214 ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN)) { 215 String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY); 216 String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY); 217 if (!TextUtils.equals(mApnType, apnType)) { 218 return; 219 } 220 if (DBG) { 221 log("Broadcast received: " + intent.getAction() + " apnType=" + apnType 222 + " apnName=" + apnName); 223 } 224 225 // Make us in the connecting state until we make a new TYPE_MOBILE_PROVISIONING 226 mMobileDataState = PhoneConstants.DataState.CONNECTING; 227 updateLinkProperitesAndCapatilities(intent); 228 mNetworkInfo.setIsConnectedToProvisioningNetwork(true); 229 230 // Change state to SUSPENDED so setDetailedState 231 // sends EVENT_STATE_CHANGED to connectivityService 232 setDetailedState(DetailedState.SUSPENDED, "", apnName); 233 } else if (intent.getAction().equals(TelephonyIntents. 234 ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) { 235 String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY); 236 if (VDBG) { 237 log(String.format("Broadcast received: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED" 238 + "mApnType=%s %s received apnType=%s", mApnType, 239 TextUtils.equals(apnType, mApnType) ? "==" : "!=", apnType)); 240 } 241 if (!TextUtils.equals(apnType, mApnType)) { 242 return; 243 } 244 // Assume this isn't a provisioning network. 245 mNetworkInfo.setIsConnectedToProvisioningNetwork(false); 246 if (DBG) { 247 log("Broadcast received: " + intent.getAction() + " apnType=" + apnType); 248 } 249 250 int oldSubtype = mNetworkInfo.getSubtype(); 251 int newSubType = TelephonyManager.getDefault().getNetworkType(); 252 String subTypeName = TelephonyManager.getDefault().getNetworkTypeName(); 253 mNetworkInfo.setSubtype(newSubType, subTypeName); 254 if (newSubType != oldSubtype && mNetworkInfo.isConnected()) { 255 Message msg = mTarget.obtainMessage(EVENT_NETWORK_SUBTYPE_CHANGED, 256 oldSubtype, 0, mNetworkInfo); 257 msg.sendToTarget(); 258 } 259 260 PhoneConstants.DataState state = Enum.valueOf(PhoneConstants.DataState.class, 261 intent.getStringExtra(PhoneConstants.STATE_KEY)); 262 String reason = intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY); 263 String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY); 264 mNetworkInfo.setRoaming(intent.getBooleanExtra( 265 PhoneConstants.DATA_NETWORK_ROAMING_KEY, false)); 266 if (VDBG) { 267 log(mApnType + " setting isAvailable to " + 268 intent.getBooleanExtra(PhoneConstants.NETWORK_UNAVAILABLE_KEY,false)); 269 } 270 mNetworkInfo.setIsAvailable(!intent.getBooleanExtra( 271 PhoneConstants.NETWORK_UNAVAILABLE_KEY, false)); 272 273 if (DBG) { 274 log("Received state=" + state + ", old=" + mMobileDataState + 275 ", reason=" + (reason == null ? "(unspecified)" : reason)); 276 } 277 if (mMobileDataState != state) { 278 mMobileDataState = state; 279 switch (state) { 280 case DISCONNECTED: 281 if(isTeardownRequested()) { 282 setTeardownRequested(false); 283 } 284 285 setDetailedState(DetailedState.DISCONNECTED, reason, apnName); 286 // can't do this here - ConnectivityService needs it to clear stuff 287 // it's ok though - just leave it to be refreshed next time 288 // we connect. 289 //if (DBG) log("clearing mInterfaceName for "+ mApnType + 290 // " as it DISCONNECTED"); 291 //mInterfaceName = null; 292 break; 293 case CONNECTING: 294 setDetailedState(DetailedState.CONNECTING, reason, apnName); 295 break; 296 case SUSPENDED: 297 setDetailedState(DetailedState.SUSPENDED, reason, apnName); 298 break; 299 case CONNECTED: 300 updateLinkProperitesAndCapatilities(intent); 301 setDetailedState(DetailedState.CONNECTED, reason, apnName); 302 break; 303 } 304 305 if (VDBG) { 306 Slog.d(TAG, "TelephonyMgr.DataConnectionStateChanged"); 307 if (mNetworkInfo != null) { 308 Slog.d(TAG, "NetworkInfo = " + mNetworkInfo); 309 Slog.d(TAG, "subType = " + mNetworkInfo.getSubtype()); 310 Slog.d(TAG, "subType = " + mNetworkInfo.getSubtypeName()); 311 } 312 if (mLinkProperties != null) { 313 Slog.d(TAG, "LinkProperties = " + mLinkProperties); 314 } else { 315 Slog.d(TAG, "LinkProperties = " ); 316 } 317 318 if (mNetworkCapabilities != null) { 319 Slog.d(TAG, mNetworkCapabilities.toString()); 320 } else { 321 Slog.d(TAG, "NetworkCapabilities = " ); 322 } 323 } 324 325 326 /* lets not sample traffic data across state changes */ 327 mSamplingDataTracker.resetSamplingData(); 328 } else { 329 // There was no state change. Check if LinkProperties has been updated. 330 if (TextUtils.equals(reason, PhoneConstants.REASON_LINK_PROPERTIES_CHANGED)) { 331 mLinkProperties = intent.getParcelableExtra( 332 PhoneConstants.DATA_LINK_PROPERTIES_KEY); 333 if (mLinkProperties == null) { 334 loge("No link property in LINK_PROPERTIES change event."); 335 mLinkProperties = new LinkProperties(); 336 } 337 // Just update reason field in this NetworkInfo 338 mNetworkInfo.setDetailedState(mNetworkInfo.getDetailedState(), reason, 339 mNetworkInfo.getExtraInfo()); 340 Message msg = mTarget.obtainMessage(EVENT_CONFIGURATION_CHANGED, 341 mNetworkInfo); 342 msg.sendToTarget(); 343 } 344 } 345 } else if (intent.getAction(). 346 equals(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED)) { 347 String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY); 348 if (!TextUtils.equals(apnType, mApnType)) { 349 if (DBG) { 350 log(String.format( 351 "Broadcast received: ACTION_ANY_DATA_CONNECTION_FAILED ignore, " + 352 "mApnType=%s != received apnType=%s", mApnType, apnType)); 353 } 354 return; 355 } 356 // Assume this isn't a provisioning network. 357 mNetworkInfo.setIsConnectedToProvisioningNetwork(false); 358 String reason = intent.getStringExtra(PhoneConstants.FAILURE_REASON_KEY); 359 String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY); 360 if (DBG) { 361 log("Broadcast received: " + intent.getAction() + 362 " reason=" + reason == null ? "null" : reason); 363 } 364 setDetailedState(DetailedState.FAILED, reason, apnName); 365 } else { 366 if (DBG) log("Broadcast received: ignore " + intent.getAction()); 367 } 368 } 369 } 370 371 private void getPhoneService(boolean forceRefresh) { 372 if ((mPhoneService == null) || forceRefresh) { 373 mPhoneService = ITelephony.Stub.asInterface(ServiceManager.getService("phone")); 374 } 375 } 376 377 /** 378 * Report whether data connectivity is possible. 379 */ 380 public boolean isAvailable() { 381 return mNetworkInfo.isAvailable(); 382 } 383 384 /** 385 * Return the system properties name associated with the tcp buffer sizes 386 * for this network. 387 */ 388 public String getTcpBufferSizesPropName() { 389 String networkTypeStr = "unknown"; 390 TelephonyManager tm = new TelephonyManager(mContext); 391 //TODO We have to edit the parameter for getNetworkType regarding CDMA 392 switch(tm.getNetworkType()) { 393 case TelephonyManager.NETWORK_TYPE_GPRS: 394 networkTypeStr = "gprs"; 395 break; 396 case TelephonyManager.NETWORK_TYPE_EDGE: 397 networkTypeStr = "edge"; 398 break; 399 case TelephonyManager.NETWORK_TYPE_UMTS: 400 networkTypeStr = "umts"; 401 break; 402 case TelephonyManager.NETWORK_TYPE_HSDPA: 403 networkTypeStr = "hsdpa"; 404 break; 405 case TelephonyManager.NETWORK_TYPE_HSUPA: 406 networkTypeStr = "hsupa"; 407 break; 408 case TelephonyManager.NETWORK_TYPE_HSPA: 409 networkTypeStr = "hspa"; 410 break; 411 case TelephonyManager.NETWORK_TYPE_HSPAP: 412 networkTypeStr = "hspap"; 413 break; 414 case TelephonyManager.NETWORK_TYPE_CDMA: 415 networkTypeStr = "cdma"; 416 break; 417 case TelephonyManager.NETWORK_TYPE_1xRTT: 418 networkTypeStr = "1xrtt"; 419 break; 420 case TelephonyManager.NETWORK_TYPE_EVDO_0: 421 networkTypeStr = "evdo"; 422 break; 423 case TelephonyManager.NETWORK_TYPE_EVDO_A: 424 networkTypeStr = "evdo"; 425 break; 426 case TelephonyManager.NETWORK_TYPE_EVDO_B: 427 networkTypeStr = "evdo"; 428 break; 429 case TelephonyManager.NETWORK_TYPE_IDEN: 430 networkTypeStr = "iden"; 431 break; 432 case TelephonyManager.NETWORK_TYPE_LTE: 433 networkTypeStr = "lte"; 434 break; 435 case TelephonyManager.NETWORK_TYPE_EHRPD: 436 networkTypeStr = "ehrpd"; 437 break; 438 default: 439 loge("unknown network type: " + tm.getNetworkType()); 440 } 441 return "net.tcp.buffersize." + networkTypeStr; 442 } 443 444 /** 445 * Tear down mobile data connectivity, i.e., disable the ability to create 446 * mobile data connections. 447 * TODO - make async and return nothing? 448 */ 449 public boolean teardown() { 450 setTeardownRequested(true); 451 return (setEnableApn(mApnType, false) != PhoneConstants.APN_REQUEST_FAILED); 452 } 453 454 /** 455 * @return true if this is ready to operate 456 */ 457 public boolean isReady() { 458 return mDataConnectionTrackerAc != null; 459 } 460 461 @Override 462 public void captivePortalCheckCompleted(boolean isCaptivePortal) { 463 if (mIsCaptivePortal.getAndSet(isCaptivePortal) != isCaptivePortal) { 464 // Captive portal change enable/disable failing fast 465 setEnableFailFastMobileData( 466 isCaptivePortal ? DctConstants.ENABLED : DctConstants.DISABLED); 467 } 468 } 469 470 /** 471 * Record the detailed state of a network, and if it is a 472 * change from the previous state, send a notification to 473 * any listeners. 474 * @param state the new {@code DetailedState} 475 * @param reason a {@code String} indicating a reason for the state change, 476 * if one was supplied. May be {@code null}. 477 * @param extraInfo optional {@code String} providing extra information about the state change 478 */ 479 private void setDetailedState(NetworkInfo.DetailedState state, String reason, 480 String extraInfo) { 481 if (DBG) log("setDetailed state, old =" 482 + mNetworkInfo.getDetailedState() + " and new state=" + state); 483 if (state != mNetworkInfo.getDetailedState()) { 484 boolean wasConnecting = (mNetworkInfo.getState() == NetworkInfo.State.CONNECTING); 485 String lastReason = mNetworkInfo.getReason(); 486 /* 487 * If a reason was supplied when the CONNECTING state was entered, and no 488 * reason was supplied for entering the CONNECTED state, then retain the 489 * reason that was supplied when going to CONNECTING. 490 */ 491 if (wasConnecting && state == NetworkInfo.DetailedState.CONNECTED && reason == null 492 && lastReason != null) 493 reason = lastReason; 494 mNetworkInfo.setDetailedState(state, reason, extraInfo); 495 Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, new NetworkInfo(mNetworkInfo)); 496 msg.sendToTarget(); 497 } 498 } 499 500 public void setTeardownRequested(boolean isRequested) { 501 mTeardownRequested = isRequested; 502 } 503 504 public boolean isTeardownRequested() { 505 return mTeardownRequested; 506 } 507 508 /** 509 * Re-enable mobile data connectivity after a {@link #teardown()}. 510 * TODO - make async and always get a notification? 511 */ 512 public boolean reconnect() { 513 boolean retValue = false; //connected or expect to be? 514 setTeardownRequested(false); 515 switch (setEnableApn(mApnType, true)) { 516 case PhoneConstants.APN_ALREADY_ACTIVE: 517 // need to set self to CONNECTING so the below message is handled. 518 retValue = true; 519 break; 520 case PhoneConstants.APN_REQUEST_STARTED: 521 // set IDLE here , avoid the following second FAILED not sent out 522 mNetworkInfo.setDetailedState(DetailedState.IDLE, null, null); 523 retValue = true; 524 break; 525 case PhoneConstants.APN_REQUEST_FAILED: 526 case PhoneConstants.APN_TYPE_NOT_AVAILABLE: 527 break; 528 default: 529 loge("Error in reconnect - unexpected response."); 530 break; 531 } 532 return retValue; 533 } 534 535 /** 536 * Turn on or off the mobile radio. No connectivity will be possible while the 537 * radio is off. The operation is a no-op if the radio is already in the desired state. 538 * @param turnOn {@code true} if the radio should be turned on, {@code false} if 539 */ 540 public boolean setRadio(boolean turnOn) { 541 getPhoneService(false); 542 /* 543 * If the phone process has crashed in the past, we'll get a 544 * RemoteException and need to re-reference the service. 545 */ 546 for (int retry = 0; retry < 2; retry++) { 547 if (mPhoneService == null) { 548 loge("Ignoring mobile radio request because could not acquire PhoneService"); 549 break; 550 } 551 552 try { 553 return mPhoneService.setRadio(turnOn); 554 } catch (RemoteException e) { 555 if (retry == 0) getPhoneService(true); 556 } 557 } 558 559 loge("Could not set radio power to " + (turnOn ? "on" : "off")); 560 return false; 561 } 562 563 564 public void setInternalDataEnable(boolean enabled) { 565 if (DBG) log("setInternalDataEnable: E enabled=" + enabled); 566 final AsyncChannel channel = mDataConnectionTrackerAc; 567 if (channel != null) { 568 channel.sendMessage(DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE, 569 enabled ? DctConstants.ENABLED : DctConstants.DISABLED); 570 } 571 if (VDBG) log("setInternalDataEnable: X enabled=" + enabled); 572 } 573 574 @Override 575 public void setUserDataEnable(boolean enabled) { 576 if (DBG) log("setUserDataEnable: E enabled=" + enabled); 577 final AsyncChannel channel = mDataConnectionTrackerAc; 578 if (channel != null) { 579 channel.sendMessage(DctConstants.CMD_SET_USER_DATA_ENABLE, 580 enabled ? DctConstants.ENABLED : DctConstants.DISABLED); 581 mUserDataEnabled = enabled; 582 } 583 if (VDBG) log("setUserDataEnable: X enabled=" + enabled); 584 } 585 586 @Override 587 public void setPolicyDataEnable(boolean enabled) { 588 if (DBG) log("setPolicyDataEnable(enabled=" + enabled + ")"); 589 final AsyncChannel channel = mDataConnectionTrackerAc; 590 if (channel != null) { 591 channel.sendMessage(DctConstants.CMD_SET_POLICY_DATA_ENABLE, 592 enabled ? DctConstants.ENABLED : DctConstants.DISABLED); 593 mPolicyDataEnabled = enabled; 594 } 595 } 596 597 /** 598 * Eanble/disable FailFast 599 * 600 * @param enabled is DctConstants.ENABLED/DISABLED 601 */ 602 public void setEnableFailFastMobileData(int enabled) { 603 if (DBG) log("setEnableFailFastMobileData(enabled=" + enabled + ")"); 604 final AsyncChannel channel = mDataConnectionTrackerAc; 605 if (channel != null) { 606 channel.sendMessage(DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA, enabled); 607 } 608 } 609 610 /** 611 * carrier dependency is met/unmet 612 * @param met 613 */ 614 public void setDependencyMet(boolean met) { 615 Bundle bundle = Bundle.forPair(DctConstants.APN_TYPE_KEY, mApnType); 616 try { 617 if (DBG) log("setDependencyMet: E met=" + met); 618 Message msg = Message.obtain(); 619 msg.what = DctConstants.CMD_SET_DEPENDENCY_MET; 620 msg.arg1 = (met ? DctConstants.ENABLED : DctConstants.DISABLED); 621 msg.setData(bundle); 622 mDataConnectionTrackerAc.sendMessage(msg); 623 if (VDBG) log("setDependencyMet: X met=" + met); 624 } catch (NullPointerException e) { 625 loge("setDependencyMet: X mAc was null" + e); 626 } 627 } 628 629 /** 630 * Inform DCT mobile provisioning has started, it ends when provisioning completes. 631 */ 632 public void enableMobileProvisioning(String url) { 633 if (DBG) log("enableMobileProvisioning(url=" + url + ")"); 634 final AsyncChannel channel = mDataConnectionTrackerAc; 635 if (channel != null) { 636 Message msg = Message.obtain(); 637 msg.what = DctConstants.CMD_ENABLE_MOBILE_PROVISIONING; 638 msg.setData(Bundle.forPair(DctConstants.PROVISIONING_URL_KEY, url)); 639 channel.sendMessage(msg); 640 } 641 } 642 643 /** 644 * Return if this network is the provisioning network. Valid only if connected. 645 * @param met 646 */ 647 public boolean isProvisioningNetwork() { 648 boolean retVal; 649 try { 650 Message msg = Message.obtain(); 651 msg.what = DctConstants.CMD_IS_PROVISIONING_APN; 652 msg.setData(Bundle.forPair(DctConstants.APN_TYPE_KEY, mApnType)); 653 Message result = mDataConnectionTrackerAc.sendMessageSynchronously(msg); 654 retVal = result.arg1 == DctConstants.ENABLED; 655 } catch (NullPointerException e) { 656 loge("isProvisioningNetwork: X " + e); 657 retVal = false; 658 } 659 if (DBG) log("isProvisioningNetwork: retVal=" + retVal); 660 return retVal; 661 } 662 663 @Override 664 public void addStackedLink(LinkProperties link) { 665 mLinkProperties.addStackedLink(link); 666 } 667 668 @Override 669 public void removeStackedLink(LinkProperties link) { 670 mLinkProperties.removeStackedLink(link); 671 } 672 673 @Override 674 public String toString() { 675 final CharArrayWriter writer = new CharArrayWriter(); 676 final PrintWriter pw = new PrintWriter(writer); 677 pw.print("Mobile data state: "); pw.println(mMobileDataState); 678 pw.print("Data enabled: user="); pw.print(mUserDataEnabled); 679 pw.print(", policy="); pw.println(mPolicyDataEnabled); 680 return writer.toString(); 681 } 682 683 /** 684 * Internal method supporting the ENABLE_MMS feature. 685 * @param apnType the type of APN to be enabled or disabled (e.g., mms) 686 * @param enable {@code true} to enable the specified APN type, 687 * {@code false} to disable it. 688 * @return an integer value representing the outcome of the request. 689 */ 690 private int setEnableApn(String apnType, boolean enable) { 691 getPhoneService(false); 692 /* 693 * If the phone process has crashed in the past, we'll get a 694 * RemoteException and need to re-reference the service. 695 */ 696 for (int retry = 0; retry < 2; retry++) { 697 if (mPhoneService == null) { 698 loge("Ignoring feature request because could not acquire PhoneService"); 699 break; 700 } 701 702// try { 703// if (enable) { 704// return mPhoneService.enableApnType(apnType); 705// } else { 706// return mPhoneService.disableApnType(apnType); 707// } 708// } catch (RemoteException e) { 709// if (retry == 0) getPhoneService(true); 710// } 711 } 712 713 loge("Could not " + (enable ? "enable" : "disable") + " APN type \"" + apnType + "\""); 714 return PhoneConstants.APN_REQUEST_FAILED; 715 } 716 717 public static String networkTypeToApnType(int netType) { 718 switch(netType) { 719 case ConnectivityManager.TYPE_MOBILE: 720 return PhoneConstants.APN_TYPE_DEFAULT; // TODO - use just one of these 721 case ConnectivityManager.TYPE_MOBILE_MMS: 722 return PhoneConstants.APN_TYPE_MMS; 723 case ConnectivityManager.TYPE_MOBILE_SUPL: 724 return PhoneConstants.APN_TYPE_SUPL; 725 case ConnectivityManager.TYPE_MOBILE_DUN: 726 return PhoneConstants.APN_TYPE_DUN; 727 case ConnectivityManager.TYPE_MOBILE_HIPRI: 728 return PhoneConstants.APN_TYPE_HIPRI; 729 case ConnectivityManager.TYPE_MOBILE_FOTA: 730 return PhoneConstants.APN_TYPE_FOTA; 731 case ConnectivityManager.TYPE_MOBILE_IMS: 732 return PhoneConstants.APN_TYPE_IMS; 733 case ConnectivityManager.TYPE_MOBILE_CBS: 734 return PhoneConstants.APN_TYPE_CBS; 735 case ConnectivityManager.TYPE_MOBILE_IA: 736 return PhoneConstants.APN_TYPE_IA; 737 case ConnectivityManager.TYPE_MOBILE_EMERGENCY: 738 return PhoneConstants.APN_TYPE_EMERGENCY; 739 default: 740 sloge("Error mapping networkType " + netType + " to apnType."); 741 return null; 742 } 743 } 744 745 746 /** 747 * @see android.net.NetworkStateTracker#getLinkProperties() 748 */ 749 @Override 750 public LinkProperties getLinkProperties() { 751 return new LinkProperties(mLinkProperties); 752 } 753 754 public void supplyMessenger(Messenger messenger) { 755 if (VDBG) log(mApnType + " got supplyMessenger"); 756 AsyncChannel ac = new AsyncChannel(); 757 ac.connect(mContext, MobileDataStateTracker.this.mHandler, messenger); 758 } 759 760 private void log(String s) { 761 Slog.d(TAG, mApnType + ": " + s); 762 } 763 764 private void loge(String s) { 765 Slog.e(TAG, mApnType + ": " + s); 766 } 767 768 static private void sloge(String s) { 769 Slog.e(TAG, s); 770 } 771 772 @Override 773 public LinkQualityInfo getLinkQualityInfo() { 774 if (mNetworkInfo == null || mNetworkInfo.getType() == ConnectivityManager.TYPE_NONE) { 775 // no data available yet; just return 776 return null; 777 } 778 779 MobileLinkQualityInfo li = new MobileLinkQualityInfo(); 780 781 li.setNetworkType(mNetworkInfo.getType()); 782 783 mSamplingDataTracker.setCommonLinkQualityInfoFields(li); 784 785 if (mNetworkInfo.getSubtype() != TelephonyManager.NETWORK_TYPE_UNKNOWN) { 786 li.setMobileNetworkType(mNetworkInfo.getSubtype()); 787 788 NetworkDataEntry entry = getNetworkDataEntry(mNetworkInfo.getSubtype()); 789 if (entry != null) { 790 li.setTheoreticalRxBandwidth(entry.downloadBandwidth); 791 li.setTheoreticalRxBandwidth(entry.uploadBandwidth); 792 li.setTheoreticalLatency(entry.latency); 793 } 794 795 if (mSignalStrength != null) { 796 li.setNormalizedSignalStrength(getNormalizedSignalStrength( 797 li.getMobileNetworkType(), mSignalStrength)); 798 } 799 } 800 801 SignalStrength ss = mSignalStrength; 802 if (ss != null) { 803 804 li.setRssi(ss.getGsmSignalStrength()); 805 li.setGsmErrorRate(ss.getGsmBitErrorRate()); 806 li.setCdmaDbm(ss.getCdmaDbm()); 807 li.setCdmaEcio(ss.getCdmaEcio()); 808 li.setEvdoDbm(ss.getEvdoDbm()); 809 li.setEvdoEcio(ss.getEvdoEcio()); 810 li.setEvdoSnr(ss.getEvdoSnr()); 811 li.setLteSignalStrength(ss.getLteSignalStrength()); 812 li.setLteRsrp(ss.getLteRsrp()); 813 li.setLteRsrq(ss.getLteRsrq()); 814 li.setLteRssnr(ss.getLteRssnr()); 815 li.setLteCqi(ss.getLteCqi()); 816 } 817 818 if (VDBG) { 819 Slog.d(TAG, "Returning LinkQualityInfo with" 820 + " MobileNetworkType = " + String.valueOf(li.getMobileNetworkType()) 821 + " Theoretical Rx BW = " + String.valueOf(li.getTheoreticalRxBandwidth()) 822 + " gsm Signal Strength = " + String.valueOf(li.getRssi()) 823 + " cdma Signal Strength = " + String.valueOf(li.getCdmaDbm()) 824 + " evdo Signal Strength = " + String.valueOf(li.getEvdoDbm()) 825 + " Lte Signal Strength = " + String.valueOf(li.getLteSignalStrength())); 826 } 827 828 return li; 829 } 830 831 static class NetworkDataEntry { 832 public int networkType; 833 public int downloadBandwidth; // in kbps 834 public int uploadBandwidth; // in kbps 835 public int latency; // in millisecond 836 837 NetworkDataEntry(int i1, int i2, int i3, int i4) { 838 networkType = i1; 839 downloadBandwidth = i2; 840 uploadBandwidth = i3; 841 latency = i4; 842 } 843 } 844 845 private static NetworkDataEntry [] mTheoreticalBWTable = new NetworkDataEntry[] { 846 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EDGE, 237, 118, UNKNOWN), 847 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_GPRS, 48, 40, UNKNOWN), 848 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_UMTS, 384, 64, UNKNOWN), 849 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSDPA, 14400, UNKNOWN, UNKNOWN), 850 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSUPA, 14400, 5760, UNKNOWN), 851 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSPA, 14400, 5760, UNKNOWN), 852 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSPAP, 21000, 5760, UNKNOWN), 853 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_CDMA, UNKNOWN, UNKNOWN, UNKNOWN), 854 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_1xRTT, UNKNOWN, UNKNOWN, UNKNOWN), 855 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_0, 2468, 153, UNKNOWN), 856 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_A, 3072, 1800, UNKNOWN), 857 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_B, 14700, 1800, UNKNOWN), 858 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_IDEN, UNKNOWN, UNKNOWN, UNKNOWN), 859 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_LTE, 100000, 50000, UNKNOWN), 860 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EHRPD, UNKNOWN, UNKNOWN, UNKNOWN), 861 }; 862 863 private static NetworkDataEntry getNetworkDataEntry(int networkType) { 864 for (NetworkDataEntry entry : mTheoreticalBWTable) { 865 if (entry.networkType == networkType) { 866 return entry; 867 } 868 } 869 870 Slog.e(TAG, "Could not find Theoretical BW entry for " + String.valueOf(networkType)); 871 return null; 872 } 873 874 private static int getNormalizedSignalStrength(int networkType, SignalStrength ss) { 875 876 int level; 877 878 switch(networkType) { 879 case TelephonyManager.NETWORK_TYPE_EDGE: 880 case TelephonyManager.NETWORK_TYPE_GPRS: 881 case TelephonyManager.NETWORK_TYPE_UMTS: 882 case TelephonyManager.NETWORK_TYPE_HSDPA: 883 case TelephonyManager.NETWORK_TYPE_HSUPA: 884 case TelephonyManager.NETWORK_TYPE_HSPA: 885 case TelephonyManager.NETWORK_TYPE_HSPAP: 886 level = ss.getGsmLevel(); 887 break; 888 case TelephonyManager.NETWORK_TYPE_CDMA: 889 case TelephonyManager.NETWORK_TYPE_1xRTT: 890 level = ss.getCdmaLevel(); 891 break; 892 case TelephonyManager.NETWORK_TYPE_EVDO_0: 893 case TelephonyManager.NETWORK_TYPE_EVDO_A: 894 case TelephonyManager.NETWORK_TYPE_EVDO_B: 895 level = ss.getEvdoLevel(); 896 break; 897 case TelephonyManager.NETWORK_TYPE_LTE: 898 level = ss.getLteLevel(); 899 break; 900 case TelephonyManager.NETWORK_TYPE_IDEN: 901 case TelephonyManager.NETWORK_TYPE_EHRPD: 902 default: 903 return UNKNOWN; 904 } 905 906 return (level * LinkQualityInfo.NORMALIZED_SIGNAL_STRENGTH_RANGE) / 907 SignalStrength.NUM_SIGNAL_STRENGTH_BINS; 908 } 909 910 @Override 911 public void startSampling(SamplingDataTracker.SamplingSnapshot s) { 912 mSamplingDataTracker.startSampling(s); 913 } 914 915 @Override 916 public void stopSampling(SamplingDataTracker.SamplingSnapshot s) { 917 mSamplingDataTracker.stopSampling(s); 918 } 919} 920