1 /* 2 * Copyright (C) 2018 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 17 package com.android.internal.telephony.dataconnection; 18 19 import android.content.Context; 20 import android.os.PersistableBundle; 21 import android.telephony.Annotation.ApnType; 22 import android.telephony.CarrierConfigManager; 23 import android.telephony.data.ApnSetting; 24 import android.util.Log; 25 26 import com.android.internal.telephony.Phone; 27 import com.android.internal.telephony.uicc.IccRecords; 28 import com.android.telephony.Rlog; 29 30 import java.util.Arrays; 31 import java.util.HashSet; 32 33 /** 34 * This class represents a apn setting for create PDP link 35 */ 36 public class ApnSettingUtils { 37 38 static final String LOG_TAG = "ApnSetting"; 39 40 private static final boolean DBG = false; 41 iccidMatches(String mvnoData, String iccId)42 private static boolean iccidMatches(String mvnoData, String iccId) { 43 String[] mvnoIccidList = mvnoData.split(","); 44 for (String mvnoIccid : mvnoIccidList) { 45 if (iccId.startsWith(mvnoIccid)) { 46 Log.d(LOG_TAG, "mvno icc id match found"); 47 return true; 48 } 49 } 50 return false; 51 } 52 imsiMatches(String imsiDB, String imsiSIM)53 private static boolean imsiMatches(String imsiDB, String imsiSIM) { 54 // Note: imsiDB value has digit number or 'x' character for seperating USIM information 55 // for MVNO operator. And then digit number is matched at same order and 'x' character 56 // could replace by any digit number. 57 // ex) if imsiDB inserted '310260x10xxxxxx' for GG Operator, 58 // that means first 6 digits, 8th and 9th digit 59 // should be set in USIM for GG Operator. 60 int len = imsiDB.length(); 61 62 if (len <= 0) return false; 63 if (len > imsiSIM.length()) return false; 64 65 for (int idx = 0; idx < len; idx++) { 66 char c = imsiDB.charAt(idx); 67 if ((c == 'x') || (c == 'X') || (c == imsiSIM.charAt(idx))) { 68 continue; 69 } else { 70 return false; 71 } 72 } 73 return true; 74 } 75 76 /** 77 * Check if MVNO type and data match IccRecords. 78 * 79 * @param r the IccRecords 80 * @param mvnoType the MVNO type 81 * @param mvnoMatchData the MVNO match data 82 * @return {@code true} if MVNO type and data match IccRecords, {@code false} otherwise. 83 */ mvnoMatches(IccRecords r, int mvnoType, String mvnoMatchData)84 public static boolean mvnoMatches(IccRecords r, int mvnoType, String mvnoMatchData) { 85 if (mvnoType == ApnSetting.MVNO_TYPE_SPN) { 86 String spn = r.getServiceProviderNameWithBrandOverride(); 87 if ((spn != null) && spn.equalsIgnoreCase(mvnoMatchData)) { 88 return true; 89 } 90 } else if (mvnoType == ApnSetting.MVNO_TYPE_IMSI) { 91 String imsiSIM = r.getIMSI(); 92 if ((imsiSIM != null) && imsiMatches(mvnoMatchData, imsiSIM)) { 93 return true; 94 } 95 } else if (mvnoType == ApnSetting.MVNO_TYPE_GID) { 96 String gid1 = r.getGid1(); 97 int mvno_match_data_length = mvnoMatchData.length(); 98 if ((gid1 != null) && (gid1.length() >= mvno_match_data_length) 99 && gid1.substring(0, mvno_match_data_length).equalsIgnoreCase(mvnoMatchData)) { 100 return true; 101 } 102 } else if (mvnoType == ApnSetting.MVNO_TYPE_ICCID) { 103 String iccId = r.getIccId(); 104 if ((iccId != null) && iccidMatches(mvnoMatchData, iccId)) { 105 return true; 106 } 107 } 108 109 return false; 110 } 111 112 /** 113 * Check if this APN type is metered. 114 * 115 * @param apnType the APN type 116 * @param phone the phone object 117 * @return {@code true} if the APN type is metered, {@code false} otherwise. 118 */ isMeteredApnType(@pnType int apnType, Phone phone)119 public static boolean isMeteredApnType(@ApnType int apnType, Phone phone) { 120 if (phone == null) { 121 return true; 122 } 123 124 boolean isRoaming = phone.getServiceState().getDataRoaming(); 125 int subId = phone.getSubId(); 126 127 String carrierConfig; 128 // First check if the device is roaming. If yes, use the roaming metered APN list. 129 // Otherwise use the normal metered APN list. 130 if (isRoaming) { 131 carrierConfig = CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS; 132 } else { 133 carrierConfig = CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS; 134 } 135 136 if (DBG) { 137 Rlog.d(LOG_TAG, "isMeteredApnType: isRoaming=" + isRoaming); 138 } 139 140 CarrierConfigManager configManager = (CarrierConfigManager) 141 phone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); 142 if (configManager == null) { 143 Rlog.e(LOG_TAG, "Carrier config service is not available"); 144 return true; 145 } 146 147 PersistableBundle b = configManager.getConfigForSubId(subId); 148 if (b == null) { 149 Rlog.e(LOG_TAG, "Can't get the config. subId = " + subId); 150 return true; 151 } 152 153 String[] meteredApnTypes = b.getStringArray(carrierConfig); 154 if (meteredApnTypes == null) { 155 Rlog.e(LOG_TAG, carrierConfig + " is not available. " + "subId = " + subId); 156 return true; 157 } 158 159 HashSet<String> meteredApnSet = new HashSet<>(Arrays.asList(meteredApnTypes)); 160 if (DBG) { 161 Rlog.d(LOG_TAG, "For subId = " + subId + ", metered APN types are " 162 + Arrays.toString(meteredApnSet.toArray())); 163 } 164 165 if (meteredApnSet.contains(ApnSetting.getApnTypeString(apnType))) { 166 if (DBG) Rlog.d(LOG_TAG, ApnSetting.getApnTypeString(apnType) + " is metered."); 167 return true; 168 } else if (apnType == ApnSetting.TYPE_ALL) { 169 // Assuming no configuration error, if at least one APN type is 170 // metered, then this APN setting is metered. 171 if (meteredApnSet.size() > 0) { 172 if (DBG) Rlog.d(LOG_TAG, "APN_TYPE_ALL APN is metered."); 173 return true; 174 } 175 } 176 177 if (DBG) Rlog.d(LOG_TAG, ApnSetting.getApnTypeString(apnType) + " is not metered."); 178 return false; 179 } 180 181 /** 182 * Check if this APN setting is metered. 183 * 184 * @param apn APN setting 185 * @param phone The phone object 186 * @return True if this APN setting is metered, otherwise false. 187 */ isMetered(ApnSetting apn, Phone phone)188 public static boolean isMetered(ApnSetting apn, Phone phone) { 189 if (phone == null || apn == null) { 190 return true; 191 } 192 193 for (int apnType : apn.getApnTypes()) { 194 // If one of the APN type is metered, then this APN setting is metered. 195 if (isMeteredApnType(apnType, phone)) { 196 return true; 197 } 198 } 199 return false; 200 } 201 } 202