Merge "Limit the number of outstanding DNS queries by UID"
diff --git a/libbpf/BpfNetworkStats.cpp b/libbpf/BpfNetworkStats.cpp
index acde1e6..446fa2b 100644
--- a/libbpf/BpfNetworkStats.cpp
+++ b/libbpf/BpfNetworkStats.cpp
@@ -44,7 +44,6 @@
 static constexpr uint32_t BPF_OPEN_FLAGS = BPF_F_RDONLY;
 
 int bpfGetUidStatsInternal(uid_t uid, Stats* stats, const base::unique_fd& map_fd) {
-    struct StatsKey nonExistentKey = NONEXISTENT_STATSKEY;
     struct StatsValue dummyValue;
     auto processUidStats = [uid, stats](void *key, const base::unique_fd& map_fd) {
         if (((StatsKey *) key)->uid != uid) {
@@ -59,7 +58,7 @@
         stats->txBytes += statsEntry.txBytes;
         return BPF_CONTINUE;
     };
-    return bpfIterateMap(nonExistentKey, dummyValue, map_fd, processUidStats);
+    return bpfIterateMap(dummyValue, map_fd, processUidStats);
 }
 
 int bpfGetUidStats(uid_t uid, Stats* stats) {
@@ -75,8 +74,7 @@
 int bpfGetIfaceStatsInternal(const char* iface, Stats* stats,
                              const base::unique_fd& ifaceStatsMapFd,
                              const base::unique_fd& ifaceNameMapFd) {
-    uint32_t nonExistentKey = NONEXISTENT_IFACE_STATS_KEY;
-    struct StatsValue dummyValue;
+    uint32_t dummyKey;
     int64_t unknownIfaceBytesTotal = 0;
     stats->tcpRxPackets = -1;
     stats->tcpTxPackets = -1;
@@ -99,7 +97,7 @@
         }
         return BPF_CONTINUE;
     };
-    return bpfIterateMap(nonExistentKey, dummyValue, ifaceStatsMapFd, processIfaceStats);
+    return bpfIterateMap(dummyKey, ifaceStatsMapFd, processIfaceStats);
 }
 
 int bpfGetIfaceStats(const char* iface, Stats* stats) {
@@ -170,8 +168,7 @@
                                        int limitUid, const base::unique_fd& statsMapFd,
                                        const base::unique_fd& ifaceMapFd) {
     int64_t unknownIfaceBytesTotal = 0;
-    struct StatsKey nonExistentKey = NONEXISTENT_STATSKEY;
-    struct StatsValue dummyValue;
+    struct StatsKey dummyKey;
     auto processDetailUidStats = [lines, &limitIfaces, limitTag, limitUid,
                                   &unknownIfaceBytesTotal, &ifaceMapFd]
                                   (void* key, const base::unique_fd& statsMapFd) {
@@ -198,7 +195,7 @@
         lines->push_back(populateStatsEntry(curKey, statsEntry, ifname));
         return BPF_CONTINUE;
     };
-    return bpfIterateMap(nonExistentKey, dummyValue, statsMapFd, processDetailUidStats);
+    return bpfIterateMap(dummyKey, statsMapFd, processDetailUidStats);
 }
 
 int parseBpfNetworkStatsDetail(std::vector<stats_line>* lines,
@@ -244,7 +241,7 @@
                                     const base::unique_fd& statsMapFd,
                                     const base::unique_fd& ifaceMapFd) {
     int64_t unknownIfaceBytesTotal = 0;
-    uint32_t nonExistentKey = NONEXISTENT_IFACE_STATS_KEY;
+    uint32_t dummyKey;
     struct StatsValue dummyValue;
     auto processDetailIfaceStats = [lines, &unknownIfaceBytesTotal, &ifaceMapFd](
                                     void* key, void* value, const base::unique_fd& statsMapFd) {
@@ -260,7 +257,7 @@
         lines->push_back(populateStatsEntry(fakeKey, *statsEntry, ifname));
         return BPF_CONTINUE;
     };
-    return bpfIterateMapWithValue(nonExistentKey, dummyValue, statsMapFd, processDetailIfaceStats);
+    return bpfIterateMapWithValue(dummyKey, dummyValue, statsMapFd, processDetailIfaceStats);
 }
 
 int parseBpfNetworkStatsDev(std::vector<stats_line>* lines) {
@@ -285,76 +282,5 @@
     return (uint64_t)uid << 32 | tag;
 }
 
-// This function get called when the system_server decided to clean up the
-// tagStatsMap after it gethered the information of taggged socket stats. The
-// function go through all the entry in tagStatsMap and remove all the entry
-// for which the tag no longer exists.
-int cleanStatsMapInternal(const base::unique_fd& cookieTagMap, const base::unique_fd& tagStatsMap) {
-    uint64_t curCookie = 0;
-    uint64_t nextCookie = 0;
-    int res;
-    UidTag tmp_uidtag;
-    std::unordered_set<uint64_t> uidTagSet;
-    StatsKey curKey, nextKey;
-
-    // Find all the uid, tag pair exist in cookieTagMap.
-    while (bpf::getNextMapKey(cookieTagMap, &curCookie, &nextCookie) != -1) {
-        curCookie = nextCookie;
-        res = bpf::findMapEntry(cookieTagMap, &curCookie, &tmp_uidtag);
-        if (res < 0) {
-            // might be a concurrent delete, continue to check other entries.
-            continue;
-        }
-        uint64_t uidTag = combineUidTag(tmp_uidtag.uid, tmp_uidtag.tag);
-        uidTagSet.insert(uidTag);
-    }
-
-    // Find all the entries in tagStatsMap where the key is not in the set of
-    // uid, tag pairs found above.
-    curKey = NONEXISTENT_STATSKEY;
-    std::vector<StatsKey> keyList;
-    while (bpf::getNextMapKey(tagStatsMap, &curKey, &nextKey) != -1) {
-        curKey = nextKey;
-        uint64_t uidTag = combineUidTag(curKey.uid, curKey.tag);
-        if (uidTagSet.find(uidTag) == uidTagSet.end()) {
-            keyList.push_back(curKey);
-        }
-    }
-
-    // Delete the entries
-    int size = keyList.size();
-    while (!keyList.empty()) {
-        StatsKey key = keyList.back();
-        keyList.pop_back();
-        res = bpf::deleteMapEntry(tagStatsMap, &key);
-        if (res < 0 && errno != ENOENT) {
-            res = -errno;
-            ALOGE("Failed to delete data(uid=%u, tag=%u): %s\n", key.uid, key.tag, strerror(errno));
-            return res;
-        }
-    }
-    ALOGD("finish clean up, %d stats entry cleaned", size);
-    return 0;
-}
-
-int cleanStatsMap() {
-    base::unique_fd cookieTagMap(bpf::mapRetrieve(COOKIE_TAG_MAP_PATH, BPF_OPEN_FLAGS));
-    int ret = 0;
-    if (cookieTagMap < 0) {
-        ret = -errno;
-        ALOGE("get cookieTag map fd failed: %s", strerror(errno));
-        return ret;
-    }
-
-    base::unique_fd tagStatsMap(bpf::mapRetrieve(TAG_STATS_MAP_PATH, BPF_OPEN_FLAGS));
-    if (tagStatsMap < 0) {
-        ret = -errno;
-        ALOGE("get tagStats map fd failed: %s", strerror(errno));
-        return ret;
-    }
-
-    return cleanStatsMapInternal(cookieTagMap, tagStatsMap);
-}
-
 }  // namespace bpf
 }  // namespace android
diff --git a/libbpf/BpfNetworkStatsTest.cpp b/libbpf/BpfNetworkStatsTest.cpp
index d1f8157..1e9ec8c 100644
--- a/libbpf/BpfNetworkStatsTest.cpp
+++ b/libbpf/BpfNetworkStatsTest.cpp
@@ -181,6 +181,29 @@
     EXPECT_EQ(headOfMap, nextCookie);
 }
 
+TEST_F(BpfNetworkStatsHelperTest, TestBpfIterateMap) {
+    SKIP_IF_BPF_NOT_SUPPORTED;
+
+    for (int i = 0; i < 5; i++) {
+        uint64_t cookie = i + 1;
+        struct UidTag tag = {.uid = TEST_UID1, .tag = TEST_TAG};
+        EXPECT_EQ(0, writeToMapEntry(mFakeCookieTagMap, &cookie, &tag, BPF_ANY));
+    }
+    int totalCount = 0;
+    int totalSum = 0;
+    uint64_t dummyCookie;
+    auto iterateMapWithoutDeletion = [&totalCount, &totalSum](void* key, const base::unique_fd&) {
+        uint64_t cookie = *(uint64_t*)key;
+        EXPECT_GE((uint64_t)5, cookie);
+        totalCount++;
+        totalSum += cookie;
+        return BPF_CONTINUE;
+    };
+    EXPECT_EQ(0, bpfIterateMap(dummyCookie, mFakeCookieTagMap, iterateMapWithoutDeletion));
+    EXPECT_EQ(5, totalCount);
+    EXPECT_EQ(1 + 2 + 3 + 4 + 5, totalSum);
+}
+
 TEST_F(BpfNetworkStatsHelperTest, TestGetUidStatsTotal) {
     SKIP_IF_BPF_NOT_SUPPORTED;
 
@@ -335,25 +358,6 @@
     ASSERT_EQ((unsigned long)2, lines.size());
 }
 
-TEST_F(BpfNetworkStatsHelperTest, TestGetStatsWithNoExistKey) {
-    SKIP_IF_BPF_NOT_SUPPORTED;
-
-    updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
-    StatsValue value1 = {
-        .rxBytes = TEST_BYTES0,
-        .rxPackets = TEST_PACKET0,
-        .txBytes = TEST_BYTES1,
-        .txPackets = TEST_PACKET1,
-    };
-    populateFakeStats(DEFAULT_OVERFLOWUID, 0, 0, 0, &value1, mFakeUidStatsMap);
-    populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, &value1, mFakeUidStatsMap);
-    std::vector<stats_line> lines;
-    std::vector<std::string> ifaces;
-    ASSERT_EQ(-EUCLEAN,
-              parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeUidStatsMap,
-                                                 mFakeIfaceIndexNameMap));
-}
-
 TEST_F(BpfNetworkStatsHelperTest, TestUnkownIfaceError) {
     SKIP_IF_BPF_NOT_SUPPORTED;
 
diff --git a/libbpf/BpfUtils.cpp b/libbpf/BpfUtils.cpp
index d6ea6d7..f137174 100644
--- a/libbpf/BpfUtils.cpp
+++ b/libbpf/BpfUtils.cpp
@@ -43,6 +43,11 @@
 namespace android {
 namespace bpf {
 
+/*  The bpf_attr is a union which might have a much larger size then the struct we are using, while
+ *  The inline initializer only reset the field we are using and leave the reset of the memory as
+ *  is. The bpf kernel code will performs a much stricter check to ensure all unused field is 0. So
+ *  this syscall will normally fail with E2BIG if we don't do a memset to bpf_attr.
+ */
 int bpf(int cmd, Slice bpfAttr) {
     return syscall(__NR_bpf, cmd, bpfAttr.base(), bpfAttr.size());
 }
@@ -100,6 +105,16 @@
     return bpf(BPF_MAP_GET_NEXT_KEY, Slice(&attr, sizeof(attr)));
 }
 
+int getFirstMapKey(const base::unique_fd& map_fd, void* firstKey) {
+    bpf_attr attr;
+    memset(&attr, 0, sizeof(attr));
+    attr.map_fd = map_fd.get();
+    attr.key = 0;
+    attr.next_key = ptr_to_u64(firstKey);
+
+    return bpf(BPF_MAP_GET_NEXT_KEY, Slice(&attr, sizeof(attr)));
+}
+
 int bpfProgLoad(bpf_prog_type prog_type, Slice bpf_insns, const char* license,
                 uint32_t kern_version, Slice bpf_log) {
     bpf_attr attr;
diff --git a/libbpf/include/bpf/BpfUtils.h b/libbpf/include/bpf/BpfUtils.h
index 550c9ca..be67420 100644
--- a/libbpf/include/bpf/BpfUtils.h
+++ b/libbpf/include/bpf/BpfUtils.h
@@ -86,13 +86,7 @@
 constexpr const char* STANDBY_UID_MAP_PATH = BPF_PATH "/traffic_standby_uid_map";
 constexpr const char* POWERSAVE_UID_MAP_PATH = BPF_PATH "/traffic_powersave_uid_map";
 
-const StatsKey NONEXISTENT_STATSKEY = {
-    .uid = DEFAULT_OVERFLOWUID,
-};
-
 constexpr const uint64_t NONEXISTENT_COOKIE = 0;
-constexpr const uint32_t NONEXISTENT_UID = DEFAULT_OVERFLOWUID;
-constexpr const uint32_t NONEXISTENT_IFACE_STATS_KEY = 0;
 
 constexpr const int MINIMUM_API_REQUIRED = 28;
 
@@ -102,6 +96,7 @@
 int findMapEntry(const base::unique_fd& map_fd, void* key, void* value);
 int deleteMapEntry(const base::unique_fd& map_fd, void* key);
 int getNextMapKey(const base::unique_fd& map_fd, void* key, void* next_key);
+int getFirstMapKey(const base::unique_fd& map_fd, void* firstKey);
 int bpfProgLoad(bpf_prog_type prog_type, netdutils::Slice bpf_insns, const char* license,
                 uint32_t kern_version, netdutils::Slice bpf_log);
 int mapPin(const base::unique_fd& map_fd, const char* pathname);
@@ -123,18 +118,21 @@
 constexpr int BPF_DELETED = 1;
 
 typedef std::function<int(void* key, const base::unique_fd& map_fd)> BpfMapEntryFilter;
-template <class Key, class Value>
-int bpfIterateMap(const Key& nonExistentKey, const Value& /* dummy */,
-                  const base::unique_fd& map_fd, const BpfMapEntryFilter& filter) {
-    Key curKey = nonExistentKey;
-    Key nextKey;
+template <class Key>
+int bpfIterateMap(const Key& /* dummy */, const base::unique_fd& map_fd,
+                  const BpfMapEntryFilter& filter) {
     int ret;
-    Value dummyEntry;
-    if (bpf::findMapEntry(map_fd, &curKey, &dummyEntry) == 0) {
-        ALOGE("This entry should never exist in map!");
-        return -EUCLEAN;
+    Key nextKey;
+    ret = bpf::getFirstMapKey(map_fd, &nextKey);
+    if (ret && errno == ENOENT) {
+        // Map is empty, return;
+        return 0;
+    } else if (ret) {
+        ALOGE("Fail to get the first key of the map: %s", strerror(errno));
+        return -errno;
     }
-    while (bpf::getNextMapKey(map_fd, &curKey, &nextKey) != -1) {
+    Key curKey = nextKey;
+    do {
         ret = filter(&nextKey, map_fd);
         switch (ret) {
             case BPF_DELETED:
@@ -147,11 +145,12 @@
             default:
                 return ret;
         }
-    }
+    } while (bpf::getNextMapKey(map_fd, &curKey, &nextKey) != -1);
     // Return errno if getNextMapKey return error before hit to the end of the map.
     if (errno != ENOENT) {
         ret = errno;
-        ALOGE("bpfIterateMap failed on MAP_FD: %d, error: %s", map_fd.get(), strerror(errno));
+        ALOGE("bpfIterateMap failed on MAP_FD: %d, error: %s", map_fd.get(),
+              strerror(errno));
         return -ret;
     }
     return 0;
@@ -160,18 +159,21 @@
 typedef std::function<int(void* key, void* value, const base::unique_fd& map_fd)>
     BpfMapEntryFilterWithValue;
 template <class Key, class Value>
-int bpfIterateMapWithValue(const Key& nonExistentKey, const Value& /* dummy */,
-                           const base::unique_fd& map_fd,
-                           const BpfMapEntryFilterWithValue& filter) {
-    Key curKey = nonExistentKey;
+int bpfIterateMapWithValue(const Key& /* dummy */, const Value& /* dummy */,
+                           const base::unique_fd& map_fd, const BpfMapEntryFilterWithValue& filter) {
     Key nextKey;
     int ret = 0;
-    Value value;
-    if (bpf::findMapEntry(map_fd, &curKey, &value) == 0) {
-        ALOGE("This entry should never exist in map!");
-        return -EUCLEAN;
+    ret = bpf::getFirstMapKey(map_fd, &nextKey);
+    if (ret && errno != ENOENT) {
+        ALOGE("Fail to get the first key of the map: %s", strerror(errno));
+        return -errno;
+    } else if (ret) {
+        // Map is empty, return;
+        return 0;
     }
-    while (bpf::getNextMapKey(map_fd, &curKey, &nextKey) != -1) {
+    Key curKey = nextKey;
+    Value value;
+    do {
         ret = bpf::findMapEntry(map_fd, &nextKey, &value);
         if (ret) {
             ALOGE("Get value failed");
@@ -189,11 +191,11 @@
             default:
                 return ret;
         }
-    }
+    } while (bpf::getNextMapKey(map_fd, &curKey, &nextKey) != -1);
     // Return errno if getNextMapKey return error before hit to the end of the map.
     if (errno != ENOENT) {
         ret = errno;
-        ALOGE("bpfIterateMap failed on MAP_FD: %d, error: %s", map_fd.get(), strerror(errno));
+        ALOGE("bpfIterateMapWithValue failed on MAP_FD: %d, error: %s", map_fd.get(), strerror(errno));
         return -ret;
     }
     return 0;
diff --git a/server/TrafficController.cpp b/server/TrafficController.cpp
index 17c8f9a..29cffd4 100644
--- a/server/TrafficController.cpp
+++ b/server/TrafficController.cpp
@@ -356,7 +356,7 @@
         return 0;
     }
 
-    uint64_t nonExistentCookie = NONEXISTENT_COOKIE;
+    uint64_t dummyCookie;
     // First we go through the cookieTagMap to delete the target uid tag combination. Or delete all
     // the tags related to the uid if the tag is 0.
     struct UidTag dummyUidTag;
@@ -375,12 +375,10 @@
         // Move forward to next cookie in the map.
         return BPF_CONTINUE;
     };
-    bpfIterateMapWithValue(nonExistentCookie, dummyUidTag, mCookieTagMap,
-                                 deleteMatchedCookieEntry);
+    res = bpfIterateMapWithValue(dummyCookie, dummyUidTag, mCookieTagMap, deleteMatchedCookieEntry);
     // Now we go through the Tag stats map and delete the data entry with correct uid and tag
     // combination. Or all tag stats under that uid if the target tag is 0.
-    struct StatsKey nonExistentStatsKey = NONEXISTENT_STATSKEY;
-    struct StatsValue dummyStatsValue;
+    struct StatsKey dummyStatsKey;
     auto deleteMatchedUidTagEntry = [&uid, &tag](void *key, const base::unique_fd& map_fd) {
         StatsKey *keyInfo = (StatsKey *) key;
         if (keyInfo->uid == uid && (keyInfo->tag == tag || tag == 0)) {
@@ -394,8 +392,7 @@
         }
         return BPF_CONTINUE;
     };
-    bpfIterateMap(nonExistentStatsKey, dummyStatsValue, mTagStatsMap,
-                  deleteMatchedUidTagEntry);
+    res = bpfIterateMap(dummyStatsKey, mTagStatsMap, deleteMatchedUidTagEntry);
     // If the tag is not zero, we already deleted all the data entry required. If tag is 0, we also
     // need to delete the stats stored in uidStatsMap and counterSet map.
     if (tag != 0) return 0;
@@ -404,8 +401,7 @@
     if (res < 0 && errno != ENOENT) {
         ALOGE("Failed to delete counterSet data(uid=%u, tag=%u): %s\n", uid, tag, strerror(errno));
     }
-    return bpfIterateMap(nonExistentStatsKey, dummyStatsValue, mUidStatsMap,
-                         deleteMatchedUidTagEntry);
+    return bpfIterateMap(dummyStatsKey, mUidStatsMap, deleteMatchedUidTagEntry);
 }
 
 int TrafficController::addInterface(const char* name, uint32_t ifaceIndex) {
@@ -430,10 +426,6 @@
 int TrafficController::updateOwnerMapEntry(const base::unique_fd& map_fd, uid_t uid,
                                            FirewallRule rule, FirewallType type) {
     int res = 0;
-    if (uid == NONEXISTENT_UID) {
-        ALOGE("This uid should never exist in maps: %u", uid);
-        return -EINVAL;
-    }
 
     if (uid == UID_MAP_ENABLED) {
         ALOGE("This uid is reserved for map state");
@@ -492,9 +484,8 @@
         }
         return BPF_CONTINUE;
     };
-    uint32_t nonExistentKey = NONEXISTENT_UID;
-    uint8_t dummyValue;
-    int ret = bpfIterateMap(nonExistentKey, dummyValue, map_fd, getUidsToDelete);
+    uint32_t dummyKey;
+    int ret = bpfIterateMap(dummyKey, map_fd, getUidsToDelete);
 
     if (ret)  return ret;
 
@@ -541,7 +532,7 @@
         return -EINVAL;
     }
     if (ret) {
-        ALOGE("Failed to clean up chain: %s: %s", name.c_str(), strerror(ret));
+        ALOGE("Failed to clean up chain: %s: %s", name.c_str(), strerror(-ret));
         return ret;
     }
     return 0;
@@ -655,7 +646,7 @@
 
     // Print CookieTagMap content.
     dumpBpfMap("mCookieTagMap", dw, "");
-    const uint64_t nonExistentCookie = NONEXISTENT_COOKIE;
+    uint64_t dummyCookie;
     UidTag dummyUidTag;
     auto printCookieTagInfo = [&dw](void *key, void *value, const base::unique_fd&) {
         UidTag uidTagEntry = *(UidTag *) value;
@@ -663,15 +654,14 @@
         dw.println("cookie=%" PRIu64 " tag=0x%x uid=%u", cookie, uidTagEntry.tag, uidTagEntry.uid);
         return BPF_CONTINUE;
     };
-    int ret = bpfIterateMapWithValue(nonExistentCookie, dummyUidTag, mCookieTagMap,
-                                     printCookieTagInfo);
+    int ret = bpfIterateMapWithValue(dummyCookie, dummyUidTag, mCookieTagMap, printCookieTagInfo);
     if (ret) {
         dw.println("mCookieTagMap print end with error: %s", strerror(-ret));
     }
 
     // Print UidCounterSetMap Content
     dumpBpfMap("mUidCounterSetMap", dw, "");
-    const uint32_t nonExistentUid = NONEXISTENT_UID;
+    uint32_t dummyUid;
     uint32_t dummyUidInfo;
     auto printUidInfo = [&dw](void *key, void *value, const base::unique_fd&) {
         uint8_t setting = *(uint8_t *) value;
@@ -679,7 +669,7 @@
         dw.println("%u %u", uid, setting);
         return BPF_CONTINUE;
     };
-    ret = bpfIterateMapWithValue(nonExistentUid, dummyUidInfo, mUidCounterSetMap, printUidInfo);
+    ret = bpfIterateMapWithValue(dummyUid, dummyUidInfo, mUidCounterSetMap, printUidInfo);
     if (ret) {
        dw.println("mUidCounterSetMap print end with error: %s", strerror(-ret));
     }
@@ -688,7 +678,7 @@
     std::string statsHeader = StringPrintf("ifaceIndex ifaceName tag_hex uid_int cnt_set rxBytes"
                                            " rxPackets txBytes txPackets");
     dumpBpfMap("mUidStatsMap", dw, statsHeader);
-    const struct StatsKey nonExistentStatsKey = NONEXISTENT_STATSKEY;
+    struct StatsKey dummyStatsKey;
     struct StatsValue dummyStatsValue;
     auto printStatsInfo = [&dw, this](void *key, void *value, const base::unique_fd&) {
         StatsValue statsEntry = *(StatsValue *) value;
@@ -703,23 +693,21 @@
                    statsEntry.rxPackets, statsEntry.txBytes, statsEntry.txPackets);
         return BPF_CONTINUE;
     };
-    ret = bpfIterateMapWithValue(nonExistentStatsKey, dummyStatsValue, mUidStatsMap,
-                                 printStatsInfo);
+    ret = bpfIterateMapWithValue(dummyStatsKey, dummyStatsValue, mUidStatsMap, printStatsInfo);
     if (ret) {
         dw.println("mUidStatsMap print end with error: %s", strerror(-ret));
     }
 
     // Print TagStatsMap content.
     dumpBpfMap("mTagStatsMap", dw, statsHeader);
-    ret = bpfIterateMapWithValue(nonExistentStatsKey, dummyStatsValue, mTagStatsMap,
-                                 printStatsInfo);
+    ret = bpfIterateMapWithValue(dummyStatsKey, dummyStatsValue, mTagStatsMap, printStatsInfo);
     if (ret) {
         dw.println("mTagStatsMap print end with error: %s", strerror(-ret));
     }
 
     // Print ifaceIndexToNameMap content.
     dumpBpfMap("mIfaceIndexNameMap", dw, "");
-    uint32_t nonExistentIface = NONEXISTENT_IFACE_STATS_KEY;
+    uint32_t dummyKey;
     char dummyIface[IFNAMSIZ];
     auto printIfaceNameInfo = [&dw](void *key, void *value, const base::unique_fd&) {
         char *ifname = (char *) value;
@@ -727,8 +715,7 @@
         dw.println("ifaceIndex=%u ifaceName=%s", ifaceIndex, ifname);
         return BPF_CONTINUE;
     };
-    ret = bpfIterateMapWithValue(nonExistentIface, dummyIface, mIfaceIndexNameMap,
-                               printIfaceNameInfo);
+    ret = bpfIterateMapWithValue(dummyKey, dummyIface, mIfaceIndexNameMap, printIfaceNameInfo);
     if (ret) {
         dw.println("mIfaceIndexNameMap print end with error: %s", strerror(-ret));
     }
@@ -749,8 +736,7 @@
                    statsEntry.txPackets);
         return BPF_CONTINUE;
     };
-    ret = bpfIterateMapWithValue(nonExistentIface, dummyStatsValue, mIfaceStatsMap,
-                                 printIfaceStatsInfo);
+    ret = bpfIterateMapWithValue(dummyKey, dummyStatsValue, mIfaceStatsMap, printIfaceStatsInfo);
     if (ret) {
         dw.println("mIfaceStatsMap print end with error: %s", strerror(-ret));
     }
@@ -758,19 +744,19 @@
     // Print owner match uid maps
     uint8_t dummyOwnerInfo;
     dumpBpfMap("mDozableUidMap", dw, "");
-    ret = bpfIterateMapWithValue(nonExistentUid, dummyOwnerInfo, mDozableUidMap, printUidInfo);
+    ret = bpfIterateMapWithValue(dummyUid, dummyOwnerInfo, mDozableUidMap, printUidInfo);
     if (ret) {
         dw.println("mDozableUidMap print end with error: %s", strerror(-ret));
     }
 
     dumpBpfMap("mStandbyUidMap", dw, "");
-    ret = bpfIterateMapWithValue(nonExistentUid, dummyOwnerInfo, mStandbyUidMap, printUidInfo);
+    ret = bpfIterateMapWithValue(dummyUid, dummyOwnerInfo, mStandbyUidMap, printUidInfo);
     if (ret) {
         dw.println("mDozableUidMap print end with error: %s", strerror(-ret));
     }
 
     dumpBpfMap("mPowerSaveUidMap", dw, "");
-    ret = bpfIterateMapWithValue(nonExistentUid, dummyOwnerInfo, mPowerSaveUidMap, printUidInfo);
+    ret = bpfIterateMapWithValue(dummyUid, dummyOwnerInfo, mPowerSaveUidMap, printUidInfo);
     if (ret) {
         dw.println("mDozableUidMap print end with error: %s", strerror(-ret));
     }
diff --git a/server/TrafficControllerTest.cpp b/server/TrafficControllerTest.cpp
index 187014f..d5e0e42 100644
--- a/server/TrafficControllerTest.cpp
+++ b/server/TrafficControllerTest.cpp
@@ -197,9 +197,8 @@
             EXPECT_NE(uidSet.end(), uidSet.find(uid));
             return BPF_CONTINUE;
         };
-        uint32_t nonExistentKey = NONEXISTENT_UID;
-        uint8_t dummyValue;
-        EXPECT_EQ(0, bpfIterateMap(nonExistentKey, dummyValue, targetMap, checkNoOtherUid));
+        uint32_t dummyKey;
+        EXPECT_EQ(0, bpfIterateMap(dummyKey, targetMap, checkNoOtherUid));
     }
 
     void checkUidMapReplace(const std::string& name, const std::vector<int32_t>& uids,
diff --git a/server/XfrmController.cpp b/server/XfrmController.cpp
index 9f62453..e229cf8 100644
--- a/server/XfrmController.cpp
+++ b/server/XfrmController.cpp
@@ -43,11 +43,12 @@
 #include <linux/netlink.h>
 #include <linux/xfrm.h>
 
+#define LOG_TAG "XfrmController"
 #include "android-base/stringprintf.h"
 #include "android-base/strings.h"
 #include "android-base/unique_fd.h"
+#include <android/net/INetd.h>
 #include <log/log_properties.h>
-#define LOG_TAG "XfrmController"
 #include "InterfaceController.h"
 #include "NetdConstants.h"
 #include "NetlinkCommands.h"
@@ -60,6 +61,7 @@
 #include <log/log.h>
 #include <logwrap/logwrap.h>
 
+using android::net::INetd;
 using android::netdutils::Fd;
 using android::netdutils::Slice;
 using android::netdutils::Status;
@@ -85,9 +87,6 @@
 
 constexpr uint32_t INVALID_SPI = 0;
 
-// Must match TUNNEL_INTERFACE_PREFIX in IpSecService.java
-constexpr char const* TUNNEL_INTERFACE_PREFIX = "ipsec";
-
 #define XFRM_MSG_TRANS(x)                                                                          \
     case x:                                                                                        \
         return #x;
@@ -386,11 +385,12 @@
 netdutils::Status XfrmController::flushInterfaces() {
     const auto& ifaces = InterfaceController::getIfaceNames();
     RETURN_IF_NOT_OK(ifaces);
+    const String8 ifPrefix8 = String8(INetd::IPSEC_INTERFACE_PREFIX().string());
 
     for (const std::string& iface : ifaces.value()) {
         int status = 0;
         // Look for the reserved interface prefix, which must be in the name at position 0
-        if (!iface.compare(0, strlen(TUNNEL_INTERFACE_PREFIX), TUNNEL_INTERFACE_PREFIX) &&
+        if (android::base::StartsWith(iface.c_str(), ifPrefix8.c_str()) &&
             (status = removeVirtualTunnelInterface(iface)) < 0) {
             ALOGE("Failed to delete ipsec tunnel %s.", iface.c_str());
             return netdutils::statusFromErrno(status, "Failed to remove ipsec tunnel.");
@@ -1346,7 +1346,8 @@
         flags |= NLM_F_EXCL | NLM_F_CREATE;
     }
 
-    int ret = sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov), nullptr);
+    // sendNetlinkRequest returns -errno
+    int ret = -1 * sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov), nullptr);
     if (ret) {
         ALOGE("Error in %s virtual tunnel interface. Error Code: %d",
               isUpdate ? "updating" : "adding", ret);
@@ -1383,7 +1384,8 @@
     uint16_t action = RTM_DELLINK;
     uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
 
-    int ret = sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov), nullptr);
+    // sendNetlinkRequest returns -errno
+    int ret = -1 * sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov), nullptr);
     if (ret) {
         ALOGE("Error in removing virtual tunnel interface %s. Error Code: %d", iflaIfNameStrValue,
               ret);
diff --git a/server/binder/android/net/INetd.aidl b/server/binder/android/net/INetd.aidl
index 0c13191..6ab6183 100644
--- a/server/binder/android/net/INetd.aidl
+++ b/server/binder/android/net/INetd.aidl
@@ -485,6 +485,10 @@
             int markValue,
             int markMask);
 
+    // This could not be declared as @uft8InCpp; thus, when used in native code it must be
+    // converted from a UTF-16 string to an ASCII string.
+    const String IPSEC_INTERFACE_PREFIX = "ipsec";
+
    /**
     * Add a Virtual Tunnel Interface.
     *
diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp
index f339ced..6752ef1 100644
--- a/tests/binder_test.cpp
+++ b/tests/binder_test.cpp
@@ -293,6 +293,9 @@
     }
 }
 
+// IPsec tests are not run in 32 bit mode; both 32-bit kernels and
+// mismatched ABIs (64-bit kernel with 32-bit userspace) are unsupported.
+#if INTPTR_MAX != INT32_MAX
 #define RETURN_FALSE_IF_NEQ(_expect_, _ret_) \
         do { if ((_expect_) != (_ret_)) return false; } while(false)
 bool BinderTest::allocateIpSecResources(bool expectOk, int32_t *spi) {
@@ -313,11 +316,15 @@
     return (status.ok() == expectOk);
 }
 
-
 TEST_F(BinderTest, TestXfrmControllerInit) {
     netdutils::Status status;
     status = XfrmController::Init();
     SCOPED_TRACE(status);
+
+    // Older devices or devices with mismatched Kernel/User ABI cannot support the IPsec
+    // feature.
+    if (status.code() == EOPNOTSUPP) return;
+
     ASSERT_TRUE(status.ok());
 
     int32_t spi = 0;
@@ -345,6 +352,7 @@
 
     ASSERT_TRUE(status.ok());
 }
+#endif
 
 static int bandwidthDataSaverEnabled(const char *binary) {
     std::vector<std::string> lines = listIptablesRule(binary, "bw_data_saver");