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