1 /* 2 * Copyright 2017 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 package com.android.internal.telephony; 17 18 import static android.provider.Telephony.CarrierId; 19 20 import android.content.ContentValues; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.database.ContentObserver; 24 import android.database.Cursor; 25 import android.net.Uri; 26 import android.os.Handler; 27 import android.os.Message; 28 import android.provider.Telephony; 29 import android.telephony.Rlog; 30 import android.telephony.SubscriptionManager; 31 import android.telephony.TelephonyManager; 32 import android.text.TextUtils; 33 import android.util.LocalLog; 34 import android.util.Log; 35 36 import com.android.internal.telephony.metrics.TelephonyMetrics; 37 import com.android.internal.telephony.uicc.IccRecords; 38 import com.android.internal.telephony.uicc.UiccController; 39 import com.android.internal.telephony.uicc.UiccProfile; 40 import com.android.internal.util.IndentingPrintWriter; 41 42 import java.io.FileDescriptor; 43 import java.io.PrintWriter; 44 import java.util.ArrayList; 45 import java.util.List; 46 import java.util.concurrent.atomic.AtomicInteger; 47 48 /** 49 * CarrierIdentifier identifies the subscription carrier and returns a canonical carrier Id 50 * and a user friendly carrier name. CarrierIdentifier reads subscription info and check against 51 * all carrier matching rules stored in CarrierIdProvider. It is msim aware, each phone has a 52 * dedicated CarrierIdentifier. 53 */ 54 public class CarrierIdentifier extends Handler { 55 private static final String LOG_TAG = CarrierIdentifier.class.getSimpleName(); 56 private static final boolean DBG = true; 57 private static final boolean VDBG = Rlog.isLoggable(LOG_TAG, Log.VERBOSE); 58 59 // events to trigger carrier identification 60 private static final int SIM_LOAD_EVENT = 1; 61 private static final int SIM_ABSENT_EVENT = 2; 62 private static final int SPN_OVERRIDE_EVENT = 3; 63 private static final int ICC_CHANGED_EVENT = 4; 64 private static final int PREFER_APN_UPDATE_EVENT = 5; 65 private static final int CARRIER_ID_DB_UPDATE_EVENT = 6; 66 67 private static final Uri CONTENT_URL_PREFER_APN = Uri.withAppendedPath( 68 Telephony.Carriers.CONTENT_URI, "preferapn"); 69 private static final String OPERATOR_BRAND_OVERRIDE_PREFIX = "operator_branding_"; 70 71 // cached matching rules based mccmnc to speed up resolution 72 private List<CarrierMatchingRule> mCarrierMatchingRulesOnMccMnc = new ArrayList<>(); 73 // cached carrier Id 74 private int mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID; 75 // cached carrier name 76 private String mCarrierName; 77 // cached preferapn name 78 private String mPreferApn; 79 // cached service provider name. telephonyManager API returns empty string as default value. 80 // some carriers need to target devices with Empty SPN. In that case, carrier matching rule 81 // should specify "" spn explicitly. 82 private String mSpn = ""; 83 84 private Context mContext; 85 private Phone mPhone; 86 private IccRecords mIccRecords; 87 private UiccProfile mUiccProfile; 88 private final LocalLog mCarrierIdLocalLog = new LocalLog(20); 89 private final TelephonyManager mTelephonyMgr; 90 private final SubscriptionsChangedListener mOnSubscriptionsChangedListener = 91 new SubscriptionsChangedListener(); 92 93 private final ContentObserver mContentObserver = new ContentObserver(this) { 94 @Override 95 public void onChange(boolean selfChange, Uri uri) { 96 if (CONTENT_URL_PREFER_APN.equals(uri.getLastPathSegment())) { 97 logd("onChange URI: " + uri); 98 sendEmptyMessage(PREFER_APN_UPDATE_EVENT); 99 } else if (CarrierId.All.CONTENT_URI.equals(uri)) { 100 logd("onChange URI: " + uri); 101 sendEmptyMessage(CARRIER_ID_DB_UPDATE_EVENT); 102 } 103 } 104 }; 105 106 private class SubscriptionsChangedListener 107 extends SubscriptionManager.OnSubscriptionsChangedListener { 108 final AtomicInteger mPreviousSubId = 109 new AtomicInteger(SubscriptionManager.INVALID_SUBSCRIPTION_ID); 110 /** 111 * Callback invoked when there is any change to any SubscriptionInfo. Typically 112 * this method would invoke {@link SubscriptionManager#getActiveSubscriptionInfoList} 113 */ 114 @Override 115 public void onSubscriptionsChanged() { 116 int subId = mPhone.getSubId(); 117 if (mPreviousSubId.getAndSet(subId) != subId) { 118 if (DBG) { 119 logd("SubscriptionListener.onSubscriptionInfoChanged subId: " 120 + mPreviousSubId); 121 } 122 if (SubscriptionManager.isValidSubscriptionId(subId)) { 123 sendEmptyMessage(SIM_LOAD_EVENT); 124 } else { 125 sendEmptyMessage(SIM_ABSENT_EVENT); 126 } 127 } 128 } 129 } 130 131 public CarrierIdentifier(Phone phone) { 132 logd("Creating CarrierIdentifier[" + phone.getPhoneId() + "]"); 133 mContext = phone.getContext(); 134 mPhone = phone; 135 mTelephonyMgr = TelephonyManager.from(mContext); 136 137 // register events 138 mContext.getContentResolver().registerContentObserver(CONTENT_URL_PREFER_APN, false, 139 mContentObserver); 140 mContext.getContentResolver().registerContentObserver( 141 CarrierId.All.CONTENT_URI, false, mContentObserver); 142 SubscriptionManager.from(mContext).addOnSubscriptionsChangedListener( 143 mOnSubscriptionsChangedListener); 144 UiccController.getInstance().registerForIccChanged(this, ICC_CHANGED_EVENT, null); 145 } 146 147 /** 148 * Entry point for the carrier identification. 149 * 150 * 1. SIM_LOAD_EVENT 151 * This indicates that all SIM records has been loaded and its first entry point for the 152 * carrier identification. Note, there are other attributes could be changed on the fly 153 * like APN and SPN. We cached all carrier matching rules based on MCCMNC to speed 154 * up carrier resolution on following trigger events. 155 * 156 * 2. PREFER_APN_UPDATE_EVENT 157 * This indicates prefer apn has been changed. It could be triggered when user modified 158 * APN settings or when default data connection first establishes on the current carrier. 159 * We follow up on this by querying prefer apn sqlite and re-issue carrier identification 160 * with the updated prefer apn name. 161 * 162 * 3. SPN_OVERRIDE_EVENT 163 * This indicates that SPN value as been changed. It could be triggered from EF_SPN 164 * record loading, carrier config override 165 * {@link android.telephony.CarrierConfigManager#KEY_CARRIER_NAME_STRING} 166 * or carrier app override {@link TelephonyManager#setOperatorBrandOverride(String)}. 167 * we follow up this by checking the cached mSPN against the latest value and issue 168 * carrier identification only if spn changes. 169 * 170 * 4. CARRIER_ID_DB_UPDATE_EVENT 171 * This indicates that carrierIdentification database which stores all matching rules 172 * has been updated. It could be triggered from OTA or assets update. 173 */ 174 @Override 175 public void handleMessage(Message msg) { 176 if (VDBG) logd("handleMessage: " + msg.what); 177 switch (msg.what) { 178 case SIM_LOAD_EVENT: 179 case CARRIER_ID_DB_UPDATE_EVENT: 180 mSpn = mTelephonyMgr.getSimOperatorNameForPhone(mPhone.getPhoneId()); 181 mPreferApn = getPreferApn(); 182 loadCarrierMatchingRulesOnMccMnc(); 183 break; 184 case SIM_ABSENT_EVENT: 185 mCarrierMatchingRulesOnMccMnc.clear(); 186 mSpn = null; 187 mPreferApn = null; 188 updateCarrierIdAndName(TelephonyManager.UNKNOWN_CARRIER_ID, null); 189 break; 190 case PREFER_APN_UPDATE_EVENT: 191 String preferApn = getPreferApn(); 192 if (!equals(mPreferApn, preferApn, true)) { 193 logd("[updatePreferApn] from:" + mPreferApn + " to:" + preferApn); 194 mPreferApn = preferApn; 195 matchCarrier(); 196 } 197 break; 198 case SPN_OVERRIDE_EVENT: 199 String spn = mTelephonyMgr.getSimOperatorNameForPhone(mPhone.getPhoneId()); 200 if (!equals(mSpn, spn, true)) { 201 logd("[updateSpn] from:" + mSpn + " to:" + spn); 202 mSpn = spn; 203 matchCarrier(); 204 } 205 break; 206 case ICC_CHANGED_EVENT: 207 // all records used for carrier identification are from SimRecord 208 final IccRecords newIccRecords = UiccController.getInstance().getIccRecords( 209 mPhone.getPhoneId(), UiccController.APP_FAM_3GPP); 210 if (mIccRecords != newIccRecords) { 211 if (mIccRecords != null) { 212 logd("Removing stale icc objects."); 213 mIccRecords.unregisterForRecordsLoaded(this); 214 mIccRecords.unregisterForRecordsOverride(this); 215 mIccRecords = null; 216 } 217 if (newIccRecords != null) { 218 logd("new Icc object"); 219 newIccRecords.registerForRecordsLoaded(this, SIM_LOAD_EVENT, null); 220 newIccRecords.registerForRecordsOverride(this, SIM_LOAD_EVENT, null); 221 mIccRecords = newIccRecords; 222 } 223 } 224 // check UICC profile 225 final UiccProfile uiccProfile = UiccController.getInstance() 226 .getUiccProfileForPhone(mPhone.getPhoneId()); 227 if (mUiccProfile != uiccProfile) { 228 if (mUiccProfile != null) { 229 logd("unregister operatorBrandOverride"); 230 mUiccProfile.unregisterForOperatorBrandOverride(this); 231 mUiccProfile = null; 232 } 233 if (uiccProfile != null) { 234 logd("register operatorBrandOverride"); 235 uiccProfile.registerForOpertorBrandOverride(this, SPN_OVERRIDE_EVENT, null); 236 mUiccProfile = uiccProfile; 237 } 238 } 239 break; 240 default: 241 loge("invalid msg: " + msg.what); 242 break; 243 } 244 } 245 246 private void loadCarrierMatchingRulesOnMccMnc() { 247 try { 248 String mccmnc = mTelephonyMgr.getSimOperatorNumericForPhone(mPhone.getPhoneId()); 249 Cursor cursor = mContext.getContentResolver().query( 250 CarrierId.All.CONTENT_URI, 251 /* projection */ null, 252 /* selection */ CarrierId.All.MCCMNC + "=?", 253 /* selectionArgs */ new String[]{mccmnc}, null); 254 try { 255 if (cursor != null) { 256 if (VDBG) { 257 logd("[loadCarrierMatchingRules]- " + cursor.getCount() 258 + " Records(s) in DB" + " mccmnc: " + mccmnc); 259 } 260 mCarrierMatchingRulesOnMccMnc.clear(); 261 while (cursor.moveToNext()) { 262 mCarrierMatchingRulesOnMccMnc.add(makeCarrierMatchingRule(cursor)); 263 } 264 matchCarrier(); 265 } 266 } finally { 267 if (cursor != null) { 268 cursor.close(); 269 } 270 } 271 } catch (Exception ex) { 272 loge("[loadCarrierMatchingRules]- ex: " + ex); 273 } 274 } 275 276 private String getPreferApn() { 277 Cursor cursor = mContext.getContentResolver().query( 278 Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "preferapn/subId/" 279 + mPhone.getSubId()), /* projection */ new String[]{Telephony.Carriers.APN}, 280 /* selection */ null, /* selectionArgs */ null, /* sortOrder */ null); 281 try { 282 if (cursor != null) { 283 if (VDBG) { 284 logd("[getPreferApn]- " + cursor.getCount() + " Records(s) in DB"); 285 } 286 while (cursor.moveToNext()) { 287 String apn = cursor.getString(cursor.getColumnIndexOrThrow( 288 Telephony.Carriers.APN)); 289 logd("[getPreferApn]- " + apn); 290 return apn; 291 } 292 } 293 } catch (Exception ex) { 294 loge("[getPreferApn]- exception: " + ex); 295 } finally { 296 if (cursor != null) { 297 cursor.close(); 298 } 299 } 300 return null; 301 } 302 303 private void updateCarrierIdAndName(int cid, String name) { 304 boolean update = false; 305 if (!equals(name, mCarrierName, true)) { 306 logd("[updateCarrierName] from:" + mCarrierName + " to:" + name); 307 mCarrierName = name; 308 update = true; 309 } 310 if (cid != mCarrierId) { 311 logd("[updateCarrierId] from:" + mCarrierId + " to:" + cid); 312 mCarrierId = cid; 313 update = true; 314 } 315 if (update) { 316 mCarrierIdLocalLog.log("[updateCarrierIdAndName] cid:" + mCarrierId + " name:" 317 + mCarrierName); 318 final Intent intent = new Intent(TelephonyManager 319 .ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED); 320 intent.putExtra(TelephonyManager.EXTRA_CARRIER_ID, mCarrierId); 321 intent.putExtra(TelephonyManager.EXTRA_CARRIER_NAME, mCarrierName); 322 intent.putExtra(TelephonyManager.EXTRA_SUBSCRIPTION_ID, mPhone.getSubId()); 323 mContext.sendBroadcast(intent); 324 325 // update current subscriptions 326 ContentValues cv = new ContentValues(); 327 cv.put(CarrierId.CARRIER_ID, mCarrierId); 328 cv.put(CarrierId.CARRIER_NAME, mCarrierName); 329 mContext.getContentResolver().update( 330 Uri.withAppendedPath(CarrierId.CONTENT_URI, 331 Integer.toString(mPhone.getSubId())), cv, null, null); 332 } 333 } 334 335 private CarrierMatchingRule makeCarrierMatchingRule(Cursor cursor) { 336 return new CarrierMatchingRule( 337 cursor.getString(cursor.getColumnIndexOrThrow(CarrierId.All.MCCMNC)), 338 cursor.getString(cursor.getColumnIndexOrThrow( 339 CarrierId.All.IMSI_PREFIX_XPATTERN)), 340 cursor.getString(cursor.getColumnIndexOrThrow( 341 CarrierId.All.ICCID_PREFIX)), 342 cursor.getString(cursor.getColumnIndexOrThrow(CarrierId.All.GID1)), 343 cursor.getString(cursor.getColumnIndexOrThrow(CarrierId.All.GID2)), 344 cursor.getString(cursor.getColumnIndexOrThrow(CarrierId.All.PLMN)), 345 cursor.getString(cursor.getColumnIndexOrThrow(CarrierId.All.SPN)), 346 cursor.getString(cursor.getColumnIndexOrThrow(CarrierId.All.APN)), 347 cursor.getInt(cursor.getColumnIndexOrThrow(CarrierId.CARRIER_ID)), 348 cursor.getString(cursor.getColumnIndexOrThrow(CarrierId.CARRIER_NAME))); 349 } 350 351 /** 352 * carrier matching attributes with corresponding cid 353 */ 354 private static class CarrierMatchingRule { 355 /** 356 * These scores provide the hierarchical relationship between the attributes, intended to 357 * resolve conflicts in a deterministic way. The scores are constructed such that a match 358 * from a higher tier will beat any subsequent match which does not match at that tier, 359 * so MCCMNC beats everything else. This avoids problems when two (or more) carriers rule 360 * matches as the score helps to find the best match uniquely. e.g., 361 * rule 1 {mccmnc, imsi} rule 2 {mccmnc, imsi, gid1} and rule 3 {mccmnc, imsi, gid2} all 362 * matches with subscription data. rule 2 wins with the highest matching score. 363 */ 364 private static final int SCORE_MCCMNC = 1 << 7; 365 private static final int SCORE_IMSI_PREFIX = 1 << 6; 366 private static final int SCORE_ICCID_PREFIX = 1 << 5; 367 private static final int SCORE_GID1 = 1 << 4; 368 private static final int SCORE_GID2 = 1 << 3; 369 private static final int SCORE_PLMN = 1 << 2; 370 private static final int SCORE_SPN = 1 << 1; 371 private static final int SCORE_APN = 1 << 0; 372 373 private static final int SCORE_INVALID = -1; 374 375 // carrier matching attributes 376 private String mMccMnc; 377 private String mImsiPrefixPattern; 378 private String mIccidPrefix; 379 private String mGid1; 380 private String mGid2; 381 private String mPlmn; 382 private String mSpn; 383 private String mApn; 384 385 // user-facing carrier name 386 private String mName; 387 // unique carrier id 388 private int mCid; 389 390 private int mScore = 0; 391 392 CarrierMatchingRule(String mccmnc, String imsiPrefixPattern, String iccidPrefix, 393 String gid1, String gid2, String plmn, String spn, String apn, int cid, 394 String name) { 395 mMccMnc = mccmnc; 396 mImsiPrefixPattern = imsiPrefixPattern; 397 mIccidPrefix = iccidPrefix; 398 mGid1 = gid1; 399 mGid2 = gid2; 400 mPlmn = plmn; 401 mSpn = spn; 402 mApn = apn; 403 mCid = cid; 404 mName = name; 405 } 406 407 // Calculate matching score. Values which aren't set in the rule are considered "wild". 408 // All values in the rule must match in order for the subscription to be considered part of 409 // the carrier. Otherwise, a invalid score -1 will be assigned. A match from a higher tier 410 // will beat any subsequent match which does not match at that tier. When there are multiple 411 // matches at the same tier, the match with highest score will be used. 412 public void match(CarrierMatchingRule subscriptionRule) { 413 mScore = 0; 414 if (mMccMnc != null) { 415 if (!CarrierIdentifier.equals(subscriptionRule.mMccMnc, mMccMnc, false)) { 416 mScore = SCORE_INVALID; 417 return; 418 } 419 mScore += SCORE_MCCMNC; 420 } 421 if (mImsiPrefixPattern != null) { 422 if (!imsiPrefixMatch(subscriptionRule.mImsiPrefixPattern, mImsiPrefixPattern)) { 423 mScore = SCORE_INVALID; 424 return; 425 } 426 mScore += SCORE_IMSI_PREFIX; 427 } 428 if (mIccidPrefix != null) { 429 if (!iccidPrefixMatch(subscriptionRule.mIccidPrefix, mIccidPrefix)) { 430 mScore = SCORE_INVALID; 431 return; 432 } 433 mScore += SCORE_ICCID_PREFIX; 434 } 435 if (mGid1 != null) { 436 // full string match. carrier matching should cover the corner case that gid1 437 // with garbage tail due to SIM manufacture issues. 438 if (!CarrierIdentifier.equals(subscriptionRule.mGid1, mGid1, true)) { 439 mScore = SCORE_INVALID; 440 return; 441 } 442 mScore += SCORE_GID1; 443 } 444 if (mGid2 != null) { 445 // full string match. carrier matching should cover the corner case that gid2 446 // with garbage tail due to SIM manufacture issues. 447 if (!CarrierIdentifier.equals(subscriptionRule.mGid2, mGid2, true)) { 448 mScore = SCORE_INVALID; 449 return; 450 } 451 mScore += SCORE_GID2; 452 } 453 if (mPlmn != null) { 454 if (!CarrierIdentifier.equals(subscriptionRule.mPlmn, mPlmn, true)) { 455 mScore = SCORE_INVALID; 456 return; 457 } 458 mScore += SCORE_PLMN; 459 } 460 if (mSpn != null) { 461 if (!CarrierIdentifier.equals(subscriptionRule.mSpn, mSpn, true)) { 462 mScore = SCORE_INVALID; 463 return; 464 } 465 mScore += SCORE_SPN; 466 } 467 if (mApn != null) { 468 if (!CarrierIdentifier.equals(subscriptionRule.mApn, mApn, true)) { 469 mScore = SCORE_INVALID; 470 return; 471 } 472 mScore += SCORE_APN; 473 } 474 } 475 476 private boolean imsiPrefixMatch(String imsi, String prefixXPattern) { 477 if (TextUtils.isEmpty(prefixXPattern)) return true; 478 if (TextUtils.isEmpty(imsi)) return false; 479 if (imsi.length() < prefixXPattern.length()) { 480 return false; 481 } 482 for (int i = 0; i < prefixXPattern.length(); i++) { 483 if ((prefixXPattern.charAt(i) != 'x') && (prefixXPattern.charAt(i) != 'X') 484 && (prefixXPattern.charAt(i) != imsi.charAt(i))) { 485 return false; 486 } 487 } 488 return true; 489 } 490 491 private boolean iccidPrefixMatch(String iccid, String prefix) { 492 if (iccid == null || prefix == null) { 493 return false; 494 } 495 return iccid.startsWith(prefix); 496 } 497 498 public String toString() { 499 return "[CarrierMatchingRule] -" 500 + " mccmnc: " + mMccMnc 501 + " gid1: " + mGid1 502 + " gid2: " + mGid2 503 + " plmn: " + mPlmn 504 + " imsi_prefix: " + mImsiPrefixPattern 505 + " iccid_prefix" + mIccidPrefix 506 + " spn: " + mSpn 507 + " apn: " + mApn 508 + " name: " + mName 509 + " cid: " + mCid 510 + " score: " + mScore; 511 } 512 } 513 514 /** 515 * find the best matching carrier from candidates with matched MCCMNC and notify 516 * all interested parties on carrier id change. 517 */ 518 private void matchCarrier() { 519 if (!SubscriptionManager.isValidSubscriptionId(mPhone.getSubId())) { 520 logd("[matchCarrier]" + "skip before sim records loaded"); 521 return; 522 } 523 final String mccmnc = mTelephonyMgr.getSimOperatorNumericForPhone(mPhone.getPhoneId()); 524 final String iccid = mPhone.getIccSerialNumber(); 525 final String gid1 = mPhone.getGroupIdLevel1(); 526 final String gid2 = mPhone.getGroupIdLevel2(); 527 final String imsi = mPhone.getSubscriberId(); 528 final String plmn = mPhone.getPlmn(); 529 final String spn = mSpn; 530 final String apn = mPreferApn; 531 532 if (VDBG) { 533 logd("[matchCarrier]" 534 + " mnnmnc:" + mccmnc 535 + " gid1: " + gid1 536 + " gid2: " + gid2 537 + " imsi: " + Rlog.pii(LOG_TAG, imsi) 538 + " iccid: " + Rlog.pii(LOG_TAG, iccid) 539 + " plmn: " + plmn 540 + " spn: " + spn 541 + " apn: " + apn); 542 } 543 544 CarrierMatchingRule subscriptionRule = new CarrierMatchingRule( 545 mccmnc, imsi, iccid, gid1, gid2, plmn, spn, apn, 546 TelephonyManager.UNKNOWN_CARRIER_ID, null); 547 548 int maxScore = CarrierMatchingRule.SCORE_INVALID; 549 CarrierMatchingRule maxRule = null; 550 551 for (CarrierMatchingRule rule : mCarrierMatchingRulesOnMccMnc) { 552 rule.match(subscriptionRule); 553 if (rule.mScore > maxScore) { 554 maxScore = rule.mScore; 555 maxRule = rule; 556 } 557 } 558 559 if (maxScore == CarrierMatchingRule.SCORE_INVALID) { 560 logd("[matchCarrier - no match] cid: " + TelephonyManager.UNKNOWN_CARRIER_ID 561 + " name: " + null); 562 updateCarrierIdAndName(TelephonyManager.UNKNOWN_CARRIER_ID, null); 563 } else { 564 logd("[matchCarrier] cid: " + maxRule.mCid + " name: " + maxRule.mName); 565 updateCarrierIdAndName(maxRule.mCid, maxRule.mName); 566 } 567 568 /* 569 * Write Carrier Identification Matching event, logging with the 570 * carrierId, mccmnc, gid1 and carrier list version to differentiate below cases of metrics: 571 * 1) unknown mccmnc - the Carrier Id provider contains no rule that matches the 572 * read mccmnc. 573 * 2) the Carrier Id provider contains some rule(s) that match the read mccmnc, 574 * but the read gid1 is not matched within the highest-scored rule. 575 * 3) successfully found a matched carrier id in the provider. 576 * 4) use carrier list version to compare the unknown carrier ratio between each version. 577 */ 578 String unknownGid1ToLog = ((maxScore & CarrierMatchingRule.SCORE_GID1) == 0 579 && !TextUtils.isEmpty(subscriptionRule.mGid1)) ? subscriptionRule.mGid1 : null; 580 String unknownMccmncToLog = ((maxScore == CarrierMatchingRule.SCORE_INVALID 581 || (maxScore & CarrierMatchingRule.SCORE_GID1) == 0) 582 && !TextUtils.isEmpty(subscriptionRule.mMccMnc)) ? subscriptionRule.mMccMnc : null; 583 TelephonyMetrics.getInstance().writeCarrierIdMatchingEvent( 584 mPhone.getPhoneId(), getCarrierListVersion(), mCarrierId, 585 unknownMccmncToLog, unknownGid1ToLog); 586 } 587 588 public int getCarrierListVersion() { 589 final Cursor cursor = mContext.getContentResolver().query( 590 Uri.withAppendedPath(CarrierId.All.CONTENT_URI, 591 "get_version"), null, null, null); 592 cursor.moveToFirst(); 593 return cursor.getInt(0); 594 } 595 596 public int getCarrierId() { 597 return mCarrierId; 598 } 599 600 public String getCarrierName() { 601 return mCarrierName; 602 } 603 604 private static boolean equals(String a, String b, boolean ignoreCase) { 605 if (a == null && b == null) return true; 606 if (a != null && b != null) { 607 return (ignoreCase) ? a.equalsIgnoreCase(b) : a.equals(b); 608 } 609 return false; 610 } 611 612 private static void logd(String str) { 613 Rlog.d(LOG_TAG, str); 614 } 615 private static void loge(String str) { 616 Rlog.e(LOG_TAG, str); 617 } 618 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 619 final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); 620 ipw.println("mCarrierIdLocalLogs:"); 621 ipw.increaseIndent(); 622 mCarrierIdLocalLog.dump(fd, pw, args); 623 ipw.decreaseIndent(); 624 625 ipw.println("mCarrierId: " + mCarrierId); 626 ipw.println("mCarrierName: " + mCarrierName); 627 ipw.println("version: " + getCarrierListVersion()); 628 629 ipw.println("mCarrierMatchingRules on mccmnc: " 630 + mTelephonyMgr.getSimOperatorNumericForPhone(mPhone.getPhoneId())); 631 ipw.increaseIndent(); 632 for (CarrierMatchingRule rule : mCarrierMatchingRulesOnMccMnc) { 633 ipw.println(rule.toString()); 634 } 635 ipw.decreaseIndent(); 636 637 ipw.println("mSpn: " + mSpn); 638 ipw.println("mPreferApn: " + mPreferApn); 639 ipw.flush(); 640 } 641 } 642