CdmaLteServiceStateTracker.java revision cbaa45bbf2cab852b6c9c3a887e9f803d4e857ea
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 = newSS.getOperatorNumeric(); 132 mcc = Integer.parseInt(operatorNumeric.substring(0,3)); 133 } catch (Exception e) { 134 try { 135 operatorNumeric = ss.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 newSS.setRilDataRadioTechnology(type); 192 int dataRegState = regCodeToServiceState(regState); 193 newSS.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 pollingContext = new int[1]; 207 pollingContext[0] = 0; 208 209 switch (cm.getRadioState()) { 210 case RADIO_UNAVAILABLE: 211 newSS.setStateOutOfService(); 212 newCellLoc.setStateInvalid(); 213 setSignalStrengthDefaultValues(); 214 mGotCountryCode = false; 215 216 pollStateDone(); 217 break; 218 219 case RADIO_OFF: 220 newSS.setStateOff(); 221 newCellLoc.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 pollingContext[0]++; 234 // RIL_REQUEST_OPERATOR is necessary for CDMA 235 cm.getOperator(obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, pollingContext)); 236 237 pollingContext[0]++; 238 // RIL_REQUEST_VOICE_REGISTRATION_STATE is necessary for CDMA 239 cm.getVoiceRegistrationState(obtainMessage(EVENT_POLL_STATE_REGISTRATION_CDMA, 240 pollingContext)); 241 242 pollingContext[0]++; 243 // RIL_REQUEST_DATA_REGISTRATION_STATE 244 cm.getDataRegistrationState(obtainMessage(EVENT_POLL_STATE_GPRS, 245 pollingContext)); 246 break; 247 } 248 } 249 250 @Override 251 protected void pollStateDone() { 252 log("pollStateDone: lte 1 ss=[" + ss + "] newSS=[" + newSS + "]"); 253 254 boolean hasRegistered = ss.getVoiceRegState() != ServiceState.STATE_IN_SERVICE 255 && newSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE; 256 257 boolean hasDeregistered = ss.getVoiceRegState() == ServiceState.STATE_IN_SERVICE 258 && newSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE; 259 260 boolean hasCdmaDataConnectionAttached = 261 ss.getDataRegState() != ServiceState.STATE_IN_SERVICE 262 && newSS.getDataRegState() == ServiceState.STATE_IN_SERVICE; 263 264 boolean hasCdmaDataConnectionDetached = 265 ss.getDataRegState() == ServiceState.STATE_IN_SERVICE 266 && newSS.getDataRegState() != ServiceState.STATE_IN_SERVICE; 267 268 boolean hasCdmaDataConnectionChanged = 269 ss.getDataRegState() != newSS.getDataRegState(); 270 271 boolean hasVoiceRadioTechnologyChanged = ss.getRilVoiceRadioTechnology() 272 != newSS.getRilVoiceRadioTechnology(); 273 274 boolean hasDataRadioTechnologyChanged = ss.getRilDataRadioTechnology() 275 != newSS.getRilDataRadioTechnology(); 276 277 boolean hasChanged = !newSS.equals(ss); 278 279 boolean hasRoamingOn = !ss.getRoaming() && newSS.getRoaming(); 280 281 boolean hasRoamingOff = ss.getRoaming() && !newSS.getRoaming(); 282 283 boolean hasLocationChanged = !newCellLoc.equals(cellLoc); 284 285 boolean has4gHandoff = 286 newSS.getDataRegState() == ServiceState.STATE_IN_SERVICE && 287 (((ss.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) && 288 (newSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD)) || 289 ((ss.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD) && 290 (newSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE))); 291 292 boolean hasMultiApnSupport = 293 (((newSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) || 294 (newSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD)) && 295 ((ss.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_LTE) && 296 (ss.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD))); 297 298 boolean hasLostMultiApnSupport = 299 ((newSS.getRilDataRadioTechnology() >= ServiceState.RIL_RADIO_TECHNOLOGY_IS95A) && 300 (newSS.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 (ss.getVoiceRegState() != newSS.getVoiceRegState() 321 || ss.getDataRegState() != newSS.getDataRegState()) { 322 EventLog.writeEvent(EventLogTags.CDMA_SERVICE_STATE_CHANGE, ss.getVoiceRegState(), 323 ss.getDataRegState(), newSS.getVoiceRegState(), newSS.getDataRegState()); 324 } 325 326 ServiceState tss; 327 tss = ss; 328 ss = newSS; 329 newSS = tss; 330 // clean slate for next time 331 newSS.setStateOutOfService(); 332 333 CdmaCellLocation tcl = cellLoc; 334 cellLoc = newCellLoc; 335 newCellLoc = tcl; 336 337 newSS.setStateOutOfService(); // clean slate for next time 338 339 if (hasVoiceRadioTechnologyChanged) { 340 phone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE, 341 ServiceState.rilRadioTechnologyToString(ss.getRilDataRadioTechnology())); 342 } 343 344 if (hasRegistered) { 345 mNetworkAttachedRegistrants.notifyRegistrants(); 346 } 347 348 if (hasChanged) { 349 if (phone.isEriFileLoaded()) { 350 String eriText; 351 // Now the CDMAPhone sees the new ServiceState so it can get the 352 // new ERI text 353 if (ss.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) { 354 eriText = phone.getCdmaEriText(); 355 } else if (ss.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 = phone.getContext() 366 .getText(com.android.internal.R.string.roamingTextSearching).toString(); 367 } 368 ss.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 = ss.getCdmaEriIconIndex(); 378 379 if (showSpn && (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) && 380 isInHomeSidNid(ss.getSystemId(), ss.getNetworkId()) && 381 mIccRecords != null) { 382 ss.setOperatorAlphaLong(mIccRecords.getServiceProviderName()); 383 } 384 } 385 386 String operatorNumeric; 387 388 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA, 389 ss.getOperatorAlphaLong()); 390 391 String prevOperatorNumeric = 392 SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, ""); 393 operatorNumeric = ss.getOperatorNumeric(); 394 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, operatorNumeric); 395 396 if (operatorNumeric == null) { 397 if (DBG) log("operatorNumeric is null"); 398 phone.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 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, 413 isoCountryCode); 414 mGotCountryCode = true; 415 416 if (shouldFixTimeZoneNow(phone, operatorNumeric, prevOperatorNumeric, 417 mNeedFixZone)) { 418 fixTimeZone(isoCountryCode); 419 } 420 } 421 422 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING, 423 ss.getRoaming() ? "true" : "false"); 424 425 updateSpnDisplay(); 426 phone.notifyServiceStateChanged(ss); 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 phone.notifyDataConnection(null); 440 } 441 442 if (hasRoamingOn) { 443 mRoamingOnRegistrants.notifyRegistrants(); 444 } 445 446 if (hasRoamingOff) { 447 mRoamingOffRegistrants.notifyRegistrants(); 448 } 449 450 if (hasLocationChanged) { 451 phone.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 = ss.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 (ss.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) { 482 isGsm = true; 483 } 484 boolean ssChanged = super.onSignalStrengthResult(ar, isGsm); 485 486 synchronized (mCellInfo) { 487 if (ss.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 (ss.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) { 506 return true; 507 } else { 508 return ss.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