Loading proto/src/telephony.proto +34 −2 Original line number Diff line number Diff line Loading @@ -1573,11 +1573,43 @@ message TelephonyEvent { // Group id level 1. Logged only if gid1 is configured from subscription // but its matching rule is unknown optional string gid1 = 2; optional string unknown_gid1 = 2; // MCC and MNC that map to this carrier. Logged only if mccmnc is configured // from subscription but its matching rule is unknown optional string mccmnc = 3; optional string unknown_mccmnc = 3; // MCC and MNC from the subscription that map to this carrier. optional string mccmnc = 4; // Group id level 1 from the subscription that map to this carrier. optional string gid1 = 5; // Group id level 2 from the subscription that map to this carrier. optional string gid2 = 6; // spn from the subscription that map to this carrier. optional string spn = 7; // pnn from the subscription that map to this carrier. optional string pnn = 8; // iccid prefix from the subscription that map to this carrier. // only log first 7 outof 20 bit of full iccid optional string iccid_prefix = 9; // imsi prefix from the subscription that map to this carrier. // only log additional 2 bits other than MCC MNC. optional string imsi_prefix = 10; // Carrier Privilege Access Rule in hex string from the subscription. // Sample values: 61ed377e85d386a8dfee6b864bd85b0bfaa5af88 repeated string privilege_access_rule = 11; // The Access Point Name, corresponding to "apn" field returned by // "content://telephony/carriers/preferapn" on device. // Sample values: fast.t-mobile.com, internet. Note only log if this apn is not user edited. optional string preferApn = 12; } // Time when event happened on device, in milliseconds since epoch Loading src/java/com/android/internal/telephony/CarrierResolver.java +110 −62 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.text.TextUtils; import android.util.LocalLog; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.uicc.IccRecords; import com.android.internal.telephony.uicc.UiccController; Loading Loading @@ -362,6 +363,23 @@ public class CarrierResolver extends Handler { return null; } private boolean isPreferApnUserEdited(@NonNull String preferApn) { try (Cursor cursor = mContext.getContentResolver().query( Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "preferapn/subId/" + mPhone.getSubId()), /* projection */ new String[]{Telephony.Carriers.EDITED_STATUS}, /* selection */ Telephony.Carriers.APN + "=?", /* selectionArgs */ new String[]{preferApn}, /* sortOrder */ null) ) { if (cursor != null && cursor.moveToFirst()) { return cursor.getInt(cursor.getColumnIndexOrThrow( Telephony.Carriers.EDITED_STATUS)) == Telephony.Carriers.USER_EDITED; } } catch (Exception ex) { loge("[isPreferApnUserEdited]- exception: " + ex); } return false; } public void setTestOverrideApn(String apn) { logd("[setTestOverrideApn]: " + apn); mTestOverrideApn = apn; Loading Loading @@ -472,7 +490,7 @@ public class CarrierResolver extends Handler { /** * carrier matching attributes with corresponding cid */ private static class CarrierMatchingRule { public static class CarrierMatchingRule { /** * These scores provide the hierarchical relationship between the attributes, intended to * resolve conflicts in a deterministic way. The scores are constructed such that a match Loading @@ -495,16 +513,16 @@ public class CarrierResolver extends Handler { private static final int SCORE_INVALID = -1; // carrier matching attributes private final String mMccMnc; private final String mImsiPrefixPattern; private final String mIccidPrefix; private final String mGid1; private final String mGid2; private final String mPlmn; private final String mSpn; private final String mApn; public final String mccMnc; public final String imsiPrefixPattern; public final String iccidPrefix; public final String gid1; public final String gid2; public final String plmn; public final String spn; public final String apn; // there can be multiple certs configured in the UICC private final List<String> mPrivilegeAccessRule; public final List<String> privilegeAccessRule; // user-facing carrier name private String mName; Loading @@ -515,33 +533,34 @@ public class CarrierResolver extends Handler { private int mScore = 0; private CarrierMatchingRule(String mccmnc, String imsiPrefixPattern, String iccidPrefix, @VisibleForTesting public CarrierMatchingRule(String mccmnc, String imsiPrefixPattern, String iccidPrefix, String gid1, String gid2, String plmn, String spn, String apn, List<String> privilegeAccessRule, int cid, String name, int parentCid) { mMccMnc = mccmnc; mImsiPrefixPattern = imsiPrefixPattern; mIccidPrefix = iccidPrefix; mGid1 = gid1; mGid2 = gid2; mPlmn = plmn; mSpn = spn; mApn = apn; mPrivilegeAccessRule = privilegeAccessRule; mccMnc = mccmnc; this.imsiPrefixPattern = imsiPrefixPattern; this.iccidPrefix = iccidPrefix; this.gid1 = gid1; this.gid2 = gid2; this.plmn = plmn; this.spn = spn; this.apn = apn; this.privilegeAccessRule = privilegeAccessRule; mCid = cid; mName = name; mParentCid = parentCid; } private CarrierMatchingRule(CarrierMatchingRule rule) { mMccMnc = rule.mMccMnc; mImsiPrefixPattern = rule.mImsiPrefixPattern; mIccidPrefix = rule.mIccidPrefix; mGid1 = rule.mGid1; mGid2 = rule.mGid2; mPlmn = rule.mPlmn; mSpn = rule.mSpn; mApn = rule.mApn; mPrivilegeAccessRule = rule.mPrivilegeAccessRule; mccMnc = rule.mccMnc; imsiPrefixPattern = rule.imsiPrefixPattern; iccidPrefix = rule.iccidPrefix; gid1 = rule.gid1; gid2 = rule.gid2; plmn = rule.plmn; spn = rule.spn; apn = rule.apn; privilegeAccessRule = rule.privilegeAccessRule; mCid = rule.mCid; mName = rule.mName; mParentCid = rule.mParentCid; Loading @@ -554,67 +573,67 @@ public class CarrierResolver extends Handler { // matches at the same tier, the match with highest score will be used. public void match(CarrierMatchingRule subscriptionRule) { mScore = 0; if (mMccMnc != null) { if (!CarrierResolver.equals(subscriptionRule.mMccMnc, mMccMnc, false)) { if (mccMnc != null) { if (!CarrierResolver.equals(subscriptionRule.mccMnc, mccMnc, false)) { mScore = SCORE_INVALID; return; } mScore += SCORE_MCCMNC; } if (mImsiPrefixPattern != null) { if (!imsiPrefixMatch(subscriptionRule.mImsiPrefixPattern, mImsiPrefixPattern)) { if (imsiPrefixPattern != null) { if (!imsiPrefixMatch(subscriptionRule.imsiPrefixPattern, imsiPrefixPattern)) { mScore = SCORE_INVALID; return; } mScore += SCORE_IMSI_PREFIX; } if (mIccidPrefix != null) { if (!iccidPrefixMatch(subscriptionRule.mIccidPrefix, mIccidPrefix)) { if (iccidPrefix != null) { if (!iccidPrefixMatch(subscriptionRule.iccidPrefix, iccidPrefix)) { mScore = SCORE_INVALID; return; } mScore += SCORE_ICCID_PREFIX; } if (mGid1 != null) { if (!gidMatch(subscriptionRule.mGid1, mGid1)) { if (gid1 != null) { if (!gidMatch(subscriptionRule.gid1, gid1)) { mScore = SCORE_INVALID; return; } mScore += SCORE_GID1; } if (mGid2 != null) { if (!gidMatch(subscriptionRule.mGid2, mGid2)) { if (gid2 != null) { if (!gidMatch(subscriptionRule.gid2, gid2)) { mScore = SCORE_INVALID; return; } mScore += SCORE_GID2; } if (mPlmn != null) { if (!CarrierResolver.equals(subscriptionRule.mPlmn, mPlmn, true)) { if (plmn != null) { if (!CarrierResolver.equals(subscriptionRule.plmn, plmn, true)) { mScore = SCORE_INVALID; return; } mScore += SCORE_PLMN; } if (mSpn != null) { if (!CarrierResolver.equals(subscriptionRule.mSpn, mSpn, true)) { if (spn != null) { if (!CarrierResolver.equals(subscriptionRule.spn, spn, true)) { mScore = SCORE_INVALID; return; } mScore += SCORE_SPN; } if (mPrivilegeAccessRule != null && !mPrivilegeAccessRule.isEmpty()) { if (!carrierPrivilegeRulesMatch(subscriptionRule.mPrivilegeAccessRule, mPrivilegeAccessRule)) { if (privilegeAccessRule != null && !privilegeAccessRule.isEmpty()) { if (!carrierPrivilegeRulesMatch(subscriptionRule.privilegeAccessRule, privilegeAccessRule)) { mScore = SCORE_INVALID; return; } mScore += SCORE_PRIVILEGE_ACCESS_RULE; } if (mApn != null) { if (!CarrierResolver.equals(subscriptionRule.mApn, mApn, true)) { if (apn != null) { if (!CarrierResolver.equals(subscriptionRule.apn, apn, true)) { mScore = SCORE_INVALID; return; } Loading Loading @@ -669,15 +688,15 @@ public class CarrierResolver extends Handler { public String toString() { return "[CarrierMatchingRule] -" + " mccmnc: " + mMccMnc + " gid1: " + mGid1 + " gid2: " + mGid2 + " plmn: " + mPlmn + " imsi_prefix: " + mImsiPrefixPattern + " iccid_prefix" + mIccidPrefix + " spn: " + mSpn + " privilege_access_rule: " + mPrivilegeAccessRule + " apn: " + mApn + " mccmnc: " + mccMnc + " gid1: " + gid1 + " gid2: " + gid2 + " plmn: " + plmn + " imsi_prefix: " + imsiPrefixPattern + " iccid_prefix" + iccidPrefix + " spn: " + spn + " privilege_access_rule: " + privilegeAccessRule + " apn: " + apn + " name: " + mName + " cid: " + mCid + " score: " + mScore; Loading @@ -698,7 +717,8 @@ public class CarrierResolver extends Handler { if (!TextUtils.isEmpty(mTestOverrideCarrierPriviledgeRule)) { accessRules = new ArrayList<>(Arrays.asList(mTestOverrideCarrierPriviledgeRule)); } else { accessRules = mTelephonyMgr.getCertsFromCarrierPrivilegeAccessRules(); accessRules = mTelephonyMgr.createForSubscriptionId(mPhone.getSubId()) .getCertsFromCarrierPrivilegeAccessRules(); } if (VDBG) { Loading Loading @@ -793,13 +813,41 @@ public class CarrierResolver extends Handler { * 4) use carrier list version to compare the unknown carrier ratio between each version. */ String unknownGid1ToLog = ((maxScore & CarrierMatchingRule.SCORE_GID1) == 0 && !TextUtils.isEmpty(subscriptionRule.mGid1)) ? subscriptionRule.mGid1 : null; && !TextUtils.isEmpty(subscriptionRule.gid1)) ? subscriptionRule.gid1 : null; String unknownMccmncToLog = ((maxScore == CarrierMatchingRule.SCORE_INVALID || (maxScore & CarrierMatchingRule.SCORE_GID1) == 0) && !TextUtils.isEmpty(subscriptionRule.mMccMnc)) ? subscriptionRule.mMccMnc : null; && !TextUtils.isEmpty(subscriptionRule.mccMnc)) ? subscriptionRule.mccMnc : null; // pass subscription rule to metrics. scrub all possible PII before uploading. // only log apn if not user edited. String apn = (subscriptionRule.apn != null && !isPreferApnUserEdited(subscriptionRule.apn)) ? subscriptionRule.apn : null; // only log first 7 bits of iccid String iccidPrefix = (subscriptionRule.iccidPrefix != null) && (subscriptionRule.iccidPrefix.length() >= 7) ? subscriptionRule.iccidPrefix.substring(0, 7) : subscriptionRule.iccidPrefix; // only log first 8 bits of imsi String imsiPrefix = (subscriptionRule.imsiPrefixPattern != null) && (subscriptionRule.imsiPrefixPattern.length() >= 8) ? subscriptionRule.imsiPrefixPattern.substring(0, 8) : subscriptionRule.imsiPrefixPattern; CarrierMatchingRule simInfo = new CarrierMatchingRule( subscriptionRule.mccMnc, imsiPrefix, iccidPrefix, subscriptionRule.gid1, subscriptionRule.gid2, subscriptionRule.plmn, subscriptionRule.spn, apn, subscriptionRule.privilegeAccessRule, -1, null, -1); TelephonyMetrics.getInstance().writeCarrierIdMatchingEvent( mPhone.getPhoneId(), getCarrierListVersion(), mCarrierId, unknownMccmncToLog, unknownGid1ToLog); unknownMccmncToLog, unknownGid1ToLog, simInfo); } public int getCarrierListVersion() { Loading Loading @@ -874,7 +922,7 @@ public class CarrierResolver extends Handler { int carrierId = TelephonyManager.UNKNOWN_CARRIER_ID; int maxScore = CarrierMatchingRule.SCORE_INVALID; List<CarrierMatchingRule> rules = getCarrierMatchingRulesFromMccMnc( context, targetRule.mMccMnc); context, targetRule.mccMnc); for (CarrierMatchingRule rule : rules) { rule.match(targetRule); if (rule.mScore > maxScore) { Loading src/java/com/android/internal/telephony/MultiSimSettingController.java +15 −20 Original line number Diff line number Diff line Loading @@ -63,7 +63,6 @@ public class MultiSimSettingController extends Handler { private final Context mContext; private final SubscriptionController mSubController; private boolean mIsAllSubscriptionsLoaded; private List<SubscriptionInfo> mPrimarySubList; /** The singleton instance. */ Loading Loading @@ -117,7 +116,8 @@ public class MultiSimSettingController extends Handler { } /** * Notify that, for the first time after boot, SIMs are all loaded * Notify that, for the first time after boot, SIMs are initialized. * Should only be triggered once. */ public void notifyAllSubscriptionLoaded() { obtainMessage(EVENT_ALL_SUBSCRIPTIONS_LOADED).sendToTarget(); Loading Loading @@ -181,8 +181,7 @@ public class MultiSimSettingController extends Handler { * If user is enabling a non-default non-opportunistic subscription, make it default * data subscription. */ @VisibleForTesting public void onUserDataEnabled(int subId, boolean enable) { private void onUserDataEnabled(int subId, boolean enable) { if (DBG) log("onUserDataEnabled"); // Make sure MOBILE_DATA of subscriptions in same group are synced. setUserDataEnabledForGroup(subId, enable); Loading @@ -197,8 +196,7 @@ public class MultiSimSettingController extends Handler { /** * Make sure DATA_ROAMING of subscriptions in same group are synced. */ @VisibleForTesting public void onRoamingDataEnabled(int subId, boolean enable) { private void onRoamingDataEnabled(int subId, boolean enable) { if (DBG) log("onRoamingDataEnabled"); setRoamingDataEnabledForGroup(subId, enable); Loading @@ -207,12 +205,11 @@ public class MultiSimSettingController extends Handler { } /** * Mark mIsAllSubscriptionsLoaded and update defaults and mobile data enabling. * Upon initialization, update defaults and mobile data enabling. * Should only be triggered once. */ @VisibleForTesting public void onAllSubscriptionsLoaded() { private void onAllSubscriptionsLoaded() { if (DBG) log("onAllSubscriptionsLoaded"); mIsAllSubscriptionsLoaded = true; updateDefaults(); disableDataForNonDefaultNonOpportunisticSubscriptions(); } Loading @@ -222,10 +219,9 @@ public class MultiSimSettingController extends Handler { * * Make sure non-default non-opportunistic subscriptions has data off. */ @VisibleForTesting public void onSubscriptionsChanged() { private void onSubscriptionsChanged() { if (DBG) log("onSubscriptionsChanged"); if (!mIsAllSubscriptionsLoaded) return; if (!SubscriptionInfoUpdater.isSubInfoInitialized()) return; updateDefaults(); disableDataForNonDefaultNonOpportunisticSubscriptions(); } Loading @@ -233,8 +229,7 @@ public class MultiSimSettingController extends Handler { /** * Make sure non-default non-opportunistic subscriptions has data disabled. */ @VisibleForTesting public void onDefaultDataSettingChanged() { private void onDefaultDataSettingChanged() { if (DBG) log("onDefaultDataSettingChanged"); disableDataForNonDefaultNonOpportunisticSubscriptions(); } Loading @@ -245,8 +240,7 @@ public class MultiSimSettingController extends Handler { * TODO: b/130258159 have a separate database table for grouped subscriptions so we don't * manually sync each setting. */ @VisibleForTesting public void onSubscriptionGroupChanged(ParcelUuid groupUuid) { private void onSubscriptionGroupChanged(ParcelUuid groupUuid) { if (DBG) log("onSubscriptionGroupChanged"); List<SubscriptionInfo> infoList = mSubController.getSubscriptionsInGroup( Loading Loading @@ -306,11 +300,10 @@ public class MultiSimSettingController extends Handler { * not a user settable value anymore. * 4) If non above is met, clear the default value to INVALID. */ @VisibleForTesting public void updateDefaults() { private void updateDefaults() { if (DBG) log("updateDefaults"); if (!mIsAllSubscriptionsLoaded) return; if (!SubscriptionInfoUpdater.isSubInfoInitialized()) return; List<SubscriptionInfo> activeSubInfos = mSubController .getActiveSubscriptionInfoList(mContext.getOpPackageName()); Loading Loading @@ -399,6 +392,8 @@ public class MultiSimSettingController extends Handler { } private void disableDataForNonDefaultNonOpportunisticSubscriptions() { if (!SubscriptionInfoUpdater.isSubInfoInitialized()) return; int defaultDataSub = mSubController.getDefaultDataSubId(); // Only disable data for non-default subscription if default sub is active. if (!mSubController.isActiveSubId(defaultDataSub)) { Loading src/java/com/android/internal/telephony/PhoneSwitcher.java +1 −0 Original line number Diff line number Diff line Loading @@ -944,6 +944,7 @@ public class PhoneSwitcher extends Handler { if (mValidator.isValidationFeatureSupported() && needValidation) { logDataSwitchEvent(subId, TelephonyEvent.EventState.EVENT_STATE_START, DataSwitch.Reason.DATA_SWITCH_REASON_CBRS); registerDefaultNetworkChangeCallback(); mSetOpptSubCallback = callback; mValidator.validate(subIdToValidate, DEFAULT_VALIDATION_EXPIRATION_TIME, false, mValidationCallback); Loading src/java/com/android/internal/telephony/SubscriptionController.java +17 −42 Original line number Diff line number Diff line Loading @@ -211,27 +211,17 @@ public class SubscriptionController extends ISub.Stub { if (DBG) logdl("[SubscriptionController] init by Context"); } /** * Should only be triggered once. */ public void notifySubInfoReady() { // broadcast default subId. sendDefaultChangedBroadcast(SubscriptionManager.getDefaultSubscriptionId()); } @UnsupportedAppUsage private boolean isSubInfoReady() { if (VDBG) { // make sure sSlotIndexToSubIds is consistent with cached subinfo list int count = 0; for (Integer i : sSlotIndexToSubIds.keySet()) { count += sSlotIndexToSubIds.get(i).size(); } if (count != mCacheActiveSubInfoList.size()) { logdl("mismatch between map and list. list size = " + mCacheActiveSubInfoList.size() + ", map size = " + count); for (Integer i : sSlotIndexToSubIds.keySet()) { logdl("From the Map, subs in map at slot index: " + i + " are: " + sSlotIndexToSubIds.get(i)); } for (SubscriptionInfo info : mCacheActiveSubInfoList) { logdl("From the Cached list, subinfo is: " + info); } } } return sSlotIndexToSubIds.size() > 0; return SubscriptionInfoUpdater.isSubInfoInitialized(); } /** Loading Loading @@ -703,14 +693,6 @@ public class SubscriptionController extends ISub.Stub { */ @VisibleForTesting // For mockito to mock this method public void refreshCachedActiveSubscriptionInfoList() { if (!isSubInfoReady()) { if (DBG_CACHE) { logdl("[refreshCachedActiveSubscriptionInfoList] " + "Sub Controller not ready "); } return; } boolean opptSubListChanged; synchronized (mSubInfoListLock) { Loading Loading @@ -1365,8 +1347,7 @@ public class SubscriptionController extends ISub.Stub { if (DBG) logdl("[clearSubInfoRecord]+ iccId:" + " slotIndex:" + slotIndex); // update simInfo db with invalid slot index List<SubscriptionInfo> oldSubInfo = getSubInfoUsingSlotIndexPrivileged(slotIndex, false); List<SubscriptionInfo> oldSubInfo = getSubInfoUsingSlotIndexPrivileged(slotIndex); ContentResolver resolver = mContext.getContentResolver(); ContentValues value = new ContentValues(1); value.put(SubscriptionManager.SIM_SLOT_INDEX, Loading Loading @@ -2337,8 +2318,7 @@ public class SubscriptionController extends ISub.Stub { /** Must be public for access from instrumentation tests. */ @VisibleForTesting public List<SubscriptionInfo> getSubInfoUsingSlotIndexPrivileged(int slotIndex, boolean needCheck) { public List<SubscriptionInfo> getSubInfoUsingSlotIndexPrivileged(int slotIndex) { if (DBG) logd("[getSubInfoUsingSlotIndexPrivileged]+ slotIndex:" + slotIndex); if (slotIndex == SubscriptionManager.DEFAULT_SIM_SLOT_INDEX) { slotIndex = getSlotIndex(getDefaultSubId()); Loading @@ -2348,11 +2328,6 @@ public class SubscriptionController extends ISub.Stub { return null; } if (needCheck && !isSubInfoReady()) { if (DBG) logd("[getSubInfoUsingSlotIndexPrivileged]- not ready"); return null; } Cursor cursor = mContext.getContentResolver().query(SubscriptionManager.CONTENT_URI, null, SubscriptionManager.SIM_SLOT_INDEX + "=?", new String[]{String.valueOf(slotIndex)}, null); Loading Loading @@ -3477,11 +3452,6 @@ public class SubscriptionController extends ISub.Stub { // They are doing similar things except operating on different cache. private List<SubscriptionInfo> getSubscriptionInfoListFromCacheHelper( String callingPackage, List<SubscriptionInfo> cacheSubList) { if (!isSubInfoReady()) { if (DBG) logd("[getSubscriptionInfoList] Sub Controller not ready"); return null; } boolean canReadAllPhoneState; try { canReadAllPhoneState = TelephonyPermissions.checkReadPhoneState(mContext, Loading Loading @@ -3590,7 +3560,11 @@ public class SubscriptionController extends ISub.Stub { for (SubscriptionInfo info : mCacheOpportunisticSubInfoList) { if (shouldDisableSubGroup(info.getGroupUuid())) { info.setGroupDisabled(true); if (isActiveSubId(info.getSubscriptionId())) { // TODO: move it to ONS. if (isActiveSubId(info.getSubscriptionId()) && isSubInfoReady()) { logd("[refreshCachedOpportunisticSubscriptionInfoList] " + "Deactivating grouped opportunistic subscription " + info.getSubscriptionId()); deactivateSubscription(info); } } Loading Loading @@ -3626,6 +3600,7 @@ public class SubscriptionController extends ISub.Stub { private void deactivateSubscription(SubscriptionInfo info) { // TODO: b/120439488 deactivate pSIM. if (info.isEmbedded()) { logd("[deactivateSubscription] eSIM profile " + info.getSubscriptionId()); EuiccManager euiccManager = (EuiccManager) mContext.getSystemService(Context.EUICC_SERVICE); euiccManager.switchToSubscription(SubscriptionManager.INVALID_SUBSCRIPTION_ID, Loading Loading
proto/src/telephony.proto +34 −2 Original line number Diff line number Diff line Loading @@ -1573,11 +1573,43 @@ message TelephonyEvent { // Group id level 1. Logged only if gid1 is configured from subscription // but its matching rule is unknown optional string gid1 = 2; optional string unknown_gid1 = 2; // MCC and MNC that map to this carrier. Logged only if mccmnc is configured // from subscription but its matching rule is unknown optional string mccmnc = 3; optional string unknown_mccmnc = 3; // MCC and MNC from the subscription that map to this carrier. optional string mccmnc = 4; // Group id level 1 from the subscription that map to this carrier. optional string gid1 = 5; // Group id level 2 from the subscription that map to this carrier. optional string gid2 = 6; // spn from the subscription that map to this carrier. optional string spn = 7; // pnn from the subscription that map to this carrier. optional string pnn = 8; // iccid prefix from the subscription that map to this carrier. // only log first 7 outof 20 bit of full iccid optional string iccid_prefix = 9; // imsi prefix from the subscription that map to this carrier. // only log additional 2 bits other than MCC MNC. optional string imsi_prefix = 10; // Carrier Privilege Access Rule in hex string from the subscription. // Sample values: 61ed377e85d386a8dfee6b864bd85b0bfaa5af88 repeated string privilege_access_rule = 11; // The Access Point Name, corresponding to "apn" field returned by // "content://telephony/carriers/preferapn" on device. // Sample values: fast.t-mobile.com, internet. Note only log if this apn is not user edited. optional string preferApn = 12; } // Time when event happened on device, in milliseconds since epoch Loading
src/java/com/android/internal/telephony/CarrierResolver.java +110 −62 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.text.TextUtils; import android.util.LocalLog; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.uicc.IccRecords; import com.android.internal.telephony.uicc.UiccController; Loading Loading @@ -362,6 +363,23 @@ public class CarrierResolver extends Handler { return null; } private boolean isPreferApnUserEdited(@NonNull String preferApn) { try (Cursor cursor = mContext.getContentResolver().query( Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "preferapn/subId/" + mPhone.getSubId()), /* projection */ new String[]{Telephony.Carriers.EDITED_STATUS}, /* selection */ Telephony.Carriers.APN + "=?", /* selectionArgs */ new String[]{preferApn}, /* sortOrder */ null) ) { if (cursor != null && cursor.moveToFirst()) { return cursor.getInt(cursor.getColumnIndexOrThrow( Telephony.Carriers.EDITED_STATUS)) == Telephony.Carriers.USER_EDITED; } } catch (Exception ex) { loge("[isPreferApnUserEdited]- exception: " + ex); } return false; } public void setTestOverrideApn(String apn) { logd("[setTestOverrideApn]: " + apn); mTestOverrideApn = apn; Loading Loading @@ -472,7 +490,7 @@ public class CarrierResolver extends Handler { /** * carrier matching attributes with corresponding cid */ private static class CarrierMatchingRule { public static class CarrierMatchingRule { /** * These scores provide the hierarchical relationship between the attributes, intended to * resolve conflicts in a deterministic way. The scores are constructed such that a match Loading @@ -495,16 +513,16 @@ public class CarrierResolver extends Handler { private static final int SCORE_INVALID = -1; // carrier matching attributes private final String mMccMnc; private final String mImsiPrefixPattern; private final String mIccidPrefix; private final String mGid1; private final String mGid2; private final String mPlmn; private final String mSpn; private final String mApn; public final String mccMnc; public final String imsiPrefixPattern; public final String iccidPrefix; public final String gid1; public final String gid2; public final String plmn; public final String spn; public final String apn; // there can be multiple certs configured in the UICC private final List<String> mPrivilegeAccessRule; public final List<String> privilegeAccessRule; // user-facing carrier name private String mName; Loading @@ -515,33 +533,34 @@ public class CarrierResolver extends Handler { private int mScore = 0; private CarrierMatchingRule(String mccmnc, String imsiPrefixPattern, String iccidPrefix, @VisibleForTesting public CarrierMatchingRule(String mccmnc, String imsiPrefixPattern, String iccidPrefix, String gid1, String gid2, String plmn, String spn, String apn, List<String> privilegeAccessRule, int cid, String name, int parentCid) { mMccMnc = mccmnc; mImsiPrefixPattern = imsiPrefixPattern; mIccidPrefix = iccidPrefix; mGid1 = gid1; mGid2 = gid2; mPlmn = plmn; mSpn = spn; mApn = apn; mPrivilegeAccessRule = privilegeAccessRule; mccMnc = mccmnc; this.imsiPrefixPattern = imsiPrefixPattern; this.iccidPrefix = iccidPrefix; this.gid1 = gid1; this.gid2 = gid2; this.plmn = plmn; this.spn = spn; this.apn = apn; this.privilegeAccessRule = privilegeAccessRule; mCid = cid; mName = name; mParentCid = parentCid; } private CarrierMatchingRule(CarrierMatchingRule rule) { mMccMnc = rule.mMccMnc; mImsiPrefixPattern = rule.mImsiPrefixPattern; mIccidPrefix = rule.mIccidPrefix; mGid1 = rule.mGid1; mGid2 = rule.mGid2; mPlmn = rule.mPlmn; mSpn = rule.mSpn; mApn = rule.mApn; mPrivilegeAccessRule = rule.mPrivilegeAccessRule; mccMnc = rule.mccMnc; imsiPrefixPattern = rule.imsiPrefixPattern; iccidPrefix = rule.iccidPrefix; gid1 = rule.gid1; gid2 = rule.gid2; plmn = rule.plmn; spn = rule.spn; apn = rule.apn; privilegeAccessRule = rule.privilegeAccessRule; mCid = rule.mCid; mName = rule.mName; mParentCid = rule.mParentCid; Loading @@ -554,67 +573,67 @@ public class CarrierResolver extends Handler { // matches at the same tier, the match with highest score will be used. public void match(CarrierMatchingRule subscriptionRule) { mScore = 0; if (mMccMnc != null) { if (!CarrierResolver.equals(subscriptionRule.mMccMnc, mMccMnc, false)) { if (mccMnc != null) { if (!CarrierResolver.equals(subscriptionRule.mccMnc, mccMnc, false)) { mScore = SCORE_INVALID; return; } mScore += SCORE_MCCMNC; } if (mImsiPrefixPattern != null) { if (!imsiPrefixMatch(subscriptionRule.mImsiPrefixPattern, mImsiPrefixPattern)) { if (imsiPrefixPattern != null) { if (!imsiPrefixMatch(subscriptionRule.imsiPrefixPattern, imsiPrefixPattern)) { mScore = SCORE_INVALID; return; } mScore += SCORE_IMSI_PREFIX; } if (mIccidPrefix != null) { if (!iccidPrefixMatch(subscriptionRule.mIccidPrefix, mIccidPrefix)) { if (iccidPrefix != null) { if (!iccidPrefixMatch(subscriptionRule.iccidPrefix, iccidPrefix)) { mScore = SCORE_INVALID; return; } mScore += SCORE_ICCID_PREFIX; } if (mGid1 != null) { if (!gidMatch(subscriptionRule.mGid1, mGid1)) { if (gid1 != null) { if (!gidMatch(subscriptionRule.gid1, gid1)) { mScore = SCORE_INVALID; return; } mScore += SCORE_GID1; } if (mGid2 != null) { if (!gidMatch(subscriptionRule.mGid2, mGid2)) { if (gid2 != null) { if (!gidMatch(subscriptionRule.gid2, gid2)) { mScore = SCORE_INVALID; return; } mScore += SCORE_GID2; } if (mPlmn != null) { if (!CarrierResolver.equals(subscriptionRule.mPlmn, mPlmn, true)) { if (plmn != null) { if (!CarrierResolver.equals(subscriptionRule.plmn, plmn, true)) { mScore = SCORE_INVALID; return; } mScore += SCORE_PLMN; } if (mSpn != null) { if (!CarrierResolver.equals(subscriptionRule.mSpn, mSpn, true)) { if (spn != null) { if (!CarrierResolver.equals(subscriptionRule.spn, spn, true)) { mScore = SCORE_INVALID; return; } mScore += SCORE_SPN; } if (mPrivilegeAccessRule != null && !mPrivilegeAccessRule.isEmpty()) { if (!carrierPrivilegeRulesMatch(subscriptionRule.mPrivilegeAccessRule, mPrivilegeAccessRule)) { if (privilegeAccessRule != null && !privilegeAccessRule.isEmpty()) { if (!carrierPrivilegeRulesMatch(subscriptionRule.privilegeAccessRule, privilegeAccessRule)) { mScore = SCORE_INVALID; return; } mScore += SCORE_PRIVILEGE_ACCESS_RULE; } if (mApn != null) { if (!CarrierResolver.equals(subscriptionRule.mApn, mApn, true)) { if (apn != null) { if (!CarrierResolver.equals(subscriptionRule.apn, apn, true)) { mScore = SCORE_INVALID; return; } Loading Loading @@ -669,15 +688,15 @@ public class CarrierResolver extends Handler { public String toString() { return "[CarrierMatchingRule] -" + " mccmnc: " + mMccMnc + " gid1: " + mGid1 + " gid2: " + mGid2 + " plmn: " + mPlmn + " imsi_prefix: " + mImsiPrefixPattern + " iccid_prefix" + mIccidPrefix + " spn: " + mSpn + " privilege_access_rule: " + mPrivilegeAccessRule + " apn: " + mApn + " mccmnc: " + mccMnc + " gid1: " + gid1 + " gid2: " + gid2 + " plmn: " + plmn + " imsi_prefix: " + imsiPrefixPattern + " iccid_prefix" + iccidPrefix + " spn: " + spn + " privilege_access_rule: " + privilegeAccessRule + " apn: " + apn + " name: " + mName + " cid: " + mCid + " score: " + mScore; Loading @@ -698,7 +717,8 @@ public class CarrierResolver extends Handler { if (!TextUtils.isEmpty(mTestOverrideCarrierPriviledgeRule)) { accessRules = new ArrayList<>(Arrays.asList(mTestOverrideCarrierPriviledgeRule)); } else { accessRules = mTelephonyMgr.getCertsFromCarrierPrivilegeAccessRules(); accessRules = mTelephonyMgr.createForSubscriptionId(mPhone.getSubId()) .getCertsFromCarrierPrivilegeAccessRules(); } if (VDBG) { Loading Loading @@ -793,13 +813,41 @@ public class CarrierResolver extends Handler { * 4) use carrier list version to compare the unknown carrier ratio between each version. */ String unknownGid1ToLog = ((maxScore & CarrierMatchingRule.SCORE_GID1) == 0 && !TextUtils.isEmpty(subscriptionRule.mGid1)) ? subscriptionRule.mGid1 : null; && !TextUtils.isEmpty(subscriptionRule.gid1)) ? subscriptionRule.gid1 : null; String unknownMccmncToLog = ((maxScore == CarrierMatchingRule.SCORE_INVALID || (maxScore & CarrierMatchingRule.SCORE_GID1) == 0) && !TextUtils.isEmpty(subscriptionRule.mMccMnc)) ? subscriptionRule.mMccMnc : null; && !TextUtils.isEmpty(subscriptionRule.mccMnc)) ? subscriptionRule.mccMnc : null; // pass subscription rule to metrics. scrub all possible PII before uploading. // only log apn if not user edited. String apn = (subscriptionRule.apn != null && !isPreferApnUserEdited(subscriptionRule.apn)) ? subscriptionRule.apn : null; // only log first 7 bits of iccid String iccidPrefix = (subscriptionRule.iccidPrefix != null) && (subscriptionRule.iccidPrefix.length() >= 7) ? subscriptionRule.iccidPrefix.substring(0, 7) : subscriptionRule.iccidPrefix; // only log first 8 bits of imsi String imsiPrefix = (subscriptionRule.imsiPrefixPattern != null) && (subscriptionRule.imsiPrefixPattern.length() >= 8) ? subscriptionRule.imsiPrefixPattern.substring(0, 8) : subscriptionRule.imsiPrefixPattern; CarrierMatchingRule simInfo = new CarrierMatchingRule( subscriptionRule.mccMnc, imsiPrefix, iccidPrefix, subscriptionRule.gid1, subscriptionRule.gid2, subscriptionRule.plmn, subscriptionRule.spn, apn, subscriptionRule.privilegeAccessRule, -1, null, -1); TelephonyMetrics.getInstance().writeCarrierIdMatchingEvent( mPhone.getPhoneId(), getCarrierListVersion(), mCarrierId, unknownMccmncToLog, unknownGid1ToLog); unknownMccmncToLog, unknownGid1ToLog, simInfo); } public int getCarrierListVersion() { Loading Loading @@ -874,7 +922,7 @@ public class CarrierResolver extends Handler { int carrierId = TelephonyManager.UNKNOWN_CARRIER_ID; int maxScore = CarrierMatchingRule.SCORE_INVALID; List<CarrierMatchingRule> rules = getCarrierMatchingRulesFromMccMnc( context, targetRule.mMccMnc); context, targetRule.mccMnc); for (CarrierMatchingRule rule : rules) { rule.match(targetRule); if (rule.mScore > maxScore) { Loading
src/java/com/android/internal/telephony/MultiSimSettingController.java +15 −20 Original line number Diff line number Diff line Loading @@ -63,7 +63,6 @@ public class MultiSimSettingController extends Handler { private final Context mContext; private final SubscriptionController mSubController; private boolean mIsAllSubscriptionsLoaded; private List<SubscriptionInfo> mPrimarySubList; /** The singleton instance. */ Loading Loading @@ -117,7 +116,8 @@ public class MultiSimSettingController extends Handler { } /** * Notify that, for the first time after boot, SIMs are all loaded * Notify that, for the first time after boot, SIMs are initialized. * Should only be triggered once. */ public void notifyAllSubscriptionLoaded() { obtainMessage(EVENT_ALL_SUBSCRIPTIONS_LOADED).sendToTarget(); Loading Loading @@ -181,8 +181,7 @@ public class MultiSimSettingController extends Handler { * If user is enabling a non-default non-opportunistic subscription, make it default * data subscription. */ @VisibleForTesting public void onUserDataEnabled(int subId, boolean enable) { private void onUserDataEnabled(int subId, boolean enable) { if (DBG) log("onUserDataEnabled"); // Make sure MOBILE_DATA of subscriptions in same group are synced. setUserDataEnabledForGroup(subId, enable); Loading @@ -197,8 +196,7 @@ public class MultiSimSettingController extends Handler { /** * Make sure DATA_ROAMING of subscriptions in same group are synced. */ @VisibleForTesting public void onRoamingDataEnabled(int subId, boolean enable) { private void onRoamingDataEnabled(int subId, boolean enable) { if (DBG) log("onRoamingDataEnabled"); setRoamingDataEnabledForGroup(subId, enable); Loading @@ -207,12 +205,11 @@ public class MultiSimSettingController extends Handler { } /** * Mark mIsAllSubscriptionsLoaded and update defaults and mobile data enabling. * Upon initialization, update defaults and mobile data enabling. * Should only be triggered once. */ @VisibleForTesting public void onAllSubscriptionsLoaded() { private void onAllSubscriptionsLoaded() { if (DBG) log("onAllSubscriptionsLoaded"); mIsAllSubscriptionsLoaded = true; updateDefaults(); disableDataForNonDefaultNonOpportunisticSubscriptions(); } Loading @@ -222,10 +219,9 @@ public class MultiSimSettingController extends Handler { * * Make sure non-default non-opportunistic subscriptions has data off. */ @VisibleForTesting public void onSubscriptionsChanged() { private void onSubscriptionsChanged() { if (DBG) log("onSubscriptionsChanged"); if (!mIsAllSubscriptionsLoaded) return; if (!SubscriptionInfoUpdater.isSubInfoInitialized()) return; updateDefaults(); disableDataForNonDefaultNonOpportunisticSubscriptions(); } Loading @@ -233,8 +229,7 @@ public class MultiSimSettingController extends Handler { /** * Make sure non-default non-opportunistic subscriptions has data disabled. */ @VisibleForTesting public void onDefaultDataSettingChanged() { private void onDefaultDataSettingChanged() { if (DBG) log("onDefaultDataSettingChanged"); disableDataForNonDefaultNonOpportunisticSubscriptions(); } Loading @@ -245,8 +240,7 @@ public class MultiSimSettingController extends Handler { * TODO: b/130258159 have a separate database table for grouped subscriptions so we don't * manually sync each setting. */ @VisibleForTesting public void onSubscriptionGroupChanged(ParcelUuid groupUuid) { private void onSubscriptionGroupChanged(ParcelUuid groupUuid) { if (DBG) log("onSubscriptionGroupChanged"); List<SubscriptionInfo> infoList = mSubController.getSubscriptionsInGroup( Loading Loading @@ -306,11 +300,10 @@ public class MultiSimSettingController extends Handler { * not a user settable value anymore. * 4) If non above is met, clear the default value to INVALID. */ @VisibleForTesting public void updateDefaults() { private void updateDefaults() { if (DBG) log("updateDefaults"); if (!mIsAllSubscriptionsLoaded) return; if (!SubscriptionInfoUpdater.isSubInfoInitialized()) return; List<SubscriptionInfo> activeSubInfos = mSubController .getActiveSubscriptionInfoList(mContext.getOpPackageName()); Loading Loading @@ -399,6 +392,8 @@ public class MultiSimSettingController extends Handler { } private void disableDataForNonDefaultNonOpportunisticSubscriptions() { if (!SubscriptionInfoUpdater.isSubInfoInitialized()) return; int defaultDataSub = mSubController.getDefaultDataSubId(); // Only disable data for non-default subscription if default sub is active. if (!mSubController.isActiveSubId(defaultDataSub)) { Loading
src/java/com/android/internal/telephony/PhoneSwitcher.java +1 −0 Original line number Diff line number Diff line Loading @@ -944,6 +944,7 @@ public class PhoneSwitcher extends Handler { if (mValidator.isValidationFeatureSupported() && needValidation) { logDataSwitchEvent(subId, TelephonyEvent.EventState.EVENT_STATE_START, DataSwitch.Reason.DATA_SWITCH_REASON_CBRS); registerDefaultNetworkChangeCallback(); mSetOpptSubCallback = callback; mValidator.validate(subIdToValidate, DEFAULT_VALIDATION_EXPIRATION_TIME, false, mValidationCallback); Loading
src/java/com/android/internal/telephony/SubscriptionController.java +17 −42 Original line number Diff line number Diff line Loading @@ -211,27 +211,17 @@ public class SubscriptionController extends ISub.Stub { if (DBG) logdl("[SubscriptionController] init by Context"); } /** * Should only be triggered once. */ public void notifySubInfoReady() { // broadcast default subId. sendDefaultChangedBroadcast(SubscriptionManager.getDefaultSubscriptionId()); } @UnsupportedAppUsage private boolean isSubInfoReady() { if (VDBG) { // make sure sSlotIndexToSubIds is consistent with cached subinfo list int count = 0; for (Integer i : sSlotIndexToSubIds.keySet()) { count += sSlotIndexToSubIds.get(i).size(); } if (count != mCacheActiveSubInfoList.size()) { logdl("mismatch between map and list. list size = " + mCacheActiveSubInfoList.size() + ", map size = " + count); for (Integer i : sSlotIndexToSubIds.keySet()) { logdl("From the Map, subs in map at slot index: " + i + " are: " + sSlotIndexToSubIds.get(i)); } for (SubscriptionInfo info : mCacheActiveSubInfoList) { logdl("From the Cached list, subinfo is: " + info); } } } return sSlotIndexToSubIds.size() > 0; return SubscriptionInfoUpdater.isSubInfoInitialized(); } /** Loading Loading @@ -703,14 +693,6 @@ public class SubscriptionController extends ISub.Stub { */ @VisibleForTesting // For mockito to mock this method public void refreshCachedActiveSubscriptionInfoList() { if (!isSubInfoReady()) { if (DBG_CACHE) { logdl("[refreshCachedActiveSubscriptionInfoList] " + "Sub Controller not ready "); } return; } boolean opptSubListChanged; synchronized (mSubInfoListLock) { Loading Loading @@ -1365,8 +1347,7 @@ public class SubscriptionController extends ISub.Stub { if (DBG) logdl("[clearSubInfoRecord]+ iccId:" + " slotIndex:" + slotIndex); // update simInfo db with invalid slot index List<SubscriptionInfo> oldSubInfo = getSubInfoUsingSlotIndexPrivileged(slotIndex, false); List<SubscriptionInfo> oldSubInfo = getSubInfoUsingSlotIndexPrivileged(slotIndex); ContentResolver resolver = mContext.getContentResolver(); ContentValues value = new ContentValues(1); value.put(SubscriptionManager.SIM_SLOT_INDEX, Loading Loading @@ -2337,8 +2318,7 @@ public class SubscriptionController extends ISub.Stub { /** Must be public for access from instrumentation tests. */ @VisibleForTesting public List<SubscriptionInfo> getSubInfoUsingSlotIndexPrivileged(int slotIndex, boolean needCheck) { public List<SubscriptionInfo> getSubInfoUsingSlotIndexPrivileged(int slotIndex) { if (DBG) logd("[getSubInfoUsingSlotIndexPrivileged]+ slotIndex:" + slotIndex); if (slotIndex == SubscriptionManager.DEFAULT_SIM_SLOT_INDEX) { slotIndex = getSlotIndex(getDefaultSubId()); Loading @@ -2348,11 +2328,6 @@ public class SubscriptionController extends ISub.Stub { return null; } if (needCheck && !isSubInfoReady()) { if (DBG) logd("[getSubInfoUsingSlotIndexPrivileged]- not ready"); return null; } Cursor cursor = mContext.getContentResolver().query(SubscriptionManager.CONTENT_URI, null, SubscriptionManager.SIM_SLOT_INDEX + "=?", new String[]{String.valueOf(slotIndex)}, null); Loading Loading @@ -3477,11 +3452,6 @@ public class SubscriptionController extends ISub.Stub { // They are doing similar things except operating on different cache. private List<SubscriptionInfo> getSubscriptionInfoListFromCacheHelper( String callingPackage, List<SubscriptionInfo> cacheSubList) { if (!isSubInfoReady()) { if (DBG) logd("[getSubscriptionInfoList] Sub Controller not ready"); return null; } boolean canReadAllPhoneState; try { canReadAllPhoneState = TelephonyPermissions.checkReadPhoneState(mContext, Loading Loading @@ -3590,7 +3560,11 @@ public class SubscriptionController extends ISub.Stub { for (SubscriptionInfo info : mCacheOpportunisticSubInfoList) { if (shouldDisableSubGroup(info.getGroupUuid())) { info.setGroupDisabled(true); if (isActiveSubId(info.getSubscriptionId())) { // TODO: move it to ONS. if (isActiveSubId(info.getSubscriptionId()) && isSubInfoReady()) { logd("[refreshCachedOpportunisticSubscriptionInfoList] " + "Deactivating grouped opportunistic subscription " + info.getSubscriptionId()); deactivateSubscription(info); } } Loading Loading @@ -3626,6 +3600,7 @@ public class SubscriptionController extends ISub.Stub { private void deactivateSubscription(SubscriptionInfo info) { // TODO: b/120439488 deactivate pSIM. if (info.isEmbedded()) { logd("[deactivateSubscription] eSIM profile " + info.getSubscriptionId()); EuiccManager euiccManager = (EuiccManager) mContext.getSystemService(Context.EUICC_SERVICE); euiccManager.switchToSubscription(SubscriptionManager.INVALID_SUBSCRIPTION_ID, Loading