CdmaLteServiceStateTracker.java revision f1b97fcff40f829cafd2fa643e8e4b788e504614
1/* 2 * Copyright (C) 2012 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 com.android.internal.telephony.cdma; 18 19import com.android.internal.telephony.TelephonyProperties; 20import com.android.internal.telephony.MccTable; 21import com.android.internal.telephony.EventLogTags; 22import com.android.internal.telephony.uicc.RuimRecords; 23import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState; 24 25import android.telephony.CellInfo; 26import android.telephony.CellInfoLte; 27import android.telephony.CellSignalStrengthLte; 28import android.telephony.CellIdentityLte; 29import android.telephony.SignalStrength; 30import android.telephony.ServiceState; 31import android.telephony.cdma.CdmaCellLocation; 32import android.text.TextUtils; 33import android.os.AsyncResult; 34import android.os.Message; 35import android.os.SystemClock; 36import android.os.SystemProperties; 37 38import android.telephony.Rlog; 39import android.util.EventLog; 40 41import java.io.FileDescriptor; 42import java.io.PrintWriter; 43import java.util.ArrayList; 44import java.util.List; 45 46public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { 47 private CDMALTEPhone mCdmaLtePhone; 48 private final CellInfoLte mCellInfoLte; 49 50 private CellIdentityLte mNewCellIdentityLte = new CellIdentityLte(); 51 private CellIdentityLte mLasteCellIdentityLte = new CellIdentityLte(); 52 53 public CdmaLteServiceStateTracker(CDMALTEPhone phone) { 54 super(phone, new CellInfoLte()); 55 mCdmaLtePhone = phone; 56 mCellInfoLte = (CellInfoLte) mCellInfo; 57 58 ((CellInfoLte)mCellInfo).setCellSignalStrength(new CellSignalStrengthLte()); 59 ((CellInfoLte)mCellInfo).setCellIdentity(new CellIdentityLte()); 60 61 if (DBG) log("CdmaLteServiceStateTracker Constructors"); 62 } 63 64 @Override 65 public void handleMessage(Message msg) { 66 AsyncResult ar; 67 int[] ints; 68 String[] strings; 69 switch (msg.what) { 70 case EVENT_POLL_STATE_GPRS: 71 if (DBG) log("handleMessage EVENT_POLL_STATE_GPRS"); 72 ar = (AsyncResult)msg.obj; 73 handlePollStateResult(msg.what, ar); 74 break; 75 case EVENT_RUIM_RECORDS_LOADED: 76 RuimRecords ruim = (RuimRecords)mIccRecords; 77 if ((ruim != null) && ruim.isProvisioned()) { 78 mMdn = ruim.getMdn(); 79 mMin = ruim.getMin(); 80 parseSidNid(ruim.getSid(), ruim.getNid()); 81 mPrlVersion = ruim.getPrlVersion(); 82 mIsMinInfoReady = true; 83 updateOtaspState(); 84 } 85 // SID/NID/PRL is loaded. Poll service state 86 // again to update to the roaming state with 87 // the latest variables. 88 pollState(); 89 break; 90 default: 91 super.handleMessage(msg); 92 } 93 } 94 95 /** 96 * Handle the result of one of the pollState()-related requests 97 */ 98 @Override 99 protected void handlePollStateResultMessage(int what, AsyncResult ar) { 100 if (what == EVENT_POLL_STATE_GPRS) { 101 String states[] = (String[])ar.result; 102 if (DBG) { 103 log("handlePollStateResultMessage: EVENT_POLL_STATE_GPRS states.length=" + 104 states.length + " states=" + states); 105 } 106 107 int type = 0; 108 int regState = -1; 109 if (states.length > 0) { 110 try { 111 regState = Integer.parseInt(states[0]); 112 113 // states[3] (if present) is the current radio technology 114 if (states.length >= 4 && states[3] != null) { 115 type = Integer.parseInt(states[3]); 116 } 117 } catch (NumberFormatException ex) { 118 loge("handlePollStateResultMessage: error parsing GprsRegistrationState: " 119 + ex); 120 } 121 if (states.length >= 10) { 122 int mcc; 123 int mnc; 124 int tac; 125 int pci; 126 int eci; 127 int csgid; 128 String operatorNumeric = null; 129 130 try { 131 operatorNumeric = mNewSS.getOperatorNumeric(); 132 mcc = Integer.parseInt(operatorNumeric.substring(0,3)); 133 } catch (Exception e) { 134 try { 135 operatorNumeric = mSS.getOperatorNumeric(); 136 mcc = Integer.parseInt(operatorNumeric.substring(0,3)); 137 } catch (Exception ex) { 138 loge("handlePollStateResultMessage: bad mcc operatorNumeric=" + 139 operatorNumeric + " ex=" + ex); 140 operatorNumeric = ""; 141 mcc = Integer.MAX_VALUE; 142 } 143 } 144 try { 145 mnc = Integer.parseInt(operatorNumeric.substring(3)); 146 } catch (Exception e) { 147 loge("handlePollStateResultMessage: bad mnc operatorNumeric=" + 148 operatorNumeric + " e=" + e); 149 mnc = Integer.MAX_VALUE; 150 } 151 152 // Use Integer#decode to be generous in what we receive and allow 153 // decimal, hex or octal values. 154 try { 155 tac = Integer.decode(states[6]); 156 } catch (Exception e) { 157 loge("handlePollStateResultMessage: bad tac states[6]=" + 158 states[6] + " e=" + e); 159 tac = Integer.MAX_VALUE; 160 } 161 try { 162 pci = Integer.decode(states[7]); 163 } catch (Exception e) { 164 loge("handlePollStateResultMessage: bad pci states[7]=" + 165 states[7] + " e=" + e); 166 pci = Integer.MAX_VALUE; 167 } 168 try { 169 eci = Integer.decode(states[8]); 170 } catch (Exception e) { 171 loge("handlePollStateResultMessage: bad eci states[8]=" + 172 states[8] + " e=" + e); 173 eci = Integer.MAX_VALUE; 174 } 175 try { 176 csgid = Integer.decode(states[9]); 177 } catch (Exception e) { 178 // FIX: Always bad so don't pollute the logs 179 // loge("handlePollStateResultMessage: bad csgid states[9]=" + 180 // states[9] + " e=" + e); 181 csgid = Integer.MAX_VALUE; 182 } 183 mNewCellIdentityLte = new CellIdentityLte(mcc, mnc, eci, pci, tac); 184 if (DBG) { 185 log("handlePollStateResultMessage: mNewLteCellIdentity=" + 186 mNewCellIdentityLte); 187 } 188 } 189 } 190 191 mNewSS.setRilDataRadioTechnology(type); 192 int dataRegState = regCodeToServiceState(regState); 193 mNewSS.setDataRegState(dataRegState); 194 if (DBG) { 195 log("handlPollStateResultMessage: CdmaLteSST setDataRegState=" + dataRegState 196 + " regState=" + regState 197 + " dataRadioTechnology=" + type); 198 } 199 } else { 200 super.handlePollStateResultMessage(what, ar); 201 } 202 } 203 204 @Override 205 protected void pollState() { 206 mPollingContext = new int[1]; 207 mPollingContext[0] = 0; 208 209 switch (mCi.getRadioState()) { 210 case RADIO_UNAVAILABLE: 211 mNewSS.setStateOutOfService(); 212 mNewCellLoc.setStateInvalid(); 213 setSignalStrengthDefaultValues(); 214 mGotCountryCode = false; 215 216 pollStateDone(); 217 break; 218 219 case RADIO_OFF: 220 mNewSS.setStateOff(); 221 mNewCellLoc.setStateInvalid(); 222 setSignalStrengthDefaultValues(); 223 mGotCountryCode = false; 224 225 pollStateDone(); 226 break; 227 228 default: 229 // Issue all poll-related commands at once, then count 230 // down the responses which are allowed to arrive 231 // out-of-order. 232 233 mPollingContext[0]++; 234 // RIL_REQUEST_OPERATOR is necessary for CDMA 235 mCi.getOperator(obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, mPollingContext)); 236 237 mPollingContext[0]++; 238 // RIL_REQUEST_VOICE_REGISTRATION_STATE is necessary for CDMA 239 mCi.getVoiceRegistrationState(obtainMessage(EVENT_POLL_STATE_REGISTRATION_CDMA, 240 mPollingContext)); 241 242 mPollingContext[0]++; 243 // RIL_REQUEST_DATA_REGISTRATION_STATE 244 mCi.getDataRegistrationState(obtainMessage(EVENT_POLL_STATE_GPRS, 245 mPollingContext)); 246 break; 247 } 248 } 249 250 @Override 251 protected void pollStateDone() { 252 log("pollStateDone: lte 1 ss=[" + mSS + "] newSS=[" + mNewSS + "]"); 253 254 boolean hasRegistered = mSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE 255 && mNewSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE; 256 257 boolean hasDeregistered = mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE 258 && mNewSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE; 259 260 boolean hasCdmaDataConnectionAttached = 261 mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE 262 && mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE; 263 264 boolean hasCdmaDataConnectionDetached = 265 mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE 266 && mNewSS.getDataRegState() != ServiceState.STATE_IN_SERVICE; 267 268 boolean hasCdmaDataConnectionChanged = 269 mSS.getDataRegState() != mNewSS.getDataRegState(); 270 271 boolean hasVoiceRadioTechnologyChanged = mSS.getRilVoiceRadioTechnology() 272 != mNewSS.getRilVoiceRadioTechnology(); 273 274 boolean hasDataRadioTechnologyChanged = mSS.getRilDataRadioTechnology() 275 != mNewSS.getRilDataRadioTechnology(); 276 277 boolean hasChanged = !mNewSS.equals(mSS); 278 279 boolean hasRoamingOn = !mSS.getRoaming() && mNewSS.getRoaming(); 280 281 boolean hasRoamingOff = mSS.getRoaming() && !mNewSS.getRoaming(); 282 283 boolean hasLocationChanged = !mNewCellLoc.equals(mCellLoc); 284 285 boolean has4gHandoff = 286 mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE && 287 (((mSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) && 288 (mNewSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD)) || 289 ((mSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD) && 290 (mNewSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE))); 291 292 boolean hasMultiApnSupport = 293 (((mNewSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) || 294 (mNewSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD)) && 295 ((mSS.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_LTE) && 296 (mSS.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD))); 297 298 boolean hasLostMultiApnSupport = 299 ((mNewSS.getRilDataRadioTechnology() >= ServiceState.RIL_RADIO_TECHNOLOGY_IS95A) && 300 (mNewSS.getRilDataRadioTechnology() <= ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A)); 301 302 if (DBG) { 303 log("pollStateDone:" 304 + " hasRegistered=" + hasRegistered 305 + " hasDeegistered=" + hasDeregistered 306 + " hasCdmaDataConnectionAttached=" + hasCdmaDataConnectionAttached 307 + " hasCdmaDataConnectionDetached=" + hasCdmaDataConnectionDetached 308 + " hasCdmaDataConnectionChanged=" + hasCdmaDataConnectionChanged 309 + " hasVoiceRadioTechnologyChanged= " + hasVoiceRadioTechnologyChanged 310 + " hasDataRadioTechnologyChanged=" + hasDataRadioTechnologyChanged 311 + " hasChanged=" + hasChanged 312 + " hasRoamingOn=" + hasRoamingOn 313 + " hasRoamingOff=" + hasRoamingOff 314 + " hasLocationChanged=" + hasLocationChanged 315 + " has4gHandoff = " + has4gHandoff 316 + " hasMultiApnSupport=" + hasMultiApnSupport 317 + " hasLostMultiApnSupport=" + hasLostMultiApnSupport); 318 } 319 // Add an event log when connection state changes 320 if (mSS.getVoiceRegState() != mNewSS.getVoiceRegState() 321 || mSS.getDataRegState() != mNewSS.getDataRegState()) { 322 EventLog.writeEvent(EventLogTags.CDMA_SERVICE_STATE_CHANGE, mSS.getVoiceRegState(), 323 mSS.getDataRegState(), mNewSS.getVoiceRegState(), mNewSS.getDataRegState()); 324 } 325 326 ServiceState tss; 327 tss = mSS; 328 mSS = mNewSS; 329 mNewSS = tss; 330 // clean slate for next time 331 mNewSS.setStateOutOfService(); 332 333 CdmaCellLocation tcl = mCellLoc; 334 mCellLoc = mNewCellLoc; 335 mNewCellLoc = tcl; 336 337 mNewSS.setStateOutOfService(); // clean slate for next time 338 339 if (hasVoiceRadioTechnologyChanged) { 340 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE, 341 ServiceState.rilRadioTechnologyToString(mSS.getRilDataRadioTechnology())); 342 } 343 344 if (hasRegistered) { 345 mNetworkAttachedRegistrants.notifyRegistrants(); 346 } 347 348 if (hasChanged) { 349 if (mPhone.isEriFileLoaded()) { 350 String eriText; 351 // Now the CDMAPhone sees the new ServiceState so it can get the 352 // new ERI text 353 if (mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) { 354 eriText = mPhone.getCdmaEriText(); 355 } else if (mSS.getVoiceRegState() == ServiceState.STATE_POWER_OFF) { 356 eriText = (mIccRecords != null) ? mIccRecords.getServiceProviderName() : null; 357 if (TextUtils.isEmpty(eriText)) { 358 // Sets operator alpha property by retrieving from 359 // build-time system property 360 eriText = SystemProperties.get("ro.cdma.home.operator.alpha"); 361 } 362 } else { 363 // Note that ServiceState.STATE_OUT_OF_SERVICE is valid used 364 // for mRegistrationState 0,2,3 and 4 365 eriText = mPhone.getContext() 366 .getText(com.android.internal.R.string.roamingTextSearching).toString(); 367 } 368 mSS.setOperatorAlphaLong(eriText); 369 } 370 371 if (mUiccApplcation != null && mUiccApplcation.getState() == AppState.APPSTATE_READY && 372 mIccRecords != null) { 373 // SIM is found on the device. If ERI roaming is OFF, and SID/NID matches 374 // one configured in SIM, use operator name from CSIM record. 375 boolean showSpn = 376 ((RuimRecords)mIccRecords).getCsimSpnDisplayCondition(); 377 int iconIndex = mSS.getCdmaEriIconIndex(); 378 379 if (showSpn && (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) && 380 isInHomeSidNid(mSS.getSystemId(), mSS.getNetworkId()) && 381 mIccRecords != null) { 382 mSS.setOperatorAlphaLong(mIccRecords.getServiceProviderName()); 383 } 384 } 385 386 String operatorNumeric; 387 388 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA, 389 mSS.getOperatorAlphaLong()); 390 391 String prevOperatorNumeric = 392 SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, ""); 393 operatorNumeric = mSS.getOperatorNumeric(); 394 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, operatorNumeric); 395 396 if (operatorNumeric == null) { 397 if (DBG) log("operatorNumeric is null"); 398 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, ""); 399 mGotCountryCode = false; 400 } else { 401 String isoCountryCode = ""; 402 String mcc = operatorNumeric.substring(0, 3); 403 try { 404 isoCountryCode = MccTable.countryCodeForMcc(Integer.parseInt(operatorNumeric 405 .substring(0, 3))); 406 } catch (NumberFormatException ex) { 407 loge("countryCodeForMcc error" + ex); 408 } catch (StringIndexOutOfBoundsException ex) { 409 loge("countryCodeForMcc error" + ex); 410 } 411 412 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, 413 isoCountryCode); 414 mGotCountryCode = true; 415 416 if (shouldFixTimeZoneNow(mPhone, operatorNumeric, prevOperatorNumeric, 417 mNeedFixZone)) { 418 fixTimeZone(isoCountryCode); 419 } 420 } 421 422 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING, 423 mSS.getRoaming() ? "true" : "false"); 424 425 updateSpnDisplay(); 426 mPhone.notifyServiceStateChanged(mSS); 427 } 428 429 if (hasCdmaDataConnectionAttached || has4gHandoff) { 430 mAttachedRegistrants.notifyRegistrants(); 431 } 432 433 if (hasCdmaDataConnectionDetached) { 434 mDetachedRegistrants.notifyRegistrants(); 435 } 436 437 if ((hasCdmaDataConnectionChanged || hasDataRadioTechnologyChanged)) { 438 log("pollStateDone: call notifyDataConnection"); 439 mPhone.notifyDataConnection(null); 440 } 441 442 if (hasRoamingOn) { 443 mRoamingOnRegistrants.notifyRegistrants(); 444 } 445 446 if (hasRoamingOff) { 447 mRoamingOffRegistrants.notifyRegistrants(); 448 } 449 450 if (hasLocationChanged) { 451 mPhone.notifyLocationChanged(); 452 } 453 454 ArrayList<CellInfo> arrayCi = new ArrayList<CellInfo>(); 455 synchronized(mCellInfo) { 456 CellInfoLte cil = (CellInfoLte)mCellInfo; 457 458 boolean cidChanged = ! mNewCellIdentityLte.equals(mLasteCellIdentityLte); 459 if (hasRegistered || hasDeregistered || cidChanged) { 460 // TODO: Handle the absence of LteCellIdentity 461 long timeStamp = SystemClock.elapsedRealtime() * 1000; 462 boolean registered = mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE; 463 mLasteCellIdentityLte = mNewCellIdentityLte; 464 465 cil.setRegisterd(registered); 466 cil.setCellIdentity(mLasteCellIdentityLte); 467 if (DBG) { 468 log("pollStateDone: hasRegistered=" + hasRegistered + 469 " hasDeregistered=" + hasDeregistered + 470 " cidChanged=" + cidChanged + 471 " mCellInfo=" + mCellInfo); 472 } 473 arrayCi.add(mCellInfo); 474 } 475 mPhoneBase.notifyCellInfo(arrayCi); 476 } 477 } 478 479 @Override 480 protected boolean onSignalStrengthResult(AsyncResult ar, boolean isGsm) { 481 if (mSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) { 482 isGsm = true; 483 } 484 boolean ssChanged = super.onSignalStrengthResult(ar, isGsm); 485 486 synchronized (mCellInfo) { 487 if (mSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) { 488 mCellInfoLte.setTimeStamp(SystemClock.elapsedRealtime() * 1000); 489 mCellInfoLte.setTimeStampType(CellInfo.TIMESTAMP_TYPE_JAVA_RIL); 490 mCellInfoLte.getCellSignalStrength() 491 .initialize(mSignalStrength,SignalStrength.INVALID); 492 } 493 if (mCellInfoLte.getCellIdentity() != null) { 494 ArrayList<CellInfo> arrayCi = new ArrayList<CellInfo>(); 495 arrayCi.add(mCellInfoLte); 496 mPhoneBase.notifyCellInfo(arrayCi); 497 } 498 } 499 return ssChanged; 500 } 501 502 @Override 503 public boolean isConcurrentVoiceAndDataAllowed() { 504 // For non-LTE, look at the CSS indicator to check on Concurrent V & D capability 505 if (mSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) { 506 return true; 507 } else { 508 return mSS.getCssIndicator() == 1; 509 } 510 } 511 512 /** 513 * Check whether the specified SID and NID pair appears in the HOME SID/NID list 514 * read from NV or SIM. 515 * 516 * @return true if provided sid/nid pair belongs to operator's home network. 517 */ 518 private boolean isInHomeSidNid(int sid, int nid) { 519 // if SID/NID is not available, assume this is home network. 520 if (isSidsAllZeros()) return true; 521 522 // length of SID/NID shold be same 523 if (mHomeSystemId.length != mHomeNetworkId.length) return true; 524 525 if (sid == 0) return true; 526 527 for (int i = 0; i < mHomeSystemId.length; i++) { 528 // Use SID only if NID is a reserved value. 529 // SID 0 and NID 0 and 65535 are reserved. (C.0005 2.6.5.2) 530 if ((mHomeSystemId[i] == sid) && 531 ((mHomeNetworkId[i] == 0) || (mHomeNetworkId[i] == 65535) || 532 (nid == 0) || (nid == 65535) || (mHomeNetworkId[i] == nid))) { 533 return true; 534 } 535 } 536 // SID/NID are not in the list. So device is not in home network 537 return false; 538 } 539 540 /** 541 * @return all available cell information, the returned List maybe empty but never null. 542 */ 543 @Override 544 public List<CellInfo> getAllCellInfo() { 545 ArrayList<CellInfo> arrayList = new ArrayList<CellInfo>(); 546 CellInfo ci; 547 synchronized(mCellInfo) { 548 arrayList.add(mCellInfoLte); 549 } 550 if (DBG) log ("getAllCellInfo: arrayList=" + arrayList); 551 return arrayList; 552 } 553 554 @Override 555 protected void log(String s) { 556 Rlog.d(LOG_TAG, "[CdmaLteSST] " + s); 557 } 558 559 @Override 560 protected void loge(String s) { 561 Rlog.e(LOG_TAG, "[CdmaLteSST] " + s); 562 } 563 564 @Override 565 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 566 pw.println("CdmaLteServiceStateTracker extends:"); 567 super.dump(fd, pw, args); 568 pw.println(" mCdmaLtePhone=" + mCdmaLtePhone); 569 } 570} 571