1 /* 2 * Copyright 2020 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.google.android.iwlan; 18 19 import android.content.Context; 20 import android.net.ipsec.ike.exceptions.IkeProtocolException; 21 import android.os.Handler; 22 import android.os.HandlerThread; 23 import android.os.Looper; 24 import android.os.Message; 25 import android.support.annotation.IntDef; 26 import android.support.annotation.NonNull; 27 import android.telephony.DataFailCause; 28 import android.telephony.TelephonyManager; 29 import android.telephony.data.DataService; 30 import android.text.TextUtils; 31 import android.util.Log; 32 33 import com.android.internal.annotations.VisibleForTesting; 34 35 import com.google.auto.value.AutoValue; 36 37 import org.json.JSONArray; 38 import org.json.JSONException; 39 import org.json.JSONObject; 40 41 import java.io.BufferedReader; 42 import java.io.IOException; 43 import java.io.InputStream; 44 import java.io.InputStreamReader; 45 import java.io.PrintWriter; 46 import java.util.ArrayList; 47 import java.util.Arrays; 48 import java.util.Calendar; 49 import java.util.Date; 50 import java.util.HashMap; 51 import java.util.HashSet; 52 import java.util.List; 53 import java.util.Map; 54 import java.util.Objects; 55 import java.util.Optional; 56 import java.util.Set; 57 import java.util.concurrent.ConcurrentHashMap; 58 import java.util.concurrent.TimeUnit; 59 60 public class ErrorPolicyManager { 61 62 /** 63 * This type is not to be used in config. This is only used internally to catch errors in 64 * parsing the error type. 65 */ 66 private static final int UNKNOWN_ERROR_TYPE = -1; 67 68 /** 69 * This value represents that the error tye is to be used as a fallback to represent all the 70 * errors. 71 */ 72 private static final int FALLBACK_ERROR_TYPE = 1; 73 74 /** 75 * This value represents rest of the errors that are not defined above. ErrorDetails should 76 * mention the specific error. If it doesn't - the policy will be used as a fallback global 77 * policy. Currently, Supported ErrorDetails "IO_EXCEPTION" "TIMEOUT_EXCEPTION" 78 * "SERVER_SELECTION_FAILED" "TUNNEL_TRANSFORM_FAILED" 79 */ 80 private static final int GENERIC_ERROR_TYPE = 2; 81 82 /** 83 * This value represents IKE Protocol Error/Notify Error. 84 * 85 * @see <a href="https://tools.ietf.org/html/rfc4306#section-3.10.1">RFC 4306,Internet Key 86 * Exchange (IKEv2) Protocol </a> for global errors and carrier specific requirements for 87 * other carrier specific error codes. ErrorDetails defined for this type is always in 88 * numeric form representing the error codes. Examples: "24", "9000-9050" 89 */ 90 private static final int IKE_PROTOCOL_ERROR_TYPE = 3; 91 builder()92 static ErrorPolicy.Builder builder() { 93 return new AutoValue_ErrorPolicyManager_ErrorPolicy.Builder() 94 .setInfiniteRetriesWithLastRetryTime(false); 95 } 96 97 @IntDef({UNKNOWN_ERROR_TYPE, FALLBACK_ERROR_TYPE, GENERIC_ERROR_TYPE, IKE_PROTOCOL_ERROR_TYPE}) 98 @interface ErrorPolicyErrorType {} 99 100 private static final String[] GENERIC_ERROR_DETAIL_STRINGS = { 101 "*", 102 "IO_EXCEPTION", 103 "TIMEOUT_EXCEPTION", 104 "SERVER_SELECTION_FAILED", 105 "TUNNEL_TRANSFORM_FAILED" 106 }; 107 108 /** Private IKEv2 notify message types. As defined in TS 124 302 (section 8.1.2.2) */ 109 private static final int IKE_PROTOCOL_ERROR_PDN_CONNECTION_REJECTION = 8192; 110 111 private static final int IKE_PROTOCOL_ERROR_MAX_CONNECTION_REACHED = 8193; 112 private static final int IKE_PROTOCOL_ERROR_SEMANTIC_ERROR_IN_THE_TFT_OPERATION = 8241; 113 private static final int IKE_PROTOCOL_ERROR_SYNTACTICAL_ERROR_IN_THE_TFT_OPERATION = 8242; 114 private static final int IKE_PROTOCOL_ERROR_SEMANTIC_ERRORS_IN_PACKET_FILTERS = 8244; 115 private static final int IKE_PROTOCOL_ERROR_SYNTACTICAL_ERRORS_IN_PACKET_FILTERS = 8245; 116 private static final int IKE_PROTOCOL_ERROR_NON_3GPP_ACCESS_TO_EPC_NOT_ALLOWED = 9000; 117 private static final int IKE_PROTOCOL_ERROR_USER_UNKNOWN = 9001; 118 private static final int IKE_PROTOCOL_ERROR_NO_APN_SUBSCRIPTION = 9002; 119 private static final int IKE_PROTOCOL_ERROR_AUTHORIZATION_REJECTED = 9003; 120 private static final int IKE_PROTOCOL_ERROR_ILLEGAL_ME = 9006; 121 private static final int IKE_PROTOCOL_ERROR_NETWORK_FAILURE = 10500; 122 private static final int IKE_PROTOCOL_ERROR_RAT_TYPE_NOT_ALLOWED = 11001; 123 private static final int IKE_PROTOCOL_ERROR_IMEI_NOT_ACCEPTED = 11005; 124 private static final int IKE_PROTOCOL_ERROR_PLMN_NOT_ALLOWED = 11011; 125 private static final int IKE_PROTOCOL_ERROR_UNAUTHENTICATED_EMERGENCY_NOT_SUPPORTED = 11055; 126 127 /** Private IKEv2 notify message types, as defined in TS 124 502 (section 9.2.4.1) */ 128 private static final int IKE_PROTOCOL_ERROR_CONGESTION = 15500; 129 130 private final String LOG_TAG; 131 132 private static final Map<Integer, ErrorPolicyManager> mInstances = new ConcurrentHashMap<>(); 133 private final Context mContext; 134 private final int mSlotId; 135 136 // Policies read from defaultiwlanerrorconfig.json 137 // String APN as key to identify the ErrorPolicies associated with it. 138 private final Map<String, List<ErrorPolicy>> mDefaultPolicies = new HashMap<>(); 139 140 // Policies read from CarrierConfig 141 // String APN as key to identify the ErrorPolicies associated with it. 142 private final Map<String, List<ErrorPolicy>> mCarrierConfigPolicies = new HashMap<>(); 143 144 // String APN as key to identify the ErrorInfo associated with that APN 145 private final Map<String, ErrorInfo> mLastErrorForApn = new ConcurrentHashMap<>(); 146 147 // Records the most recently reported IwlanError (including NO_ERROR), and the corresponding 148 // APN. 149 private ApnWithIwlanError mMostRecentError; 150 151 // List of current Unthrottling events registered with IwlanEventListener 152 private Set<Integer> mUnthrottlingEvents; 153 154 private final ErrorStats mErrorStats = new ErrorStats(); 155 156 private HandlerThread mHandlerThread; 157 @VisibleForTesting Handler mHandler; 158 159 private int carrierId = TelephonyManager.UNKNOWN_CARRIER_ID; 160 161 private String mCarrierConfigErrorPolicyString; 162 163 @VisibleForTesting 164 static final String KEY_ERROR_POLICY_CONFIG_STRING = "iwlan.key_error_policy_config_string"; 165 166 /** 167 * Returns ErrorPolicyManager instance for the subId 168 * 169 * @param context 170 * @param slotId 171 */ getInstance(@onNull Context context, int slotId)172 public static ErrorPolicyManager getInstance(@NonNull Context context, int slotId) { 173 return mInstances.computeIfAbsent(slotId, k -> new ErrorPolicyManager(context, slotId)); 174 } 175 176 @VisibleForTesting resetAllInstances()177 public static void resetAllInstances() { 178 mInstances.clear(); 179 } 180 181 /** 182 * Release or reset the instance. 183 */ releaseInstance()184 public void releaseInstance() { 185 Log.d(LOG_TAG, "Release Instance with slotId: " + mSlotId); 186 IwlanEventListener.getInstance(mContext, mSlotId).removeEventListener(mHandler); 187 mHandlerThread.quit(); 188 mInstances.remove(mSlotId); 189 } 190 191 /** 192 * Updates the last error details and returns the retry time. Return value is -1, which should 193 * be ignored, when the error is IwlanError.NO_ERROR. 194 * 195 * @param apn apn name for which the error happened 196 * @param iwlanError Error 197 * @return retry time. 0 = immediate retry, -1 = fail and n = retry after n seconds 198 */ reportIwlanError(String apn, IwlanError iwlanError)199 public synchronized long reportIwlanError(String apn, IwlanError iwlanError) { 200 // Fail by default 201 long retryTime = -1; 202 mMostRecentError = new ApnWithIwlanError(apn, iwlanError); 203 204 if (iwlanError.getErrorType() == IwlanError.NO_ERROR) { 205 Log.d(LOG_TAG, "reportIwlanError: NO_ERROR"); 206 mLastErrorForApn.remove(apn); 207 return retryTime; 208 } 209 mErrorStats.update(apn, iwlanError); 210 211 // remove the entry with the same error if it has back off time 212 if (mLastErrorForApn.containsKey(apn) 213 && mLastErrorForApn.get(apn).getError().equals(iwlanError) 214 && mLastErrorForApn.get(apn).isBackOffTimeValid()) { 215 mLastErrorForApn.remove(apn); 216 } 217 if (!mLastErrorForApn.containsKey(apn) 218 || !mLastErrorForApn.get(apn).getError().equals(iwlanError)) { 219 Log.d(LOG_TAG, "Doesn't match to the previous error" + iwlanError); 220 ErrorPolicy policy = findErrorPolicy(apn, iwlanError); 221 ErrorInfo errorInfo = new ErrorInfo(iwlanError, policy); 222 if (mLastErrorForApn.containsKey(apn)) { 223 ErrorInfo prevErrorInfo = mLastErrorForApn.get(apn); 224 IwlanError prevIwlanError = prevErrorInfo.getError(); 225 // If prev and current error are both IKE_PROTOCOL_EXCEPTION, keep the retry index 226 // TODO: b/292312000 - Workaround for RetryIndex lost 227 if (iwlanError.getErrorType() == IwlanError.IKE_PROTOCOL_EXCEPTION 228 && prevIwlanError.getErrorType() == IwlanError.IKE_PROTOCOL_EXCEPTION) { 229 errorInfo.setCurrentRetryIndex(prevErrorInfo.getCurrentRetryIndex()); 230 } 231 } 232 mLastErrorForApn.put(apn, errorInfo); 233 } 234 retryTime = mLastErrorForApn.get(apn).updateCurrentRetryTime(); 235 return retryTime; 236 } 237 238 /** 239 * Updates the last error details with back off time. Return value is -1, which should be 240 * ignored, when the error is IwlanError.NO_ERROR. 241 * 242 * @param apn apn name for which the error happened 243 * @param iwlanError Error 244 * @param backOffTime in seconds 245 * @return retry time which is the backoff time. -1 if it is NO_ERROR 246 */ reportIwlanError(String apn, IwlanError iwlanError, long backOffTime)247 public synchronized long reportIwlanError(String apn, IwlanError iwlanError, long backOffTime) { 248 // Fail by default 249 long retryTime = -1; 250 251 if (iwlanError.getErrorType() == IwlanError.NO_ERROR) { 252 Log.d(LOG_TAG, "reportIwlanError: NO_ERROR"); 253 mLastErrorForApn.remove(apn); 254 return retryTime; 255 } 256 mErrorStats.update(apn, iwlanError); 257 258 // remove the entry with the same error if it doesn't have back off time. 259 if (mLastErrorForApn.containsKey(apn) 260 && mLastErrorForApn.get(apn).getError().equals(iwlanError) 261 && !mLastErrorForApn.get(apn).isBackOffTimeValid()) { 262 mLastErrorForApn.remove(apn); 263 } 264 retryTime = backOffTime; 265 if (!mLastErrorForApn.containsKey(apn) 266 || !mLastErrorForApn.get(apn).getError().equals(iwlanError)) { 267 Log.d(LOG_TAG, "Doesn't match to the previous error" + iwlanError); 268 ErrorPolicy policy = findErrorPolicy(apn, iwlanError); 269 ErrorInfo errorInfo = new ErrorInfo(iwlanError, policy, backOffTime); 270 mLastErrorForApn.put(apn, errorInfo); 271 } else { 272 ErrorInfo info = mLastErrorForApn.get(apn); 273 info.setBackOffTime(backOffTime); 274 } 275 return retryTime; 276 } 277 278 /** 279 * Checks whether we can bring up Epdg Tunnel - Based on lastErrorForApn 280 * 281 * @param apn apn for which tunnel bring up needs to be checked 282 * @return true if tunnel can be brought up, false otherwise 283 */ canBringUpTunnel(String apn)284 public synchronized boolean canBringUpTunnel(String apn) { 285 boolean ret = true; 286 if (mLastErrorForApn.containsKey(apn)) { 287 ret = mLastErrorForApn.get(apn).canBringUpTunnel(); 288 } 289 Log.d(LOG_TAG, "canBringUpTunnel: " + ret); 290 return ret; 291 } 292 293 // TODO: Modify framework/base/Android.bp to get access to Annotation.java to use 294 // @DataFailureCause 295 // annotation as return type here. (after moving to aosp?) 296 /** 297 * Returns the DataFailCause based on the lastErrorForApn 298 * 299 * @param apn apn name for which DataFailCause is needed 300 * @return DataFailCause corresponding to the error for the apn 301 */ getDataFailCause(String apn)302 public synchronized int getDataFailCause(String apn) { 303 if (!mLastErrorForApn.containsKey(apn)) { 304 return DataFailCause.NONE; 305 } 306 IwlanError error = mLastErrorForApn.get(apn).getError(); 307 return getDataFailCause(error); 308 } 309 getDataFailCause(IwlanError error)310 private int getDataFailCause(IwlanError error) { 311 int ret = DataFailCause.ERROR_UNSPECIFIED; 312 313 if (error.getErrorType() == IwlanError.NO_ERROR) { 314 ret = DataFailCause.NONE; 315 } else if (error.getErrorType() == IwlanError.EPDG_SELECTOR_SERVER_SELECTION_FAILED) { 316 ret = DataFailCause.IWLAN_DNS_RESOLUTION_NAME_FAILURE; 317 } else if (error.getErrorType() == IwlanError.EPDG_ADDRESS_ONLY_IPV4_ALLOWED) { 318 ret = DataFailCause.ONLY_IPV4_ALLOWED; 319 } else if (error.getErrorType() == IwlanError.EPDG_ADDRESS_ONLY_IPV6_ALLOWED) { 320 ret = DataFailCause.ONLY_IPV6_ALLOWED; 321 } else if (error.getErrorType() == IwlanError.IKE_INTERNAL_IO_EXCEPTION) { 322 ret = DataFailCause.IWLAN_IKEV2_MSG_TIMEOUT; 323 } else if (error.getErrorType() == IwlanError.SIM_NOT_READY_EXCEPTION) { 324 ret = DataFailCause.SIM_CARD_CHANGED; 325 } else if (error.getErrorType() 326 == IwlanError.IKE_SESSION_CLOSED_BEFORE_CHILD_SESSION_OPENED) { 327 ret = DataFailCause.IWLAN_IKE_SESSION_CLOSED_BEFORE_CHILD_SESSION_OPENED; 328 } else if (error.getErrorType() == IwlanError.TUNNEL_NOT_FOUND) { 329 ret = DataFailCause.IWLAN_TUNNEL_NOT_FOUND; 330 } else if (error.getErrorType() == IwlanError.IKE_INIT_TIMEOUT) { 331 ret = DataFailCause.IWLAN_IKE_INIT_TIMEOUT; 332 } else if (error.getErrorType() == IwlanError.IKE_MOBILITY_TIMEOUT) { 333 ret = DataFailCause.IWLAN_IKE_MOBILITY_TIMEOUT; 334 } else if (error.getErrorType() == IwlanError.IKE_DPD_TIMEOUT) { 335 ret = DataFailCause.IWLAN_IKE_DPD_TIMEOUT; 336 } else if (error.getErrorType() == IwlanError.TUNNEL_TRANSFORM_FAILED) { 337 ret = DataFailCause.IWLAN_TUNNEL_TRANSFORM_FAILED; 338 } else if (error.getErrorType() == IwlanError.IKE_NETWORK_LOST_EXCEPTION) { 339 ret = DataFailCause.IWLAN_IKE_NETWORK_LOST_EXCEPTION; 340 } else if (error.getErrorType() == IwlanError.IKE_PROTOCOL_EXCEPTION) { 341 Exception exception = error.getException(); 342 if (exception instanceof IkeProtocolException) { 343 int protocolErrorType = ((IkeProtocolException) exception).getErrorType(); 344 switch (protocolErrorType) { 345 case IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED: 346 ret = DataFailCause.IWLAN_IKEV2_AUTH_FAILURE; 347 break; 348 case IkeProtocolException.ERROR_TYPE_INTERNAL_ADDRESS_FAILURE: 349 ret = DataFailCause.IWLAN_EPDG_INTERNAL_ADDRESS_FAILURE; 350 break; 351 case IKE_PROTOCOL_ERROR_PDN_CONNECTION_REJECTION: 352 ret = DataFailCause.IWLAN_PDN_CONNECTION_REJECTION; 353 break; 354 case IKE_PROTOCOL_ERROR_MAX_CONNECTION_REACHED: 355 ret = DataFailCause.IWLAN_MAX_CONNECTION_REACHED; 356 break; 357 case IKE_PROTOCOL_ERROR_SEMANTIC_ERROR_IN_THE_TFT_OPERATION: 358 ret = DataFailCause.IWLAN_SEMANTIC_ERROR_IN_THE_TFT_OPERATION; 359 break; 360 case IKE_PROTOCOL_ERROR_SYNTACTICAL_ERROR_IN_THE_TFT_OPERATION: 361 ret = DataFailCause.IWLAN_SYNTACTICAL_ERROR_IN_THE_TFT_OPERATION; 362 break; 363 case IKE_PROTOCOL_ERROR_SEMANTIC_ERRORS_IN_PACKET_FILTERS: 364 ret = DataFailCause.IWLAN_SEMANTIC_ERRORS_IN_PACKET_FILTERS; 365 break; 366 case IKE_PROTOCOL_ERROR_SYNTACTICAL_ERRORS_IN_PACKET_FILTERS: 367 ret = DataFailCause.IWLAN_SYNTACTICAL_ERRORS_IN_PACKET_FILTERS; 368 break; 369 case IKE_PROTOCOL_ERROR_NON_3GPP_ACCESS_TO_EPC_NOT_ALLOWED: 370 ret = DataFailCause.IWLAN_NON_3GPP_ACCESS_TO_EPC_NOT_ALLOWED; 371 break; 372 case IKE_PROTOCOL_ERROR_USER_UNKNOWN: 373 ret = DataFailCause.IWLAN_USER_UNKNOWN; 374 break; 375 case IKE_PROTOCOL_ERROR_NO_APN_SUBSCRIPTION: 376 ret = DataFailCause.IWLAN_NO_APN_SUBSCRIPTION; 377 break; 378 case IKE_PROTOCOL_ERROR_AUTHORIZATION_REJECTED: 379 ret = DataFailCause.IWLAN_AUTHORIZATION_REJECTED; 380 break; 381 case IKE_PROTOCOL_ERROR_ILLEGAL_ME: 382 ret = DataFailCause.IWLAN_ILLEGAL_ME; 383 break; 384 case IKE_PROTOCOL_ERROR_NETWORK_FAILURE: 385 ret = DataFailCause.IWLAN_NETWORK_FAILURE; 386 break; 387 case IKE_PROTOCOL_ERROR_RAT_TYPE_NOT_ALLOWED: 388 ret = DataFailCause.IWLAN_RAT_TYPE_NOT_ALLOWED; 389 break; 390 case IKE_PROTOCOL_ERROR_IMEI_NOT_ACCEPTED: 391 ret = DataFailCause.IWLAN_IMEI_NOT_ACCEPTED; 392 break; 393 case IKE_PROTOCOL_ERROR_PLMN_NOT_ALLOWED: 394 ret = DataFailCause.IWLAN_PLMN_NOT_ALLOWED; 395 break; 396 case IKE_PROTOCOL_ERROR_UNAUTHENTICATED_EMERGENCY_NOT_SUPPORTED: 397 ret = DataFailCause.IWLAN_UNAUTHENTICATED_EMERGENCY_NOT_SUPPORTED; 398 break; 399 case IKE_PROTOCOL_ERROR_CONGESTION: 400 ret = DataFailCause.IWLAN_CONGESTION; 401 break; 402 default: 403 ret = DataFailCause.IWLAN_IKE_PRIVATE_PROTOCOL_ERROR; 404 break; 405 } 406 } 407 } 408 return ret; 409 } 410 getMostRecentDataFailCause()411 public synchronized int getMostRecentDataFailCause() { 412 if (mMostRecentError != null) { 413 return getDataFailCause(mMostRecentError.mIwlanError); 414 } 415 return DataFailCause.NONE; 416 } 417 418 /** 419 * Returns the current retryTime based on the lastErrorForApn 420 * 421 * @param apn apn name for which curren retry time is needed 422 * @return long current retry time in milliseconds 423 */ getCurrentRetryTimeMs(String apn)424 public synchronized long getCurrentRetryTimeMs(String apn) { 425 if (!mLastErrorForApn.containsKey(apn)) { 426 return -1; 427 } 428 return mLastErrorForApn.get(apn).getCurrentRetryTime(); 429 } 430 431 /** 432 * Returns the index of the FQDN to use for ePDG server selection, based on how many FQDNs are 433 * available, the position of the RetryArray index, and configuration of 'NumAttemptsPerFqdn'. 434 * 435 * @param numFqdns number of FQDNs discovered during ePDG server selection. 436 * @return int index of the FQDN to use for ePDG server selection. -1 (invalid) if RetryArray or 437 * 'NumAttemptsPerFqdn' is not specified in the ErrorPolicy. 438 */ getCurrentFqdnIndex(int numFqdns)439 public synchronized int getCurrentFqdnIndex(int numFqdns) { 440 String apn = mMostRecentError.mApn; 441 if (!mLastErrorForApn.containsKey(apn)) { 442 return -1; 443 } 444 ErrorInfo errorInfo = mLastErrorForApn.get(apn); 445 return errorInfo.getCurrentFqdnIndex(numFqdns); 446 } 447 448 /** 449 * Returns the last error for that apn 450 * 451 * @param apn apn name 452 * @return IwlanError or null if there is no error 453 */ getLastError(String apn)454 public synchronized IwlanError getLastError(String apn) { 455 if (mLastErrorForApn.containsKey(apn)) { 456 return mLastErrorForApn.get(apn).getError(); 457 } 458 return new IwlanError(IwlanError.NO_ERROR); 459 } 460 461 /** 462 * Returns whether framework should retry tunnel setup with initial PDN bringup request when 463 * handover request fails. 464 * 465 * @param apn apn name 466 * @return boolean result of whether framework should retry tunnel setup with initial PDN 467 * bringup request when handover request fails 468 */ shouldRetryWithInitialAttach(String apn)469 public synchronized boolean shouldRetryWithInitialAttach(String apn) { 470 ErrorInfo errorInfo = mLastErrorForApn.get(apn); 471 return errorInfo != null && errorInfo.shouldRetryWithInitialAttach(); 472 } 473 logErrorPolicies()474 public void logErrorPolicies() { 475 Log.d(LOG_TAG, "mCarrierConfigPolicies:"); 476 for (Map.Entry<String, List<ErrorPolicy>> entry : mCarrierConfigPolicies.entrySet()) { 477 Log.d(LOG_TAG, "Apn: " + entry.getKey()); 478 for (ErrorPolicy policy : entry.getValue()) { 479 policy.log(); 480 } 481 } 482 Log.d(LOG_TAG, "mDefaultPolicies:"); 483 for (Map.Entry<String, List<ErrorPolicy>> entry : mDefaultPolicies.entrySet()) { 484 Log.d(LOG_TAG, "Apn: " + entry.getKey()); 485 for (ErrorPolicy policy : entry.getValue()) { 486 policy.log(); 487 } 488 } 489 } 490 dump(PrintWriter pw)491 public synchronized void dump(PrintWriter pw) { 492 pw.println("---- ErrorPolicyManager ----"); 493 for (Map.Entry<String, ErrorInfo> entry : mLastErrorForApn.entrySet()) { 494 pw.print("APN: " + entry.getKey() + " IwlanError: " + entry.getValue().getError()); 495 pw.println(" currentRetryTime: " + entry.getValue().getCurrentRetryTime()); 496 } 497 pw.println(mErrorStats); 498 pw.println("----------------------------"); 499 } 500 ErrorPolicyManager(Context context, int slotId)501 private ErrorPolicyManager(Context context, int slotId) { 502 mContext = context; 503 mSlotId = slotId; 504 LOG_TAG = ErrorPolicyManager.class.getSimpleName() + "[" + slotId + "]"; 505 506 initHandler(); 507 508 // read from default error policy config file 509 try { 510 mDefaultPolicies.putAll(readErrorPolicies(new JSONArray(getDefaultJSONConfig()))); 511 } catch (IOException | JSONException | IllegalArgumentException e) { 512 throw new AssertionError(e); 513 } 514 515 mCarrierConfigErrorPolicyString = null; 516 readFromCarrierConfig(IwlanHelper.getCarrierId(mContext, mSlotId)); 517 updateUnthrottlingEvents(); 518 } 519 findErrorPolicy(String apn, IwlanError iwlanError)520 private ErrorPolicy findErrorPolicy(String apn, IwlanError iwlanError) { 521 ErrorPolicy policy = null; 522 523 if (mCarrierConfigPolicies.containsKey(apn)) { 524 policy = getPreferredErrorPolicy(mCarrierConfigPolicies.get(apn), iwlanError); 525 } 526 if (policy == null && mCarrierConfigPolicies.containsKey("*")) { 527 policy = getPreferredErrorPolicy(mCarrierConfigPolicies.get("*"), iwlanError); 528 } 529 if (policy == null && mDefaultPolicies.containsKey(apn)) { 530 policy = getPreferredErrorPolicy(mDefaultPolicies.get(apn), iwlanError); 531 } 532 if (policy == null && mDefaultPolicies.containsKey("*")) { 533 policy = getPreferredErrorPolicy(mDefaultPolicies.get("*"), iwlanError); 534 } else if (policy == null) { 535 // there should at least be one default policy defined in Default config 536 // that will apply to all errors. 537 logErrorPolicies(); 538 throw new AssertionError("no Default policy defined in the config"); 539 } 540 return policy; 541 } 542 getPreferredErrorPolicy( List<ErrorPolicy> errorPolicies, IwlanError iwlanError)543 private ErrorPolicy getPreferredErrorPolicy( 544 List<ErrorPolicy> errorPolicies, IwlanError iwlanError) { 545 546 ErrorPolicy selectedPolicy = null; 547 for (ErrorPolicy policy : errorPolicies) { 548 if (policy.match(iwlanError)) { 549 if (!policy.isFallback()) { 550 selectedPolicy = policy; 551 break; 552 } 553 if (selectedPolicy == null || policy.getErrorType() != GENERIC_ERROR_TYPE) { 554 selectedPolicy = policy; 555 } 556 } 557 } 558 return selectedPolicy; 559 } 560 561 @VisibleForTesting initHandler()562 void initHandler() { 563 mHandler = new EpmHandler(getLooper()); 564 } 565 566 @VisibleForTesting getLooper()567 Looper getLooper() { 568 mHandlerThread = new HandlerThread("ErrorPolicyManagerThread"); 569 mHandlerThread.start(); 570 return mHandlerThread.getLooper(); 571 } 572 getDefaultJSONConfig()573 private String getDefaultJSONConfig() throws IOException { 574 String str; 575 StringBuilder stringBuilder = new StringBuilder(); 576 InputStream is = mContext.getAssets().open("defaultiwlanerrorconfig.json"); 577 BufferedReader reader = new BufferedReader(new InputStreamReader(is)); 578 while ((str = reader.readLine()) != null && str.length() > 0) { 579 // ignore the lines starting with '#' as they are intended to be 580 // comments 581 if (str.charAt(0) == '#') { 582 continue; 583 } 584 stringBuilder.append(str).append("\n"); 585 } 586 is.close(); 587 return stringBuilder.toString(); 588 } 589 590 @VisibleForTesting readErrorPolicies(JSONArray apnArray)591 Map<String, List<ErrorPolicy>> readErrorPolicies(JSONArray apnArray) 592 throws JSONException, IllegalArgumentException { 593 Map<String, List<ErrorPolicy>> errorPolicies = new HashMap<>(); 594 for (int i = 0; i < apnArray.length(); i++) { 595 JSONObject apnDetails = apnArray.getJSONObject(i); 596 597 String apnName = ((String) apnDetails.get("ApnName")).trim(); 598 JSONArray errorTypeArray = (JSONArray) apnDetails.get("ErrorTypes"); 599 600 for (int j = 0; j < errorTypeArray.length(); j++) { 601 JSONObject errorTypeObject = errorTypeArray.getJSONObject(j); 602 603 String errorTypeStr = ((String) errorTypeObject.get("ErrorType")).trim(); 604 JSONArray errorDetailArray = (JSONArray) errorTypeObject.get("ErrorDetails"); 605 int errorType; 606 607 if ((errorType = getErrorPolicyErrorType(errorTypeStr)) == UNKNOWN_ERROR_TYPE) { 608 throw new IllegalArgumentException("Unknown error type in the parsing"); 609 } 610 611 List<Integer> retryArray = 612 parseRetryArray((JSONArray) errorTypeObject.get("RetryArray")); 613 614 ErrorPolicy.Builder errorPolicyBuilder = 615 builder() 616 .setErrorType(errorType) 617 .setErrorDetails(parseErrorDetails(errorType, errorDetailArray)) 618 .setRetryArray(retryArray) 619 .setUnthrottlingEvents( 620 parseUnthrottlingEvents( 621 (JSONArray) 622 errorTypeObject.get("UnthrottlingEvents"))); 623 624 if (!retryArray.isEmpty() && retryArray.get(retryArray.size() - 1) == -1L) { 625 errorPolicyBuilder.setInfiniteRetriesWithLastRetryTime(true); 626 } 627 628 if (errorTypeObject.has("NumAttemptsPerFqdn")) { 629 errorPolicyBuilder.setNumAttemptsPerFqdn( 630 errorTypeObject.getInt("NumAttemptsPerFqdn")); 631 } 632 633 if (errorTypeObject.has("HandoverAttemptCount")) { 634 if (errorType != IKE_PROTOCOL_ERROR_TYPE) { 635 throw new IllegalArgumentException( 636 "Handover attempt count should not be applied when errorType is not" 637 + " explicitly defined as IKE_PROTOCOL_ERROR_TYPE"); 638 } 639 errorPolicyBuilder.setHandoverAttemptCount( 640 errorTypeObject.getInt("HandoverAttemptCount")); 641 } 642 643 ErrorPolicy errorPolicy = errorPolicyBuilder.build(); 644 645 errorPolicies.putIfAbsent(apnName, new ArrayList<>()); 646 errorPolicies.get(apnName).add(errorPolicy); 647 } 648 } 649 return errorPolicies; 650 } 651 parseRetryArray(JSONArray retryArray)652 private List<Integer> parseRetryArray(JSONArray retryArray) 653 throws JSONException, IllegalArgumentException { 654 List<Integer> ret = new ArrayList<>(); 655 for (int i = 0; i < retryArray.length(); i++) { 656 String retryTime = retryArray.getString(i).trim(); 657 658 // catch misplaced -1 retry times in the array. 659 // 1. if it is not placed at the last position in the array 660 // 2. if it is placed in the first position (catches the case where it is 661 // the only element). 662 if (retryTime.equals("-1") && (i != retryArray.length() - 1 || i == 0)) { 663 throw new IllegalArgumentException("Misplaced -1 in retry array"); 664 } 665 if (TextUtils.isDigitsOnly(retryTime) || retryTime.equals("-1")) { 666 ret.add(Integer.parseInt(retryTime)); 667 } else if (retryTime.contains("+r")) { 668 // randomized retry time 669 String[] times = retryTime.split("\\+r"); 670 if (times.length == 2 671 && TextUtils.isDigitsOnly(times[0]) 672 && TextUtils.isDigitsOnly(times[1])) { 673 ret.add( 674 Integer.parseInt(times[0]) 675 + (int) (Math.random() * Long.parseLong(times[1]))); 676 } else { 677 throw new IllegalArgumentException( 678 "Randomized Retry time is not in acceptable format"); 679 } 680 } else { 681 throw new IllegalArgumentException("Retry time is not in acceptable format"); 682 } 683 } 684 return ret; 685 } 686 parseUnthrottlingEvents(JSONArray unthrottlingEvents)687 private List<Integer> parseUnthrottlingEvents(JSONArray unthrottlingEvents) 688 throws JSONException, IllegalArgumentException { 689 List<Integer> ret = new ArrayList<>(); 690 for (int i = 0; i < unthrottlingEvents.length(); i++) { 691 int event = 692 IwlanEventListener.getUnthrottlingEvent(unthrottlingEvents.getString(i).trim()); 693 if (event == IwlanEventListener.UNKNOWN_EVENT) { 694 throw new IllegalArgumentException( 695 "Unexpected unthrottlingEvent " + unthrottlingEvents.getString(i)); 696 } 697 ret.add(event); 698 } 699 return ret; 700 } 701 parseErrorDetails(int errorType, JSONArray errorDetailArray)702 private List<String> parseErrorDetails(int errorType, JSONArray errorDetailArray) 703 throws JSONException, IllegalArgumentException { 704 List<String> ret = new ArrayList<>(); 705 boolean isValidErrorDetail = true; 706 707 for (int i = 0; i < errorDetailArray.length(); i++) { 708 String errorDetail = errorDetailArray.getString(i).trim(); 709 switch (errorType) { 710 case IKE_PROTOCOL_ERROR_TYPE: 711 isValidErrorDetail = verifyIkeProtocolErrorDetail(errorDetail); 712 break; 713 case GENERIC_ERROR_TYPE: 714 isValidErrorDetail = verifyGenericErrorDetail(errorDetail); 715 break; 716 } 717 if (!isValidErrorDetail) { 718 throw new IllegalArgumentException( 719 "Invalid ErrorDetail: " + errorDetail + " for ErrorType: " + errorType); 720 } 721 ret.add(errorDetail); 722 } 723 return ret; 724 } 725 726 /** Allowed formats are: number(Integer), range(Integers separated by -) and "*" */ verifyIkeProtocolErrorDetail(String errorDetailStr)727 private boolean verifyIkeProtocolErrorDetail(String errorDetailStr) { 728 boolean ret = true; 729 if (errorDetailStr.contains("-")) { 730 // verify range format 731 String[] rangeNumbers = errorDetailStr.split("-"); 732 if (rangeNumbers.length == 2) { 733 for (String range : rangeNumbers) { 734 if (!TextUtils.isDigitsOnly(range)) { 735 ret = false; 736 } 737 } 738 } else { 739 ret = false; 740 } 741 } else if (!errorDetailStr.equals("*") && !TextUtils.isDigitsOnly(errorDetailStr)) { 742 ret = false; 743 } 744 return ret; 745 } 746 747 /** 748 * Allowed strings are: "IO_EXCEPTION", "TIMEOUT_EXCEPTION", "SERVER_SELECTION_FAILED", 749 * "TUNNEL_TRANSFORM_FAILED" and "*" 750 */ verifyGenericErrorDetail(String errorDetailStr)751 private boolean verifyGenericErrorDetail(String errorDetailStr) { 752 boolean ret = false; 753 for (String str : GENERIC_ERROR_DETAIL_STRINGS) { 754 if (errorDetailStr.equals(str)) { 755 ret = true; 756 break; 757 } 758 } 759 return ret; 760 } 761 getErrorPolicyErrorType(String errorType)762 private @ErrorPolicyErrorType int getErrorPolicyErrorType(String errorType) { 763 int ret = UNKNOWN_ERROR_TYPE; 764 switch (errorType) { 765 case "IKE_PROTOCOL_ERROR_TYPE": 766 ret = IKE_PROTOCOL_ERROR_TYPE; 767 break; 768 case "GENERIC_ERROR_TYPE": 769 ret = GENERIC_ERROR_TYPE; 770 break; 771 case "*": 772 ret = FALLBACK_ERROR_TYPE; 773 break; 774 } 775 return ret; 776 } 777 getAllUnthrottlingEvents()778 private synchronized Set<Integer> getAllUnthrottlingEvents() { 779 Set<Integer> events = new HashSet<>(); 780 for (Map.Entry<String, List<ErrorPolicy>> entry : mCarrierConfigPolicies.entrySet()) { 781 List<ErrorPolicy> errorPolicies = entry.getValue(); 782 for (ErrorPolicy errorPolicy : errorPolicies) { 783 events.addAll(errorPolicy.unthrottlingEvents()); 784 } 785 } 786 for (Map.Entry<String, List<ErrorPolicy>> entry : mDefaultPolicies.entrySet()) { 787 List<ErrorPolicy> errorPolicies = entry.getValue(); 788 for (ErrorPolicy errorPolicy : errorPolicies) { 789 events.addAll(errorPolicy.unthrottlingEvents()); 790 } 791 } 792 events.add(IwlanEventListener.CARRIER_CONFIG_CHANGED_EVENT); 793 return events; 794 } 795 796 /** 797 * This method is called once on initialization of this class And is also called from handler on 798 * CARRIER_CONFIG_CHANGED event. There is no race condition between both as we register for the 799 * events after the calling this method. 800 */ readFromCarrierConfig(int currentCarrierId)801 private synchronized void readFromCarrierConfig(int currentCarrierId) { 802 String carrierConfigErrorPolicy = 803 IwlanHelper.getConfig(KEY_ERROR_POLICY_CONFIG_STRING, mContext, mSlotId); 804 if (carrierConfigErrorPolicy == null) { 805 Log.e(LOG_TAG, "ErrorPolicy from Carrier Config is NULL"); 806 mCarrierConfigPolicies.clear(); 807 mCarrierConfigErrorPolicyString = null; 808 return; 809 } 810 try { 811 Map<String, List<ErrorPolicy>> errorPolicies = 812 readErrorPolicies(new JSONArray(carrierConfigErrorPolicy)); 813 if (errorPolicies.size() > 0) { 814 mCarrierConfigErrorPolicyString = carrierConfigErrorPolicy; 815 carrierId = currentCarrierId; 816 mCarrierConfigPolicies.clear(); 817 mCarrierConfigPolicies.putAll(errorPolicies); 818 } 819 } catch (JSONException | IllegalArgumentException e) { 820 Log.e( 821 LOG_TAG, 822 "Unable to parse the ErrorPolicy from CarrierConfig\n" 823 + carrierConfigErrorPolicy); 824 mCarrierConfigPolicies.clear(); 825 mCarrierConfigErrorPolicyString = null; 826 e.printStackTrace(); 827 } 828 } 829 updateUnthrottlingEvents()830 private void updateUnthrottlingEvents() { 831 Set<Integer> registerEvents, unregisterEvents; 832 unregisterEvents = mUnthrottlingEvents; 833 registerEvents = getAllUnthrottlingEvents(); 834 mUnthrottlingEvents = getAllUnthrottlingEvents(); 835 836 if (unregisterEvents != null) { 837 registerEvents.removeAll(unregisterEvents); 838 unregisterEvents.removeAll(mUnthrottlingEvents); 839 } 840 841 IwlanEventListener.getInstance(mContext, mSlotId) 842 .addEventListener(new ArrayList<>(registerEvents), mHandler); 843 if (unregisterEvents != null) { 844 IwlanEventListener.getInstance(mContext, mSlotId) 845 .removeEventListener(new ArrayList<>(unregisterEvents), mHandler); 846 } 847 Log.d( 848 LOG_TAG, 849 "UnthrottlingEvents: " 850 + (mUnthrottlingEvents != null 851 ? Arrays.toString(mUnthrottlingEvents.toArray()) 852 : "null")); 853 } 854 unthrottleLastErrorOnEvent(int event)855 private synchronized void unthrottleLastErrorOnEvent(int event) { 856 Log.d(LOG_TAG, "unthrottleLastErrorOnEvent: " + event); 857 if (event == IwlanEventListener.CARRIER_CONFIG_CHANGED_EVENT) { 858 mLastErrorForApn.clear(); 859 return; 860 } 861 String apn; 862 for (Map.Entry<String, ErrorInfo> entry : mLastErrorForApn.entrySet()) { 863 ErrorPolicy errorPolicy = entry.getValue().getErrorPolicy(); 864 if (errorPolicy.canUnthrottle(event)) { 865 apn = entry.getKey(); 866 mLastErrorForApn.remove(apn); 867 DataService.DataServiceProvider provider = 868 IwlanDataService.getDataServiceProvider(mSlotId); 869 if (provider != null) { 870 provider.notifyApnUnthrottled(apn); 871 } 872 Log.d(LOG_TAG, "unthrottled error for: " + apn); 873 } 874 } 875 } 876 877 @VisibleForTesting getErrorStats()878 ErrorStats getErrorStats() { 879 return mErrorStats; 880 } 881 882 @AutoValue 883 abstract static class ErrorPolicy { 884 private static final String LOG_TAG = ErrorPolicyManager.class.getSimpleName(); 885 errorType()886 abstract @ErrorPolicyErrorType int errorType(); 887 errorDetails()888 abstract List<String> errorDetails(); 889 retryArray()890 abstract List<Integer> retryArray(); 891 infiniteRetriesWithLastRetryTime()892 abstract Boolean infiniteRetriesWithLastRetryTime(); 893 unthrottlingEvents()894 abstract List<Integer> unthrottlingEvents(); 895 numAttemptsPerFqdn()896 abstract Optional<Integer> numAttemptsPerFqdn(); 897 handoverAttemptCount()898 abstract Optional<Integer> handoverAttemptCount(); 899 900 @AutoValue.Builder 901 abstract static class Builder { setErrorType(int errorType)902 abstract Builder setErrorType(int errorType); 903 setErrorDetails(List<String> errorDetails)904 abstract Builder setErrorDetails(List<String> errorDetails); 905 setRetryArray(List<Integer> retryArray)906 abstract Builder setRetryArray(List<Integer> retryArray); 907 setInfiniteRetriesWithLastRetryTime( Boolean infiniteRetriesWithLastRetryTime)908 abstract Builder setInfiniteRetriesWithLastRetryTime( 909 Boolean infiniteRetriesWithLastRetryTime); 910 setUnthrottlingEvents(List<Integer> unthrottlingEvents)911 abstract Builder setUnthrottlingEvents(List<Integer> unthrottlingEvents); 912 setNumAttemptsPerFqdn(Integer numAttemptsPerFqdn)913 abstract Builder setNumAttemptsPerFqdn(Integer numAttemptsPerFqdn); 914 setHandoverAttemptCount(Integer handoverAttemptCount)915 abstract Builder setHandoverAttemptCount(Integer handoverAttemptCount); 916 build()917 abstract ErrorPolicy build(); 918 } 919 getRetryTime(int index)920 long getRetryTime(int index) { 921 long retryTime = -1; 922 if (retryArray().size() > 0) { 923 // If the index is greater than or equal to the last element's index 924 // and if the last item in the retryArray is "-1" use the retryTime 925 // of the element before the last element to repeat the element. 926 if (infiniteRetriesWithLastRetryTime()) { 927 index = Math.min(index, retryArray().size() - 2); 928 } 929 if (index >= 0 && index < retryArray().size()) { 930 retryTime = retryArray().get(index); 931 } 932 } 933 934 // retryTime -1 represents indefinite failure. In that case 935 // return time that represents 1 day to not retry for that day. 936 if (retryTime == -1L) { 937 retryTime = TimeUnit.DAYS.toSeconds(1); 938 } 939 return retryTime; 940 } 941 getCurrentFqdnIndex(int retryIndex, int numFqdns)942 int getCurrentFqdnIndex(int retryIndex, int numFqdns) { 943 int result = -1; 944 if (numAttemptsPerFqdn().isEmpty() || retryArray().size() <= 0) { 945 return result; 946 } 947 // Cycles between 0 and (numFqdns - 1), based on the current attempt count and size of 948 // mRetryArray. 949 return (retryIndex + 1) / numAttemptsPerFqdn().get() % numFqdns; 950 } 951 952 @ErrorPolicyErrorType getErrorType()953 int getErrorType() { 954 return errorType(); 955 } 956 getHandoverAttemptCount()957 int getHandoverAttemptCount() { 958 return handoverAttemptCount().orElse(Integer.MAX_VALUE); 959 } 960 canUnthrottle(int event)961 synchronized boolean canUnthrottle(int event) { 962 return unthrottlingEvents().contains(event); 963 } 964 match(IwlanError iwlanError)965 boolean match(IwlanError iwlanError) { 966 // Generic by default to match to generic policy. 967 String iwlanErrorDetail; 968 if (errorType() == FALLBACK_ERROR_TYPE) { 969 return true; 970 } else if (errorType() == IKE_PROTOCOL_ERROR_TYPE 971 && iwlanError.getErrorType() == IwlanError.IKE_PROTOCOL_EXCEPTION) { 972 IkeProtocolException exception = (IkeProtocolException) iwlanError.getException(); 973 iwlanErrorDetail = String.valueOf(exception.getErrorType()); 974 } else if (errorType() == GENERIC_ERROR_TYPE) { 975 iwlanErrorDetail = getGenericErrorDetailString(iwlanError); 976 if (iwlanErrorDetail.equals("UNKNOWN")) { 977 return false; 978 } 979 } else { 980 return false; 981 } 982 983 boolean ret = false; 984 for (String errorDetail : errorDetails()) { 985 if (errorType() == IKE_PROTOCOL_ERROR_TYPE 986 && iwlanError.getErrorType() == IwlanError.IKE_PROTOCOL_EXCEPTION 987 && errorDetail.contains("-")) { 988 // error detail is stored in range format. 989 // ErrorPolicyManager#verifyIkeProtocolErrorDetail will make sure that 990 // this is stored correctly in "min-max" format. 991 String[] range = errorDetail.split("-"); 992 int min = Integer.parseInt(range[0]); 993 int max = Integer.parseInt(range[1]); 994 int error = Integer.parseInt(iwlanErrorDetail); 995 if (error >= min && error <= max) { 996 ret = true; 997 break; 998 } 999 } else if (errorDetail.equals(iwlanErrorDetail) || errorDetail.equals("*")) { 1000 ret = true; 1001 break; 1002 } 1003 } 1004 return ret; 1005 } 1006 log()1007 void log() { 1008 Log.d(LOG_TAG, "ErrorType: " + errorType()); 1009 Log.d(LOG_TAG, "ErrorDetail: " + Arrays.toString(errorDetails().toArray())); 1010 Log.d(LOG_TAG, "RetryArray: " + Arrays.toString(retryArray().toArray())); 1011 Log.d( 1012 LOG_TAG, 1013 "InfiniteRetriesWithLastRetryTime: " + infiniteRetriesWithLastRetryTime()); 1014 Log.d( 1015 LOG_TAG, 1016 "UnthrottlingEvents: " + Arrays.toString(unthrottlingEvents().toArray())); 1017 Log.d(LOG_TAG, "NumAttemptsPerFqdn: " + numAttemptsPerFqdn()); 1018 Log.d(LOG_TAG, "handoverAttemptCount: " + handoverAttemptCount()); 1019 } 1020 isFallback()1021 boolean isFallback() { 1022 return (errorType() == FALLBACK_ERROR_TYPE) 1023 || (errorDetails().size() == 1 && errorDetails().get(0).equals("*")); 1024 } 1025 getGenericErrorDetailString(IwlanError iwlanError)1026 String getGenericErrorDetailString(IwlanError iwlanError) { 1027 String ret = "UNKNOWN"; 1028 switch (iwlanError.getErrorType()) { 1029 case IwlanError.IKE_INTERNAL_IO_EXCEPTION: 1030 ret = "IO_EXCEPTION"; 1031 break; 1032 case IwlanError.EPDG_SELECTOR_SERVER_SELECTION_FAILED: 1033 ret = "SERVER_SELECTION_FAILED"; 1034 break; 1035 case IwlanError.TUNNEL_TRANSFORM_FAILED: 1036 ret = "TUNNEL_TRANSFORM_FAILED"; 1037 break; 1038 case IwlanError.IKE_NETWORK_LOST_EXCEPTION: 1039 ret = "IKE_NETWORK_LOST_EXCEPTION"; 1040 break; 1041 case IwlanError.EPDG_ADDRESS_ONLY_IPV4_ALLOWED: 1042 ret = "EPDG_ADDRESS_ONLY_IPV4_ALLOWED"; 1043 break; 1044 case IwlanError.EPDG_ADDRESS_ONLY_IPV6_ALLOWED: 1045 ret = "EPDG_ADDRESS_ONLY_IPV6_ALLOWED"; 1046 break; 1047 // TODO: Add TIMEOUT_EXCEPTION processing 1048 case IwlanError.IKE_INIT_TIMEOUT: 1049 ret = "IKE_INIT_TIMEOUT"; 1050 break; 1051 case IwlanError.IKE_MOBILITY_TIMEOUT: 1052 ret = "IKE_MOBILITY_TIMEOUT"; 1053 break; 1054 case IwlanError.IKE_DPD_TIMEOUT: 1055 ret = "IKE_DPD_TIMEOUT"; 1056 break; 1057 } 1058 return ret; 1059 } 1060 } 1061 1062 class ErrorInfo { 1063 IwlanError mError; 1064 ErrorPolicy mErrorPolicy; 1065 1066 // For the lifetime of the ErrorInfo object, this is a monotonically incremented value that 1067 // can go beyond the size of mErrorPolicy's mRetryArray. 1068 int mCurrentRetryIndex; 1069 long mLastErrorTime; 1070 boolean mIsBackOffTimeValid; 1071 long mBackOffTime; 1072 ErrorInfo(IwlanError error, ErrorPolicy errorPolicy)1073 ErrorInfo(IwlanError error, ErrorPolicy errorPolicy) { 1074 mError = error; 1075 mErrorPolicy = errorPolicy; 1076 mCurrentRetryIndex = -1; 1077 mLastErrorTime = IwlanHelper.elapsedRealtime(); 1078 } 1079 ErrorInfo(IwlanError error, ErrorPolicy errorPolicy, long backOffTime)1080 ErrorInfo(IwlanError error, ErrorPolicy errorPolicy, long backOffTime) { 1081 mError = error; 1082 mErrorPolicy = errorPolicy; 1083 mCurrentRetryIndex = -1; 1084 mIsBackOffTimeValid = true; 1085 mBackOffTime = backOffTime; 1086 mLastErrorTime = IwlanHelper.elapsedRealtime(); 1087 } 1088 getCurrentRetryIndex()1089 int getCurrentRetryIndex() { 1090 return mCurrentRetryIndex; 1091 } 1092 setCurrentRetryIndex(int currentRetryIndex)1093 void setCurrentRetryIndex(int currentRetryIndex) { 1094 mCurrentRetryIndex = currentRetryIndex; 1095 } 1096 1097 /** 1098 * Updates the current retry index and returns the retry time at new index position and also 1099 * updates mLastErrorTime to current time. returns -1 if the index is out of bounds 1100 */ updateCurrentRetryTime()1101 long updateCurrentRetryTime() { 1102 if (mErrorPolicy == null) { 1103 return -1; 1104 } 1105 long time = mErrorPolicy.getRetryTime(++mCurrentRetryIndex); 1106 mLastErrorTime = IwlanHelper.elapsedRealtime(); 1107 Log.d(LOG_TAG, "Current RetryArray index: " + mCurrentRetryIndex + " time: " + time); 1108 return time; 1109 } 1110 1111 /** 1112 * Return the current retry time without changing the index. returns -1 if the index is out 1113 * of bounds. 1114 */ getCurrentRetryTime()1115 long getCurrentRetryTime() { 1116 long time = -1; 1117 1118 if (mIsBackOffTimeValid) { 1119 time = TimeUnit.SECONDS.toMillis(mBackOffTime); 1120 } else if (mErrorPolicy == null) { 1121 return time; 1122 } else { 1123 time = TimeUnit.SECONDS.toMillis(mErrorPolicy.getRetryTime(mCurrentRetryIndex)); 1124 } 1125 long currentTime = IwlanHelper.elapsedRealtime(); 1126 time = Math.max(0, time - (currentTime - mLastErrorTime)); 1127 Log.d( 1128 LOG_TAG, 1129 "Current RetryArray index: " + mCurrentRetryIndex + " and time: " + time); 1130 return time; 1131 } 1132 getCurrentFqdnIndex(int numFqdns)1133 int getCurrentFqdnIndex(int numFqdns) { 1134 ErrorPolicy errorPolicy = getErrorPolicy(); 1135 return errorPolicy.getCurrentFqdnIndex(mCurrentRetryIndex, numFqdns); 1136 } 1137 isBackOffTimeValid()1138 boolean isBackOffTimeValid() { 1139 return mIsBackOffTimeValid; 1140 } 1141 setBackOffTime(long backOffTime)1142 void setBackOffTime(long backOffTime) { 1143 mBackOffTime = backOffTime; 1144 mLastErrorTime = IwlanHelper.elapsedRealtime(); 1145 } 1146 canBringUpTunnel()1147 boolean canBringUpTunnel() { 1148 long retryTime; 1149 boolean ret = true; 1150 1151 if (mIsBackOffTimeValid) { 1152 retryTime = TimeUnit.SECONDS.toMillis(mBackOffTime); 1153 } else if (mErrorPolicy == null) { 1154 return ret; 1155 } else { 1156 retryTime = 1157 TimeUnit.SECONDS.toMillis(mErrorPolicy.getRetryTime(mCurrentRetryIndex)); 1158 } 1159 long currentTime = IwlanHelper.elapsedRealtime(); 1160 long timeDifference = currentTime - mLastErrorTime; 1161 if (timeDifference < retryTime) { 1162 ret = false; 1163 } 1164 return ret; 1165 } 1166 shouldRetryWithInitialAttach()1167 boolean shouldRetryWithInitialAttach() { 1168 // UE should only uses initial attach to reset network failure, not for UE internal or 1169 // DNS errors. When the number of handover failures due to network issues exceeds the 1170 // configured threshold, UE should request network with initial attach instead of 1171 // handover request. 1172 return mErrorPolicy.getErrorType() == IKE_PROTOCOL_ERROR_TYPE 1173 && mCurrentRetryIndex + 1 >= mErrorPolicy.getHandoverAttemptCount(); 1174 } 1175 getErrorPolicy()1176 ErrorPolicy getErrorPolicy() { 1177 return mErrorPolicy; 1178 } 1179 getError()1180 IwlanError getError() { 1181 return mError; 1182 } 1183 } 1184 1185 static class ApnWithIwlanError { 1186 @NonNull final String mApn; 1187 @NonNull final IwlanError mIwlanError; 1188 ApnWithIwlanError(@onNull String apn, @NonNull IwlanError iwlanError)1189 ApnWithIwlanError(@NonNull String apn, @NonNull IwlanError iwlanError) { 1190 mApn = apn; 1191 mIwlanError = iwlanError; 1192 } 1193 } 1194 isValidCarrierConfigChangedEvent(int currentCarrierId)1195 private boolean isValidCarrierConfigChangedEvent(int currentCarrierId) { 1196 String errorPolicyConfig = 1197 IwlanHelper.getConfig(KEY_ERROR_POLICY_CONFIG_STRING, mContext, mSlotId); 1198 return (currentCarrierId != carrierId) 1199 || (mCarrierConfigErrorPolicyString == null) 1200 || (errorPolicyConfig != null 1201 && !Objects.equals(mCarrierConfigErrorPolicyString, errorPolicyConfig)); 1202 } 1203 1204 private final class EpmHandler extends Handler { 1205 private final String TAG = EpmHandler.class.getSimpleName(); 1206 1207 @Override handleMessage(Message msg)1208 public void handleMessage(Message msg) { 1209 Log.d(TAG, "msg.what = " + msg.what); 1210 switch (msg.what) { 1211 case IwlanEventListener.CARRIER_CONFIG_CHANGED_EVENT: 1212 Log.d(TAG, "On CARRIER_CONFIG_CHANGED_EVENT"); 1213 int currentCarrierId = IwlanHelper.getCarrierId(mContext, mSlotId); 1214 if (isValidCarrierConfigChangedEvent(currentCarrierId)) { 1215 Log.d(TAG, "Unthrottle last error and read from carrier config"); 1216 unthrottleLastErrorOnEvent(IwlanEventListener.CARRIER_CONFIG_CHANGED_EVENT); 1217 readFromCarrierConfig(currentCarrierId); 1218 updateUnthrottlingEvents(); 1219 } 1220 break; 1221 case IwlanEventListener.APM_ENABLE_EVENT: 1222 case IwlanEventListener.APM_DISABLE_EVENT: 1223 case IwlanEventListener.WIFI_DISABLE_EVENT: 1224 case IwlanEventListener.WIFI_CALLING_DISABLE_EVENT: 1225 unthrottleLastErrorOnEvent(msg.what); 1226 break; 1227 default: 1228 Log.d(TAG, "Unknown message received!"); 1229 break; 1230 } 1231 } 1232 EpmHandler(Looper looper)1233 EpmHandler(Looper looper) { 1234 super(looper); 1235 } 1236 } 1237 1238 @VisibleForTesting 1239 static class ErrorStats { 1240 @VisibleForTesting Map<String, Map<String, Long>> mStats = new HashMap<>(); 1241 private Date mStartTime; 1242 private int mStatCount; 1243 private static final int APN_COUNT_MAX = 10; 1244 private static final int ERROR_COUNT_MAX = 1000; 1245 ErrorStats()1246 ErrorStats() { 1247 mStartTime = Calendar.getInstance().getTime(); 1248 mStatCount = 0; 1249 } 1250 update(String apn, IwlanError error)1251 void update(String apn, IwlanError error) { 1252 if (mStats.size() >= APN_COUNT_MAX || mStatCount >= ERROR_COUNT_MAX) { 1253 reset(); 1254 } 1255 if (!mStats.containsKey(apn)) { 1256 mStats.put(apn, new HashMap<>()); 1257 } 1258 Map<String, Long> errorMap = mStats.get(apn); 1259 String errorString = error.toString(); 1260 if (!errorMap.containsKey(errorString)) { 1261 errorMap.put(errorString, 0L); 1262 } 1263 long count = errorMap.get(errorString); 1264 errorMap.put(errorString, ++count); 1265 mStats.put(apn, errorMap); 1266 mStatCount++; 1267 } 1268 reset()1269 void reset() { 1270 mStartTime = Calendar.getInstance().getTime(); 1271 mStats = new HashMap<>(); 1272 mStatCount = 0; 1273 } 1274 1275 @Override toString()1276 public String toString() { 1277 StringBuilder sb = new StringBuilder(); 1278 sb.append("mStartTime: ").append(mStartTime); 1279 sb.append("\nErrorStats"); 1280 for (Map.Entry<String, Map<String, Long>> entry : mStats.entrySet()) { 1281 sb.append("\n\tApn: ").append(entry.getKey()); 1282 for (Map.Entry<String, Long> errorEntry : entry.getValue().entrySet()) { 1283 sb.append("\n\t ") 1284 .append(errorEntry.getKey()) 1285 .append(" : ") 1286 .append(errorEntry.getValue()); 1287 } 1288 } 1289 return sb.toString(); 1290 } 1291 } 1292 } 1293