Merge changes from topic "AR-DO combine fix"

* changes:
  Missing APDU access rule attribute shall be solved after the combination
  Missing NFC access rule attribute shall be solved after the combination
  Keep the channel access flag UNDEFINED if APDU-AR-DO is missing
diff --git a/src/com/android/se/security/AccessRuleCache.java b/src/com/android/se/security/AccessRuleCache.java
index 2d3763b..6d854c0 100644
--- a/src/com/android/se/security/AccessRuleCache.java
+++ b/src/com/android/se/security/AccessRuleCache.java
@@ -78,13 +78,17 @@
     private static ChannelAccess mapArDo2ChannelAccess(AR_DO arDo) {
         ChannelAccess channelAccess = new ChannelAccess();
 
+        // Missing access rule attribute shall be interpreted as ALWAYS or NEVER
+        // after the result of the rule conflict resolution and combination is processed.
+        // See Table G-1 in GP SEAC v1.1 Annex G.
+        //
+        // GP SEAC v1.0 also indicates the same rule in Annex D.
+        // Combined rule of APDU (ALWAYS) and NFC (ALWAYS) shall be APDU (ALWAYS) + NFC (ALWAYS).
+
         // check apdu access allowance
         if (arDo.getApduArDo() != null) {
-            // first if there is a rule for access, reset the general deny flag.
-            channelAccess.setAccess(ChannelAccess.ACCESS.ALLOWED, "");
-            channelAccess.setUseApduFilter(false);
-
             if (arDo.getApduArDo().isApduAllowed()) {
+                channelAccess.setAccess(ChannelAccess.ACCESS.ALLOWED, "");
                 // check the apdu filter
                 ArrayList<byte[]> apduHeaders = arDo.getApduArDo().getApduHeaderList();
                 ArrayList<byte[]> filterMasks = arDo.getApduArDo().getFilterMaskList();
@@ -103,10 +107,12 @@
                 }
             } else {
                 // apdu access is not allowed at all.
+                channelAccess.setAccess(ChannelAccess.ACCESS.DENIED,
+                        "NEVER is explicitly specified as the APDU access rule policy");
                 channelAccess.setApduAccess(ChannelAccess.ACCESS.DENIED);
             }
         } else {
-            channelAccess.setAccess(ChannelAccess.ACCESS.DENIED, "No APDU access rule available.!");
+            // It is too early to interpret the missing APDU access rule attribute as NEVER.
         }
 
         // check for NFC Event allowance
@@ -116,9 +122,9 @@
                             ? ChannelAccess.ACCESS.ALLOWED
                             : ChannelAccess.ACCESS.DENIED);
         } else {
-            // GP says that by default NFC should have the same right as for APDU access
-            channelAccess.setNFCEventAccess(channelAccess.getApduAccess());
+            // It is too early to interpret the missing NFC access rule attribute. Keep UNDEFINED.
         }
+
         return channelAccess;
     }
 
@@ -153,72 +159,47 @@
             ChannelAccess ca = mRuleCache.get(refDo);
 
             // if new ac condition is more restrictive then use their settings
+            // DENIED > ALLOWED > UNDEFINED
 
-            if ((channelAccess.getAccess() == ChannelAccess.ACCESS.DENIED)
-                    || (ca.getAccess() == ChannelAccess.ACCESS.DENIED)) {
-                ca.setAccess(ChannelAccess.ACCESS.DENIED, channelAccess.getReason());
-            } else if ((channelAccess.getAccess() == ChannelAccess.ACCESS.UNDEFINED)
-                    && (ca.getAccess() != ChannelAccess.ACCESS.UNDEFINED)) {
-                ca.setAccess(ca.getAccess(), ca.getReason());
-            } else if ((channelAccess.getAccess() != ChannelAccess.ACCESS.UNDEFINED)
-                    && (ca.getAccess() == ChannelAccess.ACCESS.UNDEFINED)) {
-                ca.setAccess(channelAccess.getAccess(), channelAccess.getReason());
-            } else {
-                ca.setAccess(ChannelAccess.ACCESS.ALLOWED, ca.getReason());
+            if (ca.getAccess() != ChannelAccess.ACCESS.DENIED) {
+                if (channelAccess.getAccess() == ChannelAccess.ACCESS.DENIED) {
+                    ca.setAccess(ChannelAccess.ACCESS.DENIED, channelAccess.getReason());
+                } else if (channelAccess.getAccess() == ChannelAccess.ACCESS.ALLOWED) {
+                    ca.setAccess(ChannelAccess.ACCESS.ALLOWED, "");
+                }
             }
 
-            // if new rule says NFC is denied then use it
-            // if current rule as undefined NFC rule then use setting of new rule.
-            // current NFC    new NFC     resulting NFC
-            // UNDEFINED      x           x
-            // ALLOWED        !DENIED     ALLOWED
-            // ALLOWED        DENIED      DENIED
-            // DENIED         !DENIED     DENIED
-            // DENIED         DENIED      DENIED
+            // Only the rule with the highest priority shall be applied if the rules conflict.
+            // NFC (NEVER) > NFC (ALWAYS) > No NFC attribute
 
-            if ((channelAccess.getNFCEventAccess() == ChannelAccess.ACCESS.DENIED)
-                    || (ca.getNFCEventAccess() == ChannelAccess.ACCESS.DENIED)) {
-                ca.setNFCEventAccess(ChannelAccess.ACCESS.DENIED);
-            } else if ((channelAccess.getNFCEventAccess() == ChannelAccess.ACCESS.UNDEFINED)
-                    && (ca.getNFCEventAccess() != ChannelAccess.ACCESS.UNDEFINED)) {
-                ca.setNFCEventAccess(ca.getNFCEventAccess());
-            } else if ((channelAccess.getNFCEventAccess() != ChannelAccess.ACCESS.UNDEFINED)
-                    && (ca.getNFCEventAccess() == ChannelAccess.ACCESS.UNDEFINED)) {
-                ca.setNFCEventAccess(channelAccess.getNFCEventAccess());
-            } else {
-                ca.setNFCEventAccess(ChannelAccess.ACCESS.ALLOWED);
-            }
-            // if new rule says APUD is denied then use it
-            // if current rule as undefined APDU rule then use setting of new rule.
-            // current APDU  new APDU    resulting APDU
-            // UNDEFINED     x           x
-            // ALLOWED       !DENIED     ALLOWED
-            // ALLOWED       DENIED      DENIED
-            // DENIED        !DENIED     DENIED
-            // DENEID        DENIED      DENIED
-
-            if ((channelAccess.getApduAccess() == ChannelAccess.ACCESS.DENIED)
-                    || (ca.getApduAccess() == ChannelAccess.ACCESS.DENIED)) {
-                ca.setApduAccess(ChannelAccess.ACCESS.DENIED);
-            } else if ((channelAccess.getApduAccess() == ChannelAccess.ACCESS.UNDEFINED)
-                    && (ca.getApduAccess() != ChannelAccess.ACCESS.UNDEFINED)) {
-                ca.setApduAccess(ca.getApduAccess());
-            } else if ((channelAccess.getApduAccess() == ChannelAccess.ACCESS.UNDEFINED)
-                    && (ca.getApduAccess() == ChannelAccess.ACCESS.UNDEFINED)
-                    && !channelAccess.isUseApduFilter()) {
-                ca.setApduAccess(ChannelAccess.ACCESS.DENIED);
-            } else if ((channelAccess.getApduAccess() != ChannelAccess.ACCESS.UNDEFINED)
-                    && (ca.getApduAccess() == ChannelAccess.ACCESS.UNDEFINED)) {
-                ca.setApduAccess(channelAccess.getApduAccess());
-            } else {
-                ca.setApduAccess(ChannelAccess.ACCESS.ALLOWED);
+            if (ca.getNFCEventAccess() != ChannelAccess.ACCESS.DENIED) {
+                if (channelAccess.getNFCEventAccess() == ChannelAccess.ACCESS.DENIED) {
+                    ca.setNFCEventAccess(ChannelAccess.ACCESS.DENIED);
+                } else if (channelAccess.getNFCEventAccess() == ChannelAccess.ACCESS.ALLOWED) {
+                    ca.setNFCEventAccess(ChannelAccess.ACCESS.ALLOWED);
+                }
             }
 
-            // put APDU filter together if resulting APDU access is allowed.
-            if ((ca.getApduAccess() == ChannelAccess.ACCESS.ALLOWED)
-                    || (ca.getApduAccess() == ChannelAccess.ACCESS.UNDEFINED)) {
-                Log.i(mTag, "Merged Access Rule:  APDU filter together");
+            // Only the rule with the highest priority shall be applied if the rules conflict.
+            // APDU (NEVER) > APDU (Filter) > APDU (ALWAYS) > No APDU attribute
+
+            if (ca.getApduAccess() != ChannelAccess.ACCESS.DENIED) {
+                if (channelAccess.getApduAccess() == ChannelAccess.ACCESS.DENIED) {
+                    ca.setApduAccess(ChannelAccess.ACCESS.DENIED);
+                } else if (ca.isUseApduFilter() || channelAccess.isUseApduFilter()) {
+                    // In order to differentiate APDU (Filter) from APDU (ALWAYS) clearly,
+                    // check if the combined rule will have APDU filter here
+                    // and avoid changing APDU access from UNDEFINED in APDU (Filter) case.
+                    // APDU filters combination itself will be done in the next process below.
+                } else if (channelAccess.getApduAccess() == ChannelAccess.ACCESS.ALLOWED) {
+                    ca.setApduAccess(ChannelAccess.ACCESS.ALLOWED);
+                }
+            }
+
+            // put APDU filter together if resulting APDU access is not denied.
+            if (ca.getApduAccess() != ChannelAccess.ACCESS.DENIED) {
                 if (channelAccess.isUseApduFilter()) {
+                    Log.i(mTag, "Merged Access Rule:  APDU filter together");
                     ca.setUseApduFilter(true);
                     ApduFilter[] filter = ca.getApduFilter();
                     ApduFilter[] filter2 = channelAccess.getApduFilter();
@@ -264,6 +245,7 @@
                 // All the APDU access requests shall never be allowed in this case.
                 // This missing rule resolution is valid for both ARA and ARF
                 // if the supported GP SEAC version is v1.1 or later.
+                ca.setAccess(ChannelAccess.ACCESS.DENIED, "No APDU access rule is available");
                 ca.setApduAccess(ChannelAccess.ACCESS.DENIED);
             }
             if (ca.getNFCEventAccess() == ChannelAccess.ACCESS.UNDEFINED) {