summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/com/android/nfc/RoutingTableParser.java284
-rw-r--r--tests/unit/src/com/android/nfc/NfcRoutingTableParseTest.java267
2 files changed, 472 insertions, 79 deletions
diff --git a/src/com/android/nfc/RoutingTableParser.java b/src/com/android/nfc/RoutingTableParser.java
index d2c7f1ad..9174c244 100644
--- a/src/com/android/nfc/RoutingTableParser.java
+++ b/src/com/android/nfc/RoutingTableParser.java
@@ -17,10 +17,12 @@
package com.android.nfc;
import android.os.SystemProperties;
-import java.util.Locale;
import android.util.Log;
import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.Vector;
/**
* Parse the Routing Table from the last backup lmrt cmd and dump it with a clear typography
@@ -28,57 +30,92 @@ import java.io.PrintWriter;
public class RoutingTableParser {
static final boolean DBG = SystemProperties.getBoolean("persist.nfc.debug_enabled", false);
private static final String TAG = "RoutingTableParser";
+ private static int sRoutingTableSize = 0;
+ private static int sRoutingTableMaxSize = 0;
+ private static Vector<RoutingEntryInfo> sRoutingTable = new Vector<RoutingEntryInfo>(0);
+
+ // Entry types
+ static final byte TYPE_TECHNOLOGY = 0;
+ static final byte TYPE_PROTOCOL = 1;
+ static final byte TYPE_AID = 2;
+ static final byte TYPE_SYSTEMCODE = 3;
+ static final byte TYPE_UNSUPPORTED = 4;
+
+ // Commit status
+ static final int STATS_HOST_OK = 0;
+ static final int STATS_OFFHOST_OK = 1;
+ static final int STATS_NOT_FOUND = 2;
- private String getTechStr(int value) {
+ private interface GetEntryStr {
+ String getEntryStr(byte[] entry);
+ }
+
+ private GetEntryStr[] mGetEntryStrFuncs = new GetEntryStr[] {
+ new GetEntryStr() { public String getEntryStr(byte[] entry) {
+ return getTechStr(entry); } },
+ new GetEntryStr() { public String getEntryStr(byte[] entry) {
+ return getProtoStr(entry); } },
+ new GetEntryStr() { public String getEntryStr(byte[] entry) {
+ return getAidStr(entry); } },
+ new GetEntryStr() { public String getEntryStr(byte[] entry) {
+ return getSystemCodeStr(entry); } },
+ };
+
+ private String getTechStr(byte[] tech) {
String[] tech_mask_list = {
"TECHNOLOGY_A", "TECHNOLOGY_B", "TECHNOLOGY_F", "TECHNOLOGY_V"
};
- if (value > tech_mask_list.length) {
+ if (tech[0] > tech_mask_list.length) {
return "UNSUPPORTED_TECH";
}
- return tech_mask_list[value];
+ return tech_mask_list[tech[0]];
}
- private String getProtoStr(int value) {
+ private String getProtoStr(byte[] proto) {
String[] proto_mask_list = {
"PROTOCOL_UNDETERMINED", "PROTOCOL_T1T", "PROTOCOL_T2T", "PROTOCOL_T3T",
"PROTOCOL_ISO_DEP", "PROTOCOL_NFC_DEP", "PROTOCOL_T5T", "PROTOCOL_NDEF"
};
- if (value > proto_mask_list.length) {
+ if (proto[0] > proto_mask_list.length) {
return "UNSUPPORTED_PROTO";
}
- return proto_mask_list[value];
+ return proto_mask_list[proto[0]];
}
- private String getAidStr(byte[] rt, int offset, int aidLen) {
- String Aid = "";
- for (int i = 0; i < aidLen; i++) {
- Aid += String.format("%02X", rt[offset + i]);
+ private String getAidStr(byte[] aid) {
+ String aidStr = "";
+
+ for (byte b : aid) {
+ aidStr += String.format("%02X", b);
}
- if (Aid.length() == 0) {
+ if (aidStr.length() == 0) {
return "Empty_AID";
}
- return "AID_" + Aid;
+ return "AID_" + aidStr;
}
- private String getSystemCodeStr(byte[] rt, int offset, int scLen) {
- String SystemCode = "";
- for (int i = 0; i < scLen; i++) {
- SystemCode += String.format("%02X", rt[offset + i]);
+ private String getSystemCodeStr(byte[] sc) {
+ String systemCodeStr = "";
+ for (byte b : sc) {
+ systemCodeStr += String.format("%02X", b);
}
- return "SYSTEMCODE_" + SystemCode;
+ return "SYSTEMCODE_" + systemCodeStr;
}
- private String getBlockCtrlStr(int mask) {
+ private String getBlockCtrlStr(byte mask) {
if ((mask & 0x40) != 0) {
return "True";
}
return "False";
}
- private String getPrefixSubsetStr(int mask) {
+ private String getPrefixSubsetStr(byte mask, byte type) {
+ if (type != TYPE_AID) {
+ return "";
+ }
+
String prefix_subset_str = "";
if ((mask & 0x10) != 0) {
prefix_subset_str += "Prefix ";
@@ -98,84 +135,172 @@ public class RoutingTableParser {
return String.format(fmt, entry, eeId, pwrState, blkCtrl, extra);
}
- private void dumpTechEntry(byte[] rt, int rtSize, PrintWriter pw, int offset) {
- if (offset + 4 >= rtSize) return;
+ private class RoutingEntryInfo {
+ public final byte mQualifier;
+ public final byte mType;
+ public final byte mNfceeId;
+ public final byte mPowerState;
+ public final byte[] mEntry;
+
+ private RoutingEntryInfo(byte qualifier, byte type, byte eeId, byte pwrState,
+ byte[] entry) {
+ mQualifier = qualifier;
+ mType = type;
+ mNfceeId = eeId;
+ mPowerState = pwrState;
+ mEntry = entry;
+ }
- String blkCtrl = getBlockCtrlStr(rt[offset] & 0xF0);
- String eeId = String.format("0x%02X", rt[offset + 2]);
- String pwrState = String.format("0x%02X", rt[offset + 3]);
- String entry = getTechStr(rt[offset + 4]);
+ private void dump(PrintWriter pw) {
+ String blkCtrl = getBlockCtrlStr(mQualifier);
+ String eeId = String.format("0x%02X", mNfceeId);
+ String pwrState = String.format("0x%02X", mPowerState);
+ String entry = mGetEntryStrFuncs[mType].getEntryStr(mEntry);
+ String extra = getPrefixSubsetStr(mQualifier, mType);
- pw.println(formatRow(entry, eeId, pwrState, blkCtrl, ""));
+ pw.println(formatRow(entry, eeId, pwrState, blkCtrl, extra));
+ }
}
- private void dumpProtoEntry(byte[] rt, int rtSize, PrintWriter pw, int offset) {
- if (offset + 4 >= rtSize) return;
+ private boolean validateEntryInfo(byte type, byte[] entry) {
+ switch(type) {
+ case TYPE_TECHNOLOGY:
+ if (entry.length != 1) return false;
+ break;
+ case TYPE_PROTOCOL:
+ if (entry.length != 1) return false;
+ break;
+ case TYPE_AID:
+ if (entry.length > 16) return false;
+ break;
+ case TYPE_SYSTEMCODE:
+ if (entry.length != 2) return false;
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
- String blkCtrl = getBlockCtrlStr(rt[offset] & 0xF0);
- String eeId = String.format("0x%02X", rt[offset + 2]);
- String pwrState = String.format("0x%02X", rt[offset + 3]);
- String entry = getProtoStr(rt[offset + 4]);
+ /**
+ * Check commit status by inputting type and entry
+ */
+ public int getCommitStatus(byte type, byte[] entry) {
+ if (!validateEntryInfo(type, entry)) return STATS_NOT_FOUND;
- pw.println(formatRow(entry, eeId, pwrState, blkCtrl, ""));
+ for (RoutingEntryInfo routingEntry : sRoutingTable) {
+ if (routingEntry.mType != type) {
+ continue;
+ }
+ if (Arrays.equals(routingEntry.mEntry, entry)) {
+ return routingEntry.mNfceeId == 0x00 ? STATS_HOST_OK : STATS_OFFHOST_OK;
+ }
+ if (routingEntry.mType != TYPE_AID) {
+ continue;
+ }
+ if ((routingEntry.mQualifier & 0x10) != 0
+ && entry.length > routingEntry.mEntry.length) {
+ int ptr = 0;
+ while (entry[ptr] == routingEntry.mEntry[ptr]) {
+ ptr += 1;
+ }
+ if (ptr == routingEntry.mEntry.length) {
+ return routingEntry.mNfceeId == 0x00 ? STATS_HOST_OK : STATS_OFFHOST_OK;
+ }
+ }
+ if ((routingEntry.mQualifier & 0x20) != 0
+ && entry.length < routingEntry.mEntry.length) {
+ int ptr = 0;
+ while (entry[ptr] == routingEntry.mEntry[ptr]) {
+ ptr += 1;
+ }
+ if (ptr == entry.length) {
+ return routingEntry.mNfceeId == 0x00 ? STATS_HOST_OK : STATS_OFFHOST_OK;
+ }
+ }
+ }
+ return STATS_NOT_FOUND;
}
- private void dumpAidEntry(byte[] rt, int rtSize, PrintWriter pw, int offset) {
- if (offset + 4 + rt[offset + 1] - 2 >= rtSize) return;
+ private void addRoutingEntry(byte[] rt, int offset) {
+ if (offset + 1 >= rt.length) return;
+ int valueLength = rt[offset + 1];
+
+ // Qualifier-Type(1 byte) + Length(1 byte) + Value(valueLength bytes)
+ if (offset + 2 + valueLength > rt.length) return;
- String blkCtrl = getBlockCtrlStr(rt[offset] & 0xF0);
- String extra = getPrefixSubsetStr(rt[offset] & 0xF0);
- String eeId = String.format("0x%02X", rt[offset + 2]);
- String pwrState = String.format("0x%02X", rt[offset + 3]);
- String entry = getAidStr(rt, offset + 4, rt[offset + 1] - 2);
+ byte qualifier = (byte) (rt[offset] & 0xF0);
+ byte type = (byte) (rt[offset] & 0x0F);
+ byte eeId = rt[offset + 2];
+ byte pwrState = rt[offset + 3];
+ byte[] entry = new byte[valueLength - 2];
+ for (int i = 0; i < valueLength - 2; i++) {
+ entry[i] = rt[offset + 4 + i];
+ }
- pw.println(formatRow(entry, eeId, pwrState, blkCtrl, extra));
+ if (type == TYPE_SYSTEMCODE && (entry.length & 1) == 0 && entry.length <= 64) {
+ for (int i = 0; i < entry.length; i += 2) {
+ byte[] sc_entry = {entry[i], entry[i + 1]};
+ sRoutingTable.add(new RoutingEntryInfo(qualifier, type, eeId, pwrState, sc_entry));
+ }
+ } else if (validateEntryInfo(type, entry)) {
+ sRoutingTable.add(new RoutingEntryInfo(qualifier, type, eeId, pwrState, entry));
+ }
}
- private void dumpSystemEntry(byte[] rt, int rtSize, PrintWriter pw, int offset) {
- if (offset + 4 + rt[offset + 1] - 2 >= rtSize) return;
+ /**
+ * Parse the raw data of routing table
+ */
+ public void parse(byte[] rt) {
+ int offset = 0;
+
+ logRoutingTableRawData(rt);
+
+ sRoutingTable.clear();
+ while (offset < rt.length) {
+ byte type = (byte) (rt[offset] & 0x0F);
+ if (type >= TYPE_UNSUPPORTED) {
+ // Unrecognizable entry type
+ Log.e(TAG, String.format("Unrecognizable entry type: 0x%02X, stop parsing", type));
+ return;
+ }
+ if (offset + 1 >= rt.length) {
+ // Buffer overflow
+ Log.e(TAG, String.format("Wrong tlv length, stop parsing"));
+ return;
+ }
+ // Qualifier-Type(1 byte) + Length(1 byte) + Value(valueLength bytes)
+ int tlvLength = rt[offset + 1] + 2;
- String blkCtrl = getBlockCtrlStr(rt[offset] & 0xF0);
- String eeId = String.format("0x%02X", rt[offset + 2]);
- String pwrState = String.format("0x%02X", rt[offset + 3]);
- String entry = getSystemCodeStr(rt, offset + 4, rt[offset + 1] - 2);
+ addRoutingEntry(rt, offset);
- pw.println(formatRow(entry, eeId, pwrState, blkCtrl, ""));
+ offset += tlvLength;
+ }
}
/**
- * Get Routing Table from the last backup lmrt cmd and dump it
+ * Get Routing Table from the last backup lmrt cmd and parse it
*/
- public void dump(DeviceHost dh, PrintWriter pw) {
- int offset = 0;
+ public void update(DeviceHost dh) {
+ sRoutingTableMaxSize = dh.getMaxRoutingTableSize();
byte[] rt = dh.getRoutingTable();
- int maxSize = dh.getMaxRoutingTableSize();
+ sRoutingTableSize = rt.length;
+ parse(rt);
+ }
- logRoutingTableRawData(rt);
+ /**
+ * Get Routing Table from the last backup lmrt cmd and dump it
+ */
+ public void dump(DeviceHost dh, PrintWriter pw) {
+ update(dh);
pw.println("--- dumpRoutingTable: start ---");
- pw.println(String.format(Locale.US, "RoutingTableSize: %d/%d", rt.length, maxSize));
+ pw.println(String.format(Locale.US, "RoutingTableSize: %d/%d",
+ sRoutingTableSize, sRoutingTableMaxSize));
pw.println(formatRow("Entry", "NFCEE_ID", "Power State", "Block Ctrl", "Extra Info"));
- while (offset < rt.length) {
- int type = rt[offset] & 0x0F;
- if (type == 0x00) {
- // Technology-based routing entry
- dumpTechEntry(rt, rt.length, pw, offset);
- } else if (type == 0x01) {
- // Protocol-based routing entry
- dumpProtoEntry(rt, rt.length, pw, offset);
- } else if (type == 0x02) {
- // AID-based routing entry
- dumpAidEntry(rt, rt.length, pw, offset);
- } else if (type == 0x03) {
- // System Code-based routing entry
- dumpSystemEntry(rt, rt.length, pw, offset);
- } else {
- // Unrecognizable entry type
- Log.d(TAG, String.format("Unrecognizable entry type: 0x%02X, stop parsing", type));
- break;
- }
- offset += rt[offset+1] + 2;
+
+ for (RoutingEntryInfo routingEntry : sRoutingTable) {
+ routingEntry.dump(pw);
}
pw.println("--- dumpRoutingTable: end ---");
@@ -184,10 +309,11 @@ public class RoutingTableParser {
private void logRoutingTableRawData(byte[] lmrt_cmd) {
if (!DBG) return;
String lmrt_str = "";
- for (int i = 0; i < lmrt_cmd.length; i++) {
- lmrt_str += String.format("%02X ", lmrt_cmd[i]);
+
+ for (byte b : lmrt_cmd) {
+ lmrt_str += String.format("%02X ", b);
}
- Log.d(TAG, String.format("RoutingTableSize: %d", lmrt_cmd.length));
- Log.d(TAG, String.format("RoutingTable: %s", lmrt_str));
+ Log.i(TAG, String.format("RoutingTableSize: %d", lmrt_cmd.length));
+ Log.i(TAG, String.format("RoutingTable: %s", lmrt_str));
}
}
diff --git a/tests/unit/src/com/android/nfc/NfcRoutingTableParseTest.java b/tests/unit/src/com/android/nfc/NfcRoutingTableParseTest.java
new file mode 100644
index 00000000..d435fde0
--- /dev/null
+++ b/tests/unit/src/com/android/nfc/NfcRoutingTableParseTest.java
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.nfc;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public final class NfcRoutingTableParseTest {
+ private static final String TAG = NfcRoutingTableParseTest.class.getSimpleName();
+ private RoutingTableParser mRoutingTableParser;
+
+ // NFCEE-ID
+ static final byte EE_ID_HOST = (byte) 0x00;
+ static final byte EE_ID_UICC = (byte) 0x81;
+ static final byte EE_ID_ESE = (byte) 0x86;
+
+ // Power State Mask
+ static final byte APPLY_ALL = (byte) 0x3F;
+ static final byte SWITCH_ON_SUB_3 = (byte) 0x20;
+ static final byte SWITCH_ON_SUB_2 = (byte) 0x10;
+ static final byte SWITCH_ON_SUB_1 = (byte) 0x08;
+ static final byte BATTERY_OFF = (byte) 0x04;
+ static final byte SWITCH_OFF = (byte) 0x02;
+ static final byte SWITCH_ON = (byte) 0x01;
+
+ @Before
+ public void setUp() {
+ mRoutingTableParser = new RoutingTableParser();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void testParseValidTechnologyEntry() {
+ /**
+ * set qualifier = 0x00 to indicates the routing is allowed for the power modes
+ * where it is not supported
+ */
+ byte qualifier = (byte) 0x00;
+ byte type = RoutingTableParser.TYPE_TECHNOLOGY;
+ byte eeId = EE_ID_HOST;
+ byte pwrState = (byte) (SWITCH_ON_SUB_3 | SWITCH_ON_SUB_2 | SWITCH_ON_SUB_1 | SWITCH_ON);
+ byte[] entry = hexStrToByteArray("01");
+ byte[] rt = generateRoutingEntry(qualifier, type, eeId, pwrState, entry);
+ mRoutingTableParser.parse(rt);
+
+ int ret = mRoutingTableParser.getCommitStatus(type, entry);
+
+ assertThat(ret).isEqualTo(mRoutingTableParser.STATS_HOST_OK);
+ }
+
+ @Test
+ public void testParseInvalidTechnologyEntry() {
+ /**
+ * set qualifier = 0x00 to indicates the routing is allowed for the power modes
+ * where it is not supported
+ */
+ byte qualifier = (byte) 0x00;
+ byte type = RoutingTableParser.TYPE_TECHNOLOGY;
+ byte eeId = EE_ID_HOST;
+ byte pwrState = (byte) (SWITCH_ON_SUB_3 | SWITCH_ON_SUB_2 | SWITCH_ON_SUB_1 | SWITCH_ON);
+ byte[] entry = hexStrToByteArray("0001");
+ byte[] rt = generateRoutingEntry(qualifier, type, eeId, pwrState, entry);
+ mRoutingTableParser.parse(rt);
+
+ int ret = mRoutingTableParser.getCommitStatus(type, entry);
+
+ assertThat(ret).isEqualTo(mRoutingTableParser.STATS_NOT_FOUND);
+ }
+
+ @Test
+ public void testParseValidProtocolEntry() {
+ /**
+ * set qualifier = 0x00 to indicates the routing is allowed for the power modes
+ * where it is not supported
+ */
+ byte qualifier = (byte) 0x00;
+ byte type = RoutingTableParser.TYPE_PROTOCOL;
+ byte eeId = EE_ID_HOST;
+ byte pwrState = SWITCH_ON;
+ byte[] entry = hexStrToByteArray("04");
+ byte[] rt = generateRoutingEntry(qualifier, type, eeId, pwrState, entry);
+ mRoutingTableParser.parse(rt);
+
+ int ret = mRoutingTableParser.getCommitStatus(type, entry);
+
+ assertThat(ret).isEqualTo(mRoutingTableParser.STATS_HOST_OK);
+ }
+
+ @Test
+ public void testParseInvalidProtocolEntry() {
+ /**
+ * set qualifier = 0x00 to indicates the routing is allowed for the power modes
+ * where it is not supported
+ */
+ byte qualifier = (byte) 0x00;
+ byte type = RoutingTableParser.TYPE_PROTOCOL;
+ byte eeId = EE_ID_HOST;
+ byte pwrState = SWITCH_ON;
+ byte[] entry = hexStrToByteArray("0405");
+ byte[] rt = generateRoutingEntry(qualifier, type, eeId, pwrState, entry);
+ mRoutingTableParser.parse(rt);
+
+ int ret = mRoutingTableParser.getCommitStatus(type, entry);
+
+ assertThat(ret).isEqualTo(mRoutingTableParser.STATS_NOT_FOUND);
+ }
+
+ @Test
+ public void testParseValidAidEntry() {
+ /**
+ * set qualifier = 0x40 to indicates the routing is blocked for the power modes
+ * where it is not supported
+ */
+ byte qualifier = (byte) 0x40;
+ byte type = RoutingTableParser.TYPE_AID;
+ byte eeId = EE_ID_UICC;
+ byte pwrState = (byte) (APPLY_ALL ^ BATTERY_OFF);
+ byte[] entry = hexStrToByteArray("6E6663746573743031");
+ byte[] rt = generateRoutingEntry(qualifier, type, eeId, pwrState, entry);
+ mRoutingTableParser.parse(rt);
+
+ int ret = mRoutingTableParser.getCommitStatus(type, entry);
+
+ assertThat(ret).isEqualTo(mRoutingTableParser.STATS_OFFHOST_OK);
+ }
+
+ @Test
+ public void testParseInvalidAidEntry() {
+ /**
+ * set qualifier = 0x40 to indicates the routing is blocked for the power modes
+ * where it is not supported
+ */
+ byte qualifier = (byte) 0x40;
+ byte type = RoutingTableParser.TYPE_AID;
+ byte eeId = EE_ID_UICC;
+ byte pwrState = (byte) (APPLY_ALL ^ BATTERY_OFF);
+ byte[] entry = hexStrToByteArray("6E66637465737430316E6663746573743031");
+ byte[] rt = generateRoutingEntry(qualifier, type, eeId, pwrState, entry);
+ mRoutingTableParser.parse(rt);
+
+ int ret = mRoutingTableParser.getCommitStatus(type, entry);
+
+ assertThat(ret).isEqualTo(mRoutingTableParser.STATS_NOT_FOUND);
+ }
+
+ @Test
+ public void testParseValidSystemCodeEntry() {
+ /**
+ * set qualifier = 0x40 to indicates the routing is blocked for the power modes
+ * where it is not supported
+ */
+ byte qualifier = (byte) 0x40;
+ byte type = RoutingTableParser.TYPE_SYSTEMCODE;
+ byte eeId = EE_ID_ESE;
+ byte pwrState = (byte) (APPLY_ALL ^ BATTERY_OFF);
+ byte[] entry = hexStrToByteArray("FEFE");
+ byte[] rt = generateRoutingEntry(qualifier, type, eeId, pwrState, entry);
+ mRoutingTableParser.parse(rt);
+
+ int ret = mRoutingTableParser.getCommitStatus(type, entry);
+
+ assertThat(ret).isEqualTo(mRoutingTableParser.STATS_OFFHOST_OK);
+ }
+
+ @Test
+ public void testParseSeveralValidSystemCodeEntry() {
+ /**
+ * set qualifier = 0x40 to indicates the routing is blocked for the power modes
+ * where it is not supported
+ */
+ byte qualifier = (byte) 0x40;
+ byte type = RoutingTableParser.TYPE_SYSTEMCODE;
+ byte eeId = EE_ID_ESE;
+ byte pwrState = (byte) (APPLY_ALL ^ BATTERY_OFF);
+ byte[] entry1 = hexStrToByteArray("FEFE");
+ byte[] entry2 = hexStrToByteArray("EEEE");
+ byte[] entryAll = hexStrToByteArray("FEFEEEEE");
+ byte[] rt = generateRoutingEntry(qualifier, type, eeId, pwrState, entryAll);
+ mRoutingTableParser.parse(rt);
+
+ int ret1 = mRoutingTableParser.getCommitStatus(type, entry1);
+ int ret2 = mRoutingTableParser.getCommitStatus(type, entry2);
+
+ assertThat(ret1).isEqualTo(mRoutingTableParser.STATS_OFFHOST_OK);
+ assertThat(ret2).isEqualTo(mRoutingTableParser.STATS_OFFHOST_OK);
+ }
+
+ @Test
+ public void testParseInvalidSystemCodeEntry() {
+ /**
+ * set qualifier = 0x40 to indicates the routing is blocked for the power modes
+ * where it is not supported
+ */
+ byte qualifier = (byte) 0x40;
+ byte type = RoutingTableParser.TYPE_SYSTEMCODE;
+ byte eeId = EE_ID_ESE;
+ byte pwrState = (byte) (APPLY_ALL ^ BATTERY_OFF);
+ byte[] entry = hexStrToByteArray("FEFEFE");
+ byte[] rt = generateRoutingEntry(qualifier, type, eeId, pwrState, entry);
+ mRoutingTableParser.parse(rt);
+
+ int ret = mRoutingTableParser.getCommitStatus(type, entry);
+
+ assertThat(ret).isEqualTo(mRoutingTableParser.STATS_NOT_FOUND);
+ }
+
+ private byte[] generateRoutingEntry(byte qualifier, byte type, byte eeId, byte pwrState,
+ byte[] entry) {
+ int length = 2 + entry.length;
+ byte[] rt = new byte[length + 2];
+ rt[0] = (byte) (qualifier | type);
+ rt[1] = (byte) length;
+ rt[2] = eeId;
+ rt[3] = pwrState;
+
+ for (int i = 0; i < entry.length; i++) {
+ rt[i + 4] = entry[i];
+ }
+
+ return rt;
+ }
+
+ private byte[] hexStrToByteArray(String hexStr) {
+ if (hexStr.length() % 2 != 0) {
+ return new byte[0];
+ }
+
+ char[] hex = hexStr.toCharArray();
+ int length = hexStr.length() / 2;
+ byte[] byteArr = new byte[length];
+ for (int i = 0; i < length; i++) {
+ int high = Character.digit(hex[i * 2], 16);
+ int low = Character.digit(hex[i * 2 + 1], 16);
+ int value = (high << 4) | low;
+
+ if (value > 127) {
+ value -= 256;
+ }
+ byteArr [i] = (byte) value;
+ }
+
+ return byteArr;
+ }
+}