Add a retry mechanism to retrieve access rules again depending on the status words

Bug: 144442533
Test: Unit test & Manual test
Change-Id: I3e8b9cb91cfb00a6a0b309449cd63c1552ab3120
diff --git a/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java b/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java
index 2585e26..114447f 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java
@@ -114,6 +114,8 @@
     // Max number of retries for open logical channel, interval is 10s.
     private static final int MAX_RETRY = 1;
     private static final int RETRY_INTERVAL_MS = 10000;
+    private static final int STATUS_CODE_CONDITION_NOT_SATISFIED = 0x6985;
+    private static final int STATUS_CODE_APPLET_SELECT_FAILED = 0x6999;
 
     // Used for parsing the data from the UICC.
     public static class TLV {
@@ -426,6 +428,30 @@
         return null;
     }
 
+    /**
+     * The following three situations could be due to logical channels temporarily unavailable, so
+     * we retry up to MAX_RETRY times, with an interval of RETRY_INTERVAL_MS: 1. MISSING_RESOURCE,
+     * 2. NO_SUCH_ELEMENT and the status code is 6985, 3. INTERNAL_ERR and the status code is 6999.
+     */
+    public static boolean shouldRetry(AsyncResult ar, int retryCount) {
+        if (ar.exception instanceof CommandException && retryCount < MAX_RETRY) {
+            CommandException.Error error = ((CommandException) (ar.exception)).getCommandError();
+            int[] results = (int[]) ar.result;
+            int statusCode = 0;
+            if (results.length == 3) {
+                byte[] bytes = new byte[]{(byte) results[1], (byte) results[2]};
+                statusCode = Integer.parseInt(IccUtils.bytesToHexString(bytes), 16);
+                log("status code: " + String.valueOf(statusCode));
+            }
+            return (error == CommandException.Error.MISSING_RESOURCE)
+                            || (error == CommandException.Error.NO_SUCH_ELEMENT
+                    && statusCode == STATUS_CODE_CONDITION_NOT_SATISFIED)
+                            || (error == CommandException.Error.INTERNAL_ERR
+                    && statusCode == STATUS_CODE_APPLET_SELECT_FAILED);
+        }
+        return false;
+    }
+
     @Override
     public void handleMessage(Message msg) {
         AsyncResult ar;
@@ -442,11 +468,8 @@
                             DATA, obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE, mChannelId,
                                     mAIDInUse));
                 } else {
-                    // MISSING_RESOURCE could be due to logical channels temporarily unavailable,
-                    // so we retry up to MAX_RETRY times, with an interval of RETRY_INTERVAL_MS.
-                    if (ar.exception instanceof CommandException && mRetryCount < MAX_RETRY
-                            && ((CommandException) (ar.exception)).getCommandError()
-                            == CommandException.Error.MISSING_RESOURCE) {
+                    if (shouldRetry(ar, mRetryCount)) {
+                        log("should retry");
                         mRetryCount++;
                         removeCallbacks(mRetryRunnable);
                         postDelayed(mRetryRunnable, RETRY_INTERVAL_MS);
@@ -745,4 +768,4 @@
                 return "UNKNOWN";
         }
     }
-}
+}
\ No newline at end of file
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRulesTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRulesTest.java
index 5edb2d8..4e56d3e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRulesTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRulesTest.java
@@ -30,6 +30,7 @@
 import android.os.Message;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import com.android.internal.telephony.CommandException;
 import com.android.internal.telephony.TelephonyTest;
 
 import org.junit.After;
@@ -299,6 +300,38 @@
         assertEquals(0, mUiccCarrierPrivilegeRules.getPackageNames().size());
     }
 
+    @Test
+    @SmallTest
+    public void testRetryARAM_shouldRetry() {
+        AsyncResult ar1 = new AsyncResult(
+                null,
+                new int[]{0, 105, -123},
+                new CommandException(CommandException.Error.NO_SUCH_ELEMENT));
+        assertTrue(mUiccCarrierPrivilegeRules.shouldRetry(ar1, 0));
+
+        AsyncResult ar2 = new AsyncResult(
+                null,
+                new int[]{0},
+                new CommandException(CommandException.Error.MISSING_RESOURCE));
+        assertTrue(mUiccCarrierPrivilegeRules.shouldRetry(ar2, 0));
+
+        AsyncResult ar3 = new AsyncResult(
+                null,
+                new int[]{0, 105, 153},
+                new CommandException(CommandException.Error.INTERNAL_ERR));
+        assertTrue(mUiccCarrierPrivilegeRules.shouldRetry(ar3, 0));
+    }
+
+    @Test
+    @SmallTest
+    public void testRetryARAM_shouldNotRetry() {
+        AsyncResult ar = new AsyncResult(
+                null,
+                new int[]{0, 106, -126},
+                new CommandException(CommandException.Error.NO_SUCH_ELEMENT));
+        assertTrue(!mUiccCarrierPrivilegeRules.shouldRetry(ar, 0));
+    }
+
     private static final String ARAM = "A00000015141434C00";
     private static final String ARAD = "A00000015144414300";
     private static final String PKCS15_AID = "A000000063504B43532D3135";