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 17 package android.net; 18 19 import android.content.BroadcastReceiver; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.IntentFilter; 23 import android.net.NetworkInfo.DetailedState; 24 import android.os.Bundle; 25 import android.os.Handler; 26 import android.os.Looper; 27 import android.os.Message; 28 import android.os.Messenger; 29 import android.os.RemoteException; 30 import android.os.ServiceManager; 31 import android.telephony.PhoneStateListener; 32 import android.telephony.SignalStrength; 33 import android.telephony.TelephonyManager; 34 import android.text.TextUtils; 35 import android.util.Slog; 36 37 import com.android.internal.telephony.DctConstants; 38 import com.android.internal.telephony.ITelephony; 39 import com.android.internal.telephony.PhoneConstants; 40 import com.android.internal.telephony.TelephonyIntents; 41 import com.android.internal.util.AsyncChannel; 42 43 import java.io.CharArrayWriter; 44 import java.io.PrintWriter; 45 import 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 */ 54 public 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 String toString() { 665 final CharArrayWriter writer = new CharArrayWriter(); 666 final PrintWriter pw = new PrintWriter(writer); 667 pw.print("Mobile data state: "); pw.println(mMobileDataState); 668 pw.print("Data enabled: user="); pw.print(mUserDataEnabled); 669 pw.print(", policy="); pw.println(mPolicyDataEnabled); 670 return writer.toString(); 671 } 672 673 /** 674 * Internal method supporting the ENABLE_MMS feature. 675 * @param apnType the type of APN to be enabled or disabled (e.g., mms) 676 * @param enable {@code true} to enable the specified APN type, 677 * {@code false} to disable it. 678 * @return an integer value representing the outcome of the request. 679 */ 680 private int setEnableApn(String apnType, boolean enable) { 681 getPhoneService(false); 682 /* 683 * If the phone process has crashed in the past, we'll get a 684 * RemoteException and need to re-reference the service. 685 */ 686 for (int retry = 0; retry < 2; retry++) { 687 if (mPhoneService == null) { 688 loge("Ignoring feature request because could not acquire PhoneService"); 689 break; 690 } 691 692 // try { 693 // if (enable) { 694 // return mPhoneService.enableApnType(apnType); 695 // } else { 696 // return mPhoneService.disableApnType(apnType); 697 // } 698 // } catch (RemoteException e) { 699 // if (retry == 0) getPhoneService(true); 700 // } 701 } 702 703 loge("Could not " + (enable ? "enable" : "disable") + " APN type \"" + apnType + "\""); 704 return PhoneConstants.APN_REQUEST_FAILED; 705 } 706 707 public static String networkTypeToApnType(int netType) { 708 switch(netType) { 709 case ConnectivityManager.TYPE_MOBILE: 710 return PhoneConstants.APN_TYPE_DEFAULT; // TODO - use just one of these 711 case ConnectivityManager.TYPE_MOBILE_MMS: 712 return PhoneConstants.APN_TYPE_MMS; 713 case ConnectivityManager.TYPE_MOBILE_SUPL: 714 return PhoneConstants.APN_TYPE_SUPL; 715 case ConnectivityManager.TYPE_MOBILE_DUN: 716 return PhoneConstants.APN_TYPE_DUN; 717 case ConnectivityManager.TYPE_MOBILE_HIPRI: 718 return PhoneConstants.APN_TYPE_HIPRI; 719 case ConnectivityManager.TYPE_MOBILE_FOTA: 720 return PhoneConstants.APN_TYPE_FOTA; 721 case ConnectivityManager.TYPE_MOBILE_IMS: 722 return PhoneConstants.APN_TYPE_IMS; 723 case ConnectivityManager.TYPE_MOBILE_CBS: 724 return PhoneConstants.APN_TYPE_CBS; 725 case ConnectivityManager.TYPE_MOBILE_IA: 726 return PhoneConstants.APN_TYPE_IA; 727 case ConnectivityManager.TYPE_MOBILE_EMERGENCY: 728 return PhoneConstants.APN_TYPE_EMERGENCY; 729 default: 730 sloge("Error mapping networkType " + netType + " to apnType."); 731 return null; 732 } 733 } 734 735 736 /** 737 * @see android.net.NetworkStateTracker#getLinkProperties() 738 */ 739 @Override 740 public LinkProperties getLinkProperties() { 741 return new LinkProperties(mLinkProperties); 742 } 743 744 public void supplyMessenger(Messenger messenger) { 745 if (VDBG) log(mApnType + " got supplyMessenger"); 746 AsyncChannel ac = new AsyncChannel(); 747 ac.connect(mContext, MobileDataStateTracker.this.mHandler, messenger); 748 } 749 750 private void log(String s) { 751 Slog.d(TAG, mApnType + ": " + s); 752 } 753 754 private void loge(String s) { 755 Slog.e(TAG, mApnType + ": " + s); 756 } 757 758 static private void sloge(String s) { 759 Slog.e(TAG, s); 760 } 761 762 @Override 763 public LinkQualityInfo getLinkQualityInfo() { 764 if (mNetworkInfo == null || mNetworkInfo.getType() == ConnectivityManager.TYPE_NONE) { 765 // no data available yet; just return 766 return null; 767 } 768 769 MobileLinkQualityInfo li = new MobileLinkQualityInfo(); 770 771 li.setNetworkType(mNetworkInfo.getType()); 772 773 mSamplingDataTracker.setCommonLinkQualityInfoFields(li); 774 775 if (mNetworkInfo.getSubtype() != TelephonyManager.NETWORK_TYPE_UNKNOWN) { 776 li.setMobileNetworkType(mNetworkInfo.getSubtype()); 777 778 NetworkDataEntry entry = getNetworkDataEntry(mNetworkInfo.getSubtype()); 779 if (entry != null) { 780 li.setTheoreticalRxBandwidth(entry.downloadBandwidth); 781 li.setTheoreticalRxBandwidth(entry.uploadBandwidth); 782 li.setTheoreticalLatency(entry.latency); 783 } 784 785 if (mSignalStrength != null) { 786 li.setNormalizedSignalStrength(getNormalizedSignalStrength( 787 li.getMobileNetworkType(), mSignalStrength)); 788 } 789 } 790 791 SignalStrength ss = mSignalStrength; 792 if (ss != null) { 793 794 li.setRssi(ss.getGsmSignalStrength()); 795 li.setGsmErrorRate(ss.getGsmBitErrorRate()); 796 li.setCdmaDbm(ss.getCdmaDbm()); 797 li.setCdmaEcio(ss.getCdmaEcio()); 798 li.setEvdoDbm(ss.getEvdoDbm()); 799 li.setEvdoEcio(ss.getEvdoEcio()); 800 li.setEvdoSnr(ss.getEvdoSnr()); 801 li.setLteSignalStrength(ss.getLteSignalStrength()); 802 li.setLteRsrp(ss.getLteRsrp()); 803 li.setLteRsrq(ss.getLteRsrq()); 804 li.setLteRssnr(ss.getLteRssnr()); 805 li.setLteCqi(ss.getLteCqi()); 806 } 807 808 if (VDBG) { 809 Slog.d(TAG, "Returning LinkQualityInfo with" 810 + " MobileNetworkType = " + String.valueOf(li.getMobileNetworkType()) 811 + " Theoretical Rx BW = " + String.valueOf(li.getTheoreticalRxBandwidth()) 812 + " gsm Signal Strength = " + String.valueOf(li.getRssi()) 813 + " cdma Signal Strength = " + String.valueOf(li.getCdmaDbm()) 814 + " evdo Signal Strength = " + String.valueOf(li.getEvdoDbm()) 815 + " Lte Signal Strength = " + String.valueOf(li.getLteSignalStrength())); 816 } 817 818 return li; 819 } 820 821 static class NetworkDataEntry { 822 public int networkType; 823 public int downloadBandwidth; // in kbps 824 public int uploadBandwidth; // in kbps 825 public int latency; // in millisecond 826 827 NetworkDataEntry(int i1, int i2, int i3, int i4) { 828 networkType = i1; 829 downloadBandwidth = i2; 830 uploadBandwidth = i3; 831 latency = i4; 832 } 833 } 834 835 private static NetworkDataEntry [] mTheoreticalBWTable = new NetworkDataEntry[] { 836 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EDGE, 237, 118, UNKNOWN), 837 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_GPRS, 48, 40, UNKNOWN), 838 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_UMTS, 384, 64, UNKNOWN), 839 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSDPA, 14400, UNKNOWN, UNKNOWN), 840 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSUPA, 14400, 5760, UNKNOWN), 841 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSPA, 14400, 5760, UNKNOWN), 842 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSPAP, 21000, 5760, UNKNOWN), 843 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_CDMA, UNKNOWN, UNKNOWN, UNKNOWN), 844 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_1xRTT, UNKNOWN, UNKNOWN, UNKNOWN), 845 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_0, 2468, 153, UNKNOWN), 846 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_A, 3072, 1800, UNKNOWN), 847 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_B, 14700, 1800, UNKNOWN), 848 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_IDEN, UNKNOWN, UNKNOWN, UNKNOWN), 849 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_LTE, 100000, 50000, UNKNOWN), 850 new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EHRPD, UNKNOWN, UNKNOWN, UNKNOWN), 851 }; 852 853 private static NetworkDataEntry getNetworkDataEntry(int networkType) { 854 for (NetworkDataEntry entry : mTheoreticalBWTable) { 855 if (entry.networkType == networkType) { 856 return entry; 857 } 858 } 859 860 Slog.e(TAG, "Could not find Theoretical BW entry for " + String.valueOf(networkType)); 861 return null; 862 } 863 864 private static int getNormalizedSignalStrength(int networkType, SignalStrength ss) { 865 866 int level; 867 868 switch(networkType) { 869 case TelephonyManager.NETWORK_TYPE_EDGE: 870 case TelephonyManager.NETWORK_TYPE_GPRS: 871 case TelephonyManager.NETWORK_TYPE_UMTS: 872 case TelephonyManager.NETWORK_TYPE_HSDPA: 873 case TelephonyManager.NETWORK_TYPE_HSUPA: 874 case TelephonyManager.NETWORK_TYPE_HSPA: 875 case TelephonyManager.NETWORK_TYPE_HSPAP: 876 level = ss.getGsmLevel(); 877 break; 878 case TelephonyManager.NETWORK_TYPE_CDMA: 879 case TelephonyManager.NETWORK_TYPE_1xRTT: 880 level = ss.getCdmaLevel(); 881 break; 882 case TelephonyManager.NETWORK_TYPE_EVDO_0: 883 case TelephonyManager.NETWORK_TYPE_EVDO_A: 884 case TelephonyManager.NETWORK_TYPE_EVDO_B: 885 level = ss.getEvdoLevel(); 886 break; 887 case TelephonyManager.NETWORK_TYPE_LTE: 888 level = ss.getLteLevel(); 889 break; 890 case TelephonyManager.NETWORK_TYPE_IDEN: 891 case TelephonyManager.NETWORK_TYPE_EHRPD: 892 default: 893 return UNKNOWN; 894 } 895 896 return (level * LinkQualityInfo.NORMALIZED_SIGNAL_STRENGTH_RANGE) / 897 SignalStrength.NUM_SIGNAL_STRENGTH_BINS; 898 } 899 900 @Override 901 public void startSampling(SamplingDataTracker.SamplingSnapshot s) { 902 mSamplingDataTracker.startSampling(s); 903 } 904 905 @Override 906 public void stopSampling(SamplingDataTracker.SamplingSnapshot s) { 907 mSamplingDataTracker.stopSampling(s); 908 } 909 } 910