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 onSubscriptionsChanged()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 CarrierIdentifier(Phone phone)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 handleMessage(Message msg)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 loadCarrierMatchingRulesOnMccMnc()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 getPreferApn()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 updateCarrierIdAndName(int cid, String name)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 makeCarrierMatchingRule(Cursor cursor)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 CarrierMatchingRule(String mccmnc, String imsiPrefixPattern, String iccidPrefix, String gid1, String gid2, String plmn, String spn, String apn, int cid, String name)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. match(CarrierMatchingRule subscriptionRule)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 imsiPrefixMatch(String imsi, String prefixXPattern)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 iccidPrefixMatch(String iccid, String prefix)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 toString()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 */ matchCarrier()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 getCarrierListVersion()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 getCarrierId()596 public int getCarrierId() { 597 return mCarrierId; 598 } 599 getCarrierName()600 public String getCarrierName() { 601 return mCarrierName; 602 } 603 equals(String a, String b, boolean ignoreCase)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 logd(String str)612 private static void logd(String str) { 613 Rlog.d(LOG_TAG, str); 614 } loge(String str)615 private static void loge(String str) { 616 Rlog.e(LOG_TAG, str); 617 } dump(FileDescriptor fd, PrintWriter pw, String[] args)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