1 /* 2 * Copyright (C) 2006 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.CarrierConfigManager; 22 import android.telephony.Rlog; 23 import android.telephony.ServiceState; 24 import android.text.TextUtils; 25 26 import com.android.internal.telephony.PhoneConstants; 27 import com.android.internal.telephony.RILConstants; 28 import com.android.internal.telephony.uicc.IccRecords; 29 30 import java.util.ArrayList; 31 import java.util.Arrays; 32 import java.util.HashMap; 33 import java.util.HashSet; 34 import java.util.List; 35 import java.util.Locale; 36 37 /** 38 * This class represents a apn setting for create PDP link 39 */ 40 public class ApnSetting { 41 42 static final String LOG_TAG = "ApnSetting"; 43 44 private static final boolean DBG = false; 45 46 static final String V2_FORMAT_REGEX = "^\\[ApnSettingV2\\]\\s*"; 47 static final String V3_FORMAT_REGEX = "^\\[ApnSettingV3\\]\\s*"; 48 49 public final String carrier; 50 public final String apn; 51 public final String proxy; 52 public final String port; 53 public final String mmsc; 54 public final String mmsProxy; 55 public final String mmsPort; 56 public final String user; 57 public final String password; 58 public final int authType; 59 public final String[] types; 60 public final int id; 61 public final String numeric; 62 public final String protocol; 63 public final String roamingProtocol; 64 public final int mtu; 65 66 /** 67 * Current status of APN 68 * true : enabled APN, false : disabled APN. 69 */ 70 public final boolean carrierEnabled; 71 /** 72 * Radio Access Technology info 73 * To check what values can hold, refer to ServiceState.java. 74 * This should be spread to other technologies, 75 * but currently only used for LTE(14) and EHRPD(13). 76 */ 77 private final int bearer; 78 /** 79 * Radio Access Technology info 80 * To check what values can hold, refer to ServiceState.java. This is a bitmask of radio 81 * technologies in ServiceState. 82 * This should be spread to other technologies, 83 * but currently only used for LTE(14) and EHRPD(13). 84 */ 85 public final int bearerBitmask; 86 87 /* ID of the profile in the modem */ 88 public final int profileId; 89 public final boolean modemCognitive; 90 public final int maxConns; 91 public final int waitTime; 92 public final int maxConnsTime; 93 94 /** 95 * MVNO match type. Possible values: 96 * "spn": Service provider name. 97 * "imsi": IMSI. 98 * "gid": Group identifier level 1. 99 */ 100 public final String mvnoType; 101 /** 102 * MVNO data. Examples: 103 * "spn": A MOBILE, BEN NL 104 * "imsi": 302720x94, 2060188 105 * "gid": 4E, 33 106 */ 107 public final String mvnoMatchData; 108 109 /** 110 * Indicates this APN setting is permanently failed and cannot be 111 * retried by the retry manager anymore. 112 * */ 113 public boolean permanentFailed = false; 114 115 /** 116 * Metered APN types which would be accounted for in data usage. This is a map of subId -> 117 * set of metered apn strings for the carrier. 118 */ 119 private static HashMap<Integer, HashSet<String>> sMeteredApnTypes = new HashMap<>(); 120 121 /** 122 * Metered Roaming APN types which would be accounted for in data usage. This is a map of 123 * subId -> set of metered roaming apn strings for the carrier. 124 */ 125 private static HashMap<Integer, HashSet<String>> sMeteredRoamingApnTypes = new HashMap<>(); 126 ApnSetting(int id, String numeric, String carrier, String apn, String proxy, String port, String mmsc, String mmsProxy, String mmsPort, String user, String password, int authType, String[] types, String protocol, String roamingProtocol, boolean carrierEnabled, int bearer, int bearerBitmask, int profileId, boolean modemCognitive, int maxConns, int waitTime, int maxConnsTime, int mtu, String mvnoType, String mvnoMatchData)127 public ApnSetting(int id, String numeric, String carrier, String apn, 128 String proxy, String port, 129 String mmsc, String mmsProxy, String mmsPort, 130 String user, String password, int authType, String[] types, 131 String protocol, String roamingProtocol, boolean carrierEnabled, int bearer, 132 int bearerBitmask, int profileId, boolean modemCognitive, int maxConns, int waitTime, 133 int maxConnsTime, int mtu, String mvnoType, String mvnoMatchData) { 134 this.id = id; 135 this.numeric = numeric; 136 this.carrier = carrier; 137 this.apn = apn; 138 this.proxy = proxy; 139 this.port = port; 140 this.mmsc = mmsc; 141 this.mmsProxy = mmsProxy; 142 this.mmsPort = mmsPort; 143 this.user = user; 144 this.password = password; 145 this.authType = authType; 146 this.types = new String[types.length]; 147 for (int i = 0; i < types.length; i++) { 148 this.types[i] = types[i].toLowerCase(Locale.ROOT); 149 } 150 this.protocol = protocol; 151 this.roamingProtocol = roamingProtocol; 152 this.carrierEnabled = carrierEnabled; 153 this.bearer = bearer; 154 this.bearerBitmask = (bearerBitmask | ServiceState.getBitmaskForTech(bearer)); 155 this.profileId = profileId; 156 this.modemCognitive = modemCognitive; 157 this.maxConns = maxConns; 158 this.waitTime = waitTime; 159 this.maxConnsTime = maxConnsTime; 160 this.mtu = mtu; 161 this.mvnoType = mvnoType; 162 this.mvnoMatchData = mvnoMatchData; 163 164 } 165 ApnSetting(ApnSetting apn)166 public ApnSetting(ApnSetting apn) { 167 this(apn.id, apn.numeric, apn.carrier, apn.apn, apn.proxy, apn.port, apn.mmsc, apn.mmsProxy, 168 apn.mmsPort, apn.user, apn.password, apn.authType, apn.types, apn.protocol, 169 apn.roamingProtocol, apn.carrierEnabled, apn.bearer, apn.bearerBitmask, 170 apn.profileId, apn.modemCognitive, apn.maxConns, apn.waitTime, apn.maxConnsTime, 171 apn.mtu, apn.mvnoType, apn.mvnoMatchData); 172 } 173 174 /** 175 * Creates an ApnSetting object from a string. 176 * 177 * @param data the string to read. 178 * 179 * The string must be in one of two formats (newlines added for clarity, 180 * spaces are optional): 181 * 182 * v1 format: 183 * <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>, 184 * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>, 185 * <type>[| <type>...], 186 * 187 * v2 format: 188 * [ApnSettingV2] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>, 189 * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>, 190 * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>, 191 * 192 * v3 format: 193 * [ApnSettingV3] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>, 194 * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>, 195 * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>, 196 * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>, 197 * <mvnoType>, <mvnoMatchData> 198 * 199 * Note that the strings generated by toString() do not contain the username 200 * and password and thus cannot be read by this method. 201 */ fromString(String data)202 public static ApnSetting fromString(String data) { 203 if (data == null) return null; 204 205 int version; 206 // matches() operates on the whole string, so append .* to the regex. 207 if (data.matches(V3_FORMAT_REGEX + ".*")) { 208 version = 3; 209 data = data.replaceFirst(V3_FORMAT_REGEX, ""); 210 } else if (data.matches(V2_FORMAT_REGEX + ".*")) { 211 version = 2; 212 data = data.replaceFirst(V2_FORMAT_REGEX, ""); 213 } else { 214 version = 1; 215 } 216 217 String[] a = data.split("\\s*,\\s*"); 218 if (a.length < 14) { 219 return null; 220 } 221 222 int authType; 223 try { 224 authType = Integer.parseInt(a[12]); 225 } catch (NumberFormatException e) { 226 authType = 0; 227 } 228 229 String[] typeArray; 230 String protocol, roamingProtocol; 231 boolean carrierEnabled; 232 int bearerBitmask = 0; 233 int profileId = 0; 234 boolean modemCognitive = false; 235 int maxConns = 0; 236 int waitTime = 0; 237 int maxConnsTime = 0; 238 int mtu = PhoneConstants.UNSET_MTU; 239 String mvnoType = ""; 240 String mvnoMatchData = ""; 241 if (version == 1) { 242 typeArray = new String[a.length - 13]; 243 System.arraycopy(a, 13, typeArray, 0, a.length - 13); 244 protocol = RILConstants.SETUP_DATA_PROTOCOL_IP; 245 roamingProtocol = RILConstants.SETUP_DATA_PROTOCOL_IP; 246 carrierEnabled = true; 247 } else { 248 if (a.length < 18) { 249 return null; 250 } 251 typeArray = a[13].split("\\s*\\|\\s*"); 252 protocol = a[14]; 253 roamingProtocol = a[15]; 254 carrierEnabled = Boolean.parseBoolean(a[16]); 255 256 bearerBitmask = ServiceState.getBitmaskFromString(a[17]); 257 258 if (a.length > 22) { 259 modemCognitive = Boolean.parseBoolean(a[19]); 260 try { 261 profileId = Integer.parseInt(a[18]); 262 maxConns = Integer.parseInt(a[20]); 263 waitTime = Integer.parseInt(a[21]); 264 maxConnsTime = Integer.parseInt(a[22]); 265 } catch (NumberFormatException e) { 266 } 267 } 268 if (a.length > 23) { 269 try { 270 mtu = Integer.parseInt(a[23]); 271 } catch (NumberFormatException e) { 272 } 273 } 274 if (a.length > 25) { 275 mvnoType = a[24]; 276 mvnoMatchData = a[25]; 277 } 278 } 279 280 return new ApnSetting(-1,a[10]+a[11],a[0],a[1],a[2],a[3],a[7],a[8], 281 a[9],a[4],a[5],authType,typeArray,protocol,roamingProtocol,carrierEnabled,0, 282 bearerBitmask, profileId, modemCognitive, maxConns, waitTime, maxConnsTime, mtu, 283 mvnoType, mvnoMatchData); 284 } 285 286 /** 287 * Creates an array of ApnSetting objects from a string. 288 * 289 * @param data the string to read. 290 * 291 * Builds on top of the same format used by fromString, but allows for multiple entries 292 * separated by "; ". 293 */ arrayFromString(String data)294 public static List<ApnSetting> arrayFromString(String data) { 295 List<ApnSetting> retVal = new ArrayList<ApnSetting>(); 296 if (TextUtils.isEmpty(data)) { 297 return retVal; 298 } 299 String[] apnStrings = data.split("\\s*;\\s*"); 300 for (String apnString : apnStrings) { 301 ApnSetting apn = fromString(apnString); 302 if (apn != null) { 303 retVal.add(apn); 304 } 305 } 306 return retVal; 307 } 308 309 @Override toString()310 public String toString() { 311 StringBuilder sb = new StringBuilder(); 312 sb.append("[ApnSettingV3] ") 313 .append(carrier) 314 .append(", ").append(id) 315 .append(", ").append(numeric) 316 .append(", ").append(apn) 317 .append(", ").append(proxy) 318 .append(", ").append(mmsc) 319 .append(", ").append(mmsProxy) 320 .append(", ").append(mmsPort) 321 .append(", ").append(port) 322 .append(", ").append(authType).append(", "); 323 for (int i = 0; i < types.length; i++) { 324 sb.append(types[i]); 325 if (i < types.length - 1) { 326 sb.append(" | "); 327 } 328 } 329 sb.append(", ").append(protocol); 330 sb.append(", ").append(roamingProtocol); 331 sb.append(", ").append(carrierEnabled); 332 sb.append(", ").append(bearer); 333 sb.append(", ").append(bearerBitmask); 334 sb.append(", ").append(profileId); 335 sb.append(", ").append(modemCognitive); 336 sb.append(", ").append(maxConns); 337 sb.append(", ").append(waitTime); 338 sb.append(", ").append(maxConnsTime); 339 sb.append(", ").append(mtu); 340 sb.append(", ").append(mvnoType); 341 sb.append(", ").append(mvnoMatchData); 342 sb.append(", ").append(permanentFailed); 343 return sb.toString(); 344 } 345 346 /** 347 * Returns true if there are MVNO params specified. 348 */ hasMvnoParams()349 public boolean hasMvnoParams() { 350 return !TextUtils.isEmpty(mvnoType) && !TextUtils.isEmpty(mvnoMatchData); 351 } 352 canHandleType(String type)353 public boolean canHandleType(String type) { 354 if (!carrierEnabled) return false; 355 for (String t : types) { 356 // DEFAULT handles all, and HIPRI is handled by DEFAULT 357 if (t.equalsIgnoreCase(type) || 358 t.equalsIgnoreCase(PhoneConstants.APN_TYPE_ALL) || 359 (t.equalsIgnoreCase(PhoneConstants.APN_TYPE_DEFAULT) && 360 type.equalsIgnoreCase(PhoneConstants.APN_TYPE_HIPRI))) { 361 return true; 362 } 363 } 364 return false; 365 } 366 imsiMatches(String imsiDB, String imsiSIM)367 private static boolean imsiMatches(String imsiDB, String imsiSIM) { 368 // Note: imsiDB value has digit number or 'x' character for seperating USIM information 369 // for MVNO operator. And then digit number is matched at same order and 'x' character 370 // could replace by any digit number. 371 // ex) if imsiDB inserted '310260x10xxxxxx' for GG Operator, 372 // that means first 6 digits, 8th and 9th digit 373 // should be set in USIM for GG Operator. 374 int len = imsiDB.length(); 375 int idxCompare = 0; 376 377 if (len <= 0) return false; 378 if (len > imsiSIM.length()) return false; 379 380 for (int idx=0; idx<len; idx++) { 381 char c = imsiDB.charAt(idx); 382 if ((c == 'x') || (c == 'X') || (c == imsiSIM.charAt(idx))) { 383 continue; 384 } else { 385 return false; 386 } 387 } 388 return true; 389 } 390 mvnoMatches(IccRecords r, String mvnoType, String mvnoMatchData)391 public static boolean mvnoMatches(IccRecords r, String mvnoType, String mvnoMatchData) { 392 if (mvnoType.equalsIgnoreCase("spn")) { 393 if ((r.getServiceProviderName() != null) && 394 r.getServiceProviderName().equalsIgnoreCase(mvnoMatchData)) { 395 return true; 396 } 397 } else if (mvnoType.equalsIgnoreCase("imsi")) { 398 String imsiSIM = r.getIMSI(); 399 if ((imsiSIM != null) && imsiMatches(mvnoMatchData, imsiSIM)) { 400 return true; 401 } 402 } else if (mvnoType.equalsIgnoreCase("gid")) { 403 String gid1 = r.getGid1(); 404 int mvno_match_data_length = mvnoMatchData.length(); 405 if ((gid1 != null) && (gid1.length() >= mvno_match_data_length) && 406 gid1.substring(0, mvno_match_data_length).equalsIgnoreCase(mvnoMatchData)) { 407 return true; 408 } 409 } 410 return false; 411 } 412 isMeteredApnType(String type, Context context, int subId, boolean isRoaming)413 public static boolean isMeteredApnType(String type, Context context, int subId, 414 boolean isRoaming) { 415 416 HashMap<Integer, HashSet<String>> meteredApnTypesCache = (isRoaming) ? 417 sMeteredApnTypes : sMeteredRoamingApnTypes; 418 String carrierConfig = (isRoaming) ? 419 CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS : 420 CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS; 421 422 synchronized (meteredApnTypesCache) { 423 HashSet<String> meteredApnSet = meteredApnTypesCache.get(subId); 424 425 // In case of cache miss, we need to look up the settings from carrier config. 426 if (meteredApnSet == null) { 427 // Retrieve the metered APN types from carrier config 428 CarrierConfigManager configManager = (CarrierConfigManager) 429 context.getSystemService(Context.CARRIER_CONFIG_SERVICE); 430 if (configManager == null) { 431 Rlog.e(LOG_TAG, "Carrier config service is not available"); 432 return true; 433 } 434 435 PersistableBundle b = configManager.getConfigForSubId(subId); 436 if (b == null) { 437 Rlog.e(LOG_TAG, "Can't get the config. subId = " + subId); 438 return true; 439 } 440 441 String[] meteredApnTypes = b.getStringArray(carrierConfig); 442 if (meteredApnTypes == null) { 443 Rlog.e(LOG_TAG, carrierConfig + " is not available. " + "subId = " + subId); 444 return true; 445 } 446 447 meteredApnSet = new HashSet<String>(Arrays.asList(meteredApnTypes)); 448 meteredApnTypesCache.put(subId, meteredApnSet); 449 if (DBG) { 450 Rlog.d(LOG_TAG, "For subId = " + subId + ", metered APN types are " + 451 Arrays.toString(meteredApnSet.toArray()) + 452 " isRoaming: " + isRoaming); 453 } 454 } 455 // If all types of APN are metered, then this APN setting must be metered. 456 if (meteredApnSet.contains(PhoneConstants.APN_TYPE_ALL)) { 457 if (DBG) Rlog.d(LOG_TAG, "All APN types are metered. isRoaming: " + isRoaming); 458 return true; 459 } 460 461 if (meteredApnSet.contains(type)) { 462 if (DBG) Rlog.d(LOG_TAG, type + " is metered. isRoaming: " + isRoaming); 463 return true; 464 } else if (type.equals(PhoneConstants.APN_TYPE_ALL)) { 465 // Assuming no configuration error, if at least one APN type is 466 // metered, then this APN setting is metered. 467 if (meteredApnSet.size() > 0) { 468 if (DBG) Rlog.d(LOG_TAG, "APN_TYPE_ALL APN is metered. isRoaming: " + 469 isRoaming); 470 return true; 471 } 472 } 473 } 474 if (DBG) Rlog.d(LOG_TAG, type + " is not metered. isRoaming: " + isRoaming); 475 return false; 476 } 477 isMetered(Context context, int subId, boolean isRoaming )478 public boolean isMetered(Context context, int subId, boolean isRoaming ) { 479 for (String type : types) { 480 // If one of the APN type is metered, then this APN setting is metered. 481 if (isMeteredApnType(type, context, subId, isRoaming)) { 482 if (DBG) Rlog.d(LOG_TAG, "Metered. APN = " + toString() + 483 "isRoaming: " + isRoaming); 484 return true; 485 } 486 } 487 if (DBG) Rlog.d(LOG_TAG, "Not metered. APN = " + toString() + "isRoaming: " + isRoaming); 488 return false; 489 } 490 491 // TODO - if we have this function we should also have hashCode. 492 // Also should handle changes in type order and perhaps case-insensitivity 493 @Override equals(Object o)494 public boolean equals(Object o) { 495 if (o instanceof ApnSetting == false) { 496 return false; 497 } 498 499 ApnSetting other = (ApnSetting) o; 500 501 return carrier.equals(other.carrier) && 502 id == other.id && 503 numeric.equals(other.numeric) && 504 apn.equals(other.apn) && 505 proxy.equals(other.proxy) && 506 mmsc.equals(other.mmsc) && 507 mmsProxy.equals(other.mmsProxy) && 508 port.equals(other.port) && 509 authType == other.authType && 510 Arrays.deepEquals(types, other.types) && 511 protocol.equals(other.protocol) && 512 roamingProtocol.equals(other.roamingProtocol) && 513 carrierEnabled == other.carrierEnabled && 514 bearer == other.bearer && 515 bearerBitmask == other.bearerBitmask && 516 profileId == other.profileId && 517 modemCognitive == other.modemCognitive && 518 maxConns == other.maxConns && 519 waitTime == other.waitTime && 520 maxConnsTime == other.maxConnsTime && 521 mtu == other.mtu && 522 mvnoType.equals(other.mvnoType) && 523 mvnoMatchData.equals(other.mvnoMatchData); 524 } 525 } 526