Home | History | Annotate | Download | only in telephony
      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