Merge all uid owner match map into one

The bpf maps used for storing the uid owner match information are using
the same key value pairs and the duplication can be reduced by using one
single value to store all the match information for a given uid and use
a configuration map to store the chain that is currently enabled. This
migration can save some kernel memory space and simplify the owner match
process.

Bug: 79781072
Test: netd_unit_test,
      com.android.cts.net.HostsideRestrictBackgroundNetworkTests

Change-Id: I9658321e9d4a87eaa724231d33a474113dd75019
diff --git a/bpfloader/BpfLoader.cpp b/bpfloader/BpfLoader.cpp
index 0329be3..1a41d3d 100644
--- a/bpfloader/BpfLoader.cpp
+++ b/bpfloader/BpfLoader.cpp
@@ -54,6 +54,7 @@
 #define BPF_PROG_PATH "/system/etc/bpf"
 #define BPF_PROG_SRC BPF_PROG_PATH "/bpf_kern.o"
 #define MAP_LD_CMD_HEAD 0x18
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 
 #define FAIL(...)      \
     do {               \
@@ -229,61 +230,19 @@
     return bpfProgLoad(type, prog, "Apache 2.0", 0, bpfLog);
 }
 
-int loadAndAttachProgram(bpf_attach_type type, const char* path, const char* name,
-                         const std::vector<ReplacePattern>& mapPatterns) {
-    unique_fd fd;
-    if (type == BPF_CGROUP_INET_INGRESS) {
-        fd.reset(loadProg(cgroupIngressProg, BPF_PROG_TYPE_CGROUP_SKB, mapPatterns));
-    } else if (type == BPF_CGROUP_INET_EGRESS) {
-        fd.reset(loadProg(cgroupEgressProg, BPF_PROG_TYPE_CGROUP_SKB, mapPatterns));
-    } else if (!strcmp(name, XT_BPF_INGRESS_PROG_NAME)) {
-        fd.reset(loadProg(xtIngressProg, BPF_PROG_TYPE_SOCKET_FILTER, mapPatterns));
-    } else if (!strcmp(name, XT_BPF_EGRESS_PROG_NAME)) {
-        fd.reset(loadProg(xtEgressProg, BPF_PROG_TYPE_SOCKET_FILTER, mapPatterns));
-    } else if (!strcmp(name, XT_BPF_WHITELIST_PROG_NAME)) {
-        fd.reset(loadProg(xtWhiteListProg, BPF_PROG_TYPE_SOCKET_FILTER, mapPatterns));
-    } else if (!strcmp(name, XT_BPF_BLACKLIST_PROG_NAME)) {
-        fd.reset(loadProg(xtBlackListProg, BPF_PROG_TYPE_SOCKET_FILTER, mapPatterns));
-    } else {
-        FAIL("Unrecognized program type: %s", name);
-    }
-
-    if (fd < 0) {
-        FAIL("load %s failed: %s", name, strerror(errno));
-    }
-    int ret = 0;
-    if (type == BPF_CGROUP_INET_EGRESS || type == BPF_CGROUP_INET_INGRESS) {
-        unique_fd cg_fd(open(CGROUP_ROOT_PATH, O_DIRECTORY | O_RDONLY | O_CLOEXEC));
-        if (cg_fd < 0) {
-            FAIL("Failed to open the cgroup directory");
-        }
-        ret = attachProgram(type, fd, cg_fd);
-        if (ret) {
-            FAIL("%s attach failed: %s", name, strerror(errno));
-        }
-    }
-
-    ret = mapPin(fd, path);
-    if (ret) {
-        FAIL("Pin %s as file %s failed: %s", name, path, strerror(errno));
-    }
-    return 0;
-}
-
 }  // namespace bpf
 }  // namespace android
 
 using android::bpf::APP_UID_STATS_MAP_PATH;
-using android::bpf::BANDWIDTH_UID_MAP_PATH;
 using android::bpf::BPF_EGRESS_PROG_PATH;
 using android::bpf::BPF_INGRESS_PROG_PATH;
+using android::bpf::CGROUP_ROOT_PATH;
+using android::bpf::CONFIGURATION_MAP_PATH;
 using android::bpf::COOKIE_TAG_MAP_PATH;
-using android::bpf::DOZABLE_UID_MAP_PATH;
 using android::bpf::IFACE_STATS_MAP_PATH;
-using android::bpf::POWERSAVE_UID_MAP_PATH;
-using android::bpf::STANDBY_UID_MAP_PATH;
 using android::bpf::TAG_STATS_MAP_PATH;
 using android::bpf::UID_COUNTERSET_MAP_PATH;
+using android::bpf::UID_OWNER_MAP_PATH;
 using android::bpf::UID_STATS_MAP_PATH;
 using android::bpf::XT_BPF_BLACKLIST_PROG_PATH;
 using android::bpf::XT_BPF_EGRESS_PROG_PATH;
@@ -291,20 +250,15 @@
 using android::bpf::XT_BPF_WHITELIST_PROG_PATH;
 
 using android::bpf::ReplacePattern;
-using android::bpf::loadAndAttachProgram;
 
-static void usage(void) {
-    ALOGE(
-        "Usage: ./bpfloader [-i] [-e]\n"
-        "   -i load ingress bpf program\n"
-        "   -e load egress bpf program\n"
-        "   -p load prerouting xt_bpf program\n"
-        "   -m load mangle xt_bpf program\n"
-        "   -w load bandwidth whitelist program\n"
-        "   -b load bandwidth blacklist program\n");
-}
+using android::bpf::cgroupEgressProg;
+using android::bpf::cgroupIngressProg;
+using android::bpf::xtBlackListProg;
+using android::bpf::xtEgressProg;
+using android::bpf::xtIngressProg;
+using android::bpf::xtWhiteListProg;
 
-int main(int argc, char** argv) {
+int main() {
     int ret = 0;
     DECLARE_MAP(cookieTagMap, COOKIE_TAG_MAP_PATH);
     DECLARE_MAP(uidCounterSetMap, UID_COUNTERSET_MAP_PATH);
@@ -312,94 +266,66 @@
     DECLARE_MAP(uidStatsMap, UID_STATS_MAP_PATH);
     DECLARE_MAP(tagStatsMap, TAG_STATS_MAP_PATH);
     DECLARE_MAP(ifaceStatsMap, IFACE_STATS_MAP_PATH);
-    DECLARE_MAP(dozableUidMap, DOZABLE_UID_MAP_PATH);
-    DECLARE_MAP(standbyUidMap, STANDBY_UID_MAP_PATH);
-    DECLARE_MAP(powerSaveUidMap, POWERSAVE_UID_MAP_PATH);
-    DECLARE_MAP(bandwidthUidMap, BANDWIDTH_UID_MAP_PATH);
+    DECLARE_MAP(configurationMap, CONFIGURATION_MAP_PATH);
+    DECLARE_MAP(uidOwnerMap, UID_OWNER_MAP_PATH);
 
     const std::vector<ReplacePattern> mapPatterns = {
-        ReplacePattern(COOKIE_TAG_MAP, cookieTagMap.get()),
-        ReplacePattern(UID_COUNTERSET_MAP, uidCounterSetMap.get()),
-        ReplacePattern(APP_UID_STATS_MAP, appUidStatsMap.get()),
-        ReplacePattern(UID_STATS_MAP, uidStatsMap.get()),
-        ReplacePattern(TAG_STATS_MAP, tagStatsMap.get()),
-        ReplacePattern(IFACE_STATS_MAP, ifaceStatsMap.get()),
-        ReplacePattern(DOZABLE_UID_MAP, dozableUidMap.get()),
-        ReplacePattern(STANDBY_UID_MAP, standbyUidMap.get()),
-        ReplacePattern(POWERSAVE_UID_MAP, powerSaveUidMap.get()),
-        ReplacePattern(BANDWIDTH_UID_MAP, bandwidthUidMap.get()),
+            ReplacePattern(COOKIE_TAG_MAP, cookieTagMap.get()),
+            ReplacePattern(UID_COUNTERSET_MAP, uidCounterSetMap.get()),
+            ReplacePattern(APP_UID_STATS_MAP, appUidStatsMap.get()),
+            ReplacePattern(UID_STATS_MAP, uidStatsMap.get()),
+            ReplacePattern(TAG_STATS_MAP, tagStatsMap.get()),
+            ReplacePattern(IFACE_STATS_MAP, ifaceStatsMap.get()),
+            ReplacePattern(CONFIGURATION_MAP, configurationMap.get()),
+            ReplacePattern(UID_OWNER_MAP, uidOwnerMap.get()),
     };
-
-    int opt;
-    bool doIngress = false, doEgress = false, doPrerouting = false, doMangle = false;
-    bool doWhitelist = false, doBlacklist = false;
-    while ((opt = getopt(argc, argv, "iepmwb")) != -1) {
-        switch (opt) {
-            case 'i':
-                doIngress = true;
-                break;
-            case 'e':
-                doEgress = true;
-                break;
-            case 'p':
-                doPrerouting = true;
-                break;
-            case 'm':
-                doMangle = true;
-                break;
-            case 'w':
-                doWhitelist = true;
-                break;
-            case 'b':
-                doBlacklist = true;
-                break;
-            default:
-                usage();
-                FAIL("unknown argument %c", opt);
-        }
-    }
     android::bpf::parseProgramsFromFile(BPF_PROG_SRC);
 
-    if (doIngress) {
-        ret = loadAndAttachProgram(BPF_CGROUP_INET_INGRESS, BPF_INGRESS_PROG_PATH,
-                                   BPF_CGROUP_INGRESS_PROG_NAME, mapPatterns);
-        if (ret) {
-            FAIL("Failed to set up ingress program");
-        }
-    }
-    if (doEgress) {
-        ret = loadAndAttachProgram(BPF_CGROUP_INET_EGRESS, BPF_EGRESS_PROG_PATH,
-                                   BPF_CGROUP_EGRESS_PROG_NAME, mapPatterns);
-        if (ret) {
-            FAIL("Failed to set up ingress program");
-        }
-    }
-    if (doPrerouting) {
-        ret = loadAndAttachProgram(MAX_BPF_ATTACH_TYPE, XT_BPF_INGRESS_PROG_PATH,
-                                   XT_BPF_INGRESS_PROG_NAME, mapPatterns);
-        if (ret) {
-            FAIL("Failed to set up xt_bpf program");
-        }
-    }
-    if (doMangle) {
-        ret = loadAndAttachProgram(MAX_BPF_ATTACH_TYPE, XT_BPF_EGRESS_PROG_PATH,
-                                   XT_BPF_EGRESS_PROG_NAME, mapPatterns);
-        if (ret) {
-            FAIL("Failed to set up xt_bpf program");
-        }
-    }
-    if (doWhitelist) {
-        ret = loadAndAttachProgram(MAX_BPF_ATTACH_TYPE, XT_BPF_WHITELIST_PROG_PATH,
-                                   XT_BPF_WHITELIST_PROG_NAME, mapPatterns);
-        if (ret) {
-            FAIL("Failed to set up xt_bpf Whitelist program");
-        }
-    }
-    if (doBlacklist) {
-        ret = loadAndAttachProgram(MAX_BPF_ATTACH_TYPE, XT_BPF_BLACKLIST_PROG_PATH,
-                                   XT_BPF_BLACKLIST_PROG_NAME, mapPatterns);
-        if (ret) {
-            FAIL("Failed to set up xt_bpf blacklist program");
+    struct BpfProgInfo {
+        bpf_attach_type attachType;
+        const char* path;
+        const char* name;
+        bpf_prog_type loadType;
+        Slice progBlock;
+    } programs[] = {{BPF_CGROUP_INET_INGRESS, BPF_INGRESS_PROG_PATH, BPF_CGROUP_INGRESS_PROG_NAME,
+                     BPF_PROG_TYPE_CGROUP_SKB, cgroupIngressProg},
+                    {BPF_CGROUP_INET_EGRESS, BPF_EGRESS_PROG_PATH, BPF_CGROUP_EGRESS_PROG_NAME,
+                     BPF_PROG_TYPE_CGROUP_SKB, cgroupEgressProg},
+                    {MAX_BPF_ATTACH_TYPE, XT_BPF_INGRESS_PROG_PATH, XT_BPF_INGRESS_PROG_NAME,
+                     BPF_PROG_TYPE_SOCKET_FILTER, xtIngressProg},
+                    {MAX_BPF_ATTACH_TYPE, XT_BPF_EGRESS_PROG_PATH, XT_BPF_EGRESS_PROG_NAME,
+                     BPF_PROG_TYPE_SOCKET_FILTER, xtEgressProg},
+                    {MAX_BPF_ATTACH_TYPE, XT_BPF_WHITELIST_PROG_PATH, XT_BPF_WHITELIST_PROG_NAME,
+                     BPF_PROG_TYPE_SOCKET_FILTER, xtWhiteListProg},
+                    {MAX_BPF_ATTACH_TYPE, XT_BPF_BLACKLIST_PROG_PATH, XT_BPF_BLACKLIST_PROG_NAME,
+                     BPF_PROG_TYPE_SOCKET_FILTER, xtBlackListProg}};
+
+    for (size_t i = 0; i < ARRAY_SIZE(programs); i++) {
+        BpfProgInfo* prog = programs + i;
+        if (access(prog->path, R_OK) == -1) {
+            // Program doesn't exist. Try to load it.
+            unique_fd fd;
+            fd.reset(loadProg(prog->progBlock, prog->loadType, mapPatterns));
+            if (fd < 0) {
+                FAIL("load %s failed: %s", prog->name, strerror(errno));
+            }
+            int ret = 0;
+            if (prog->attachType == BPF_CGROUP_INET_EGRESS ||
+                prog->attachType == BPF_CGROUP_INET_INGRESS) {
+                unique_fd cg_fd(open(CGROUP_ROOT_PATH, O_DIRECTORY | O_RDONLY | O_CLOEXEC));
+                if (cg_fd < 0) {
+                    FAIL("Failed to open the cgroup directory");
+                }
+                ret = android::bpf::attachProgram(prog->attachType, fd, cg_fd);
+                if (ret) {
+                    FAIL("%s attach failed: %s", prog->name, strerror(errno));
+                }
+            }
+
+            ret = android::bpf::mapPin(fd, prog->path);
+            if (ret) {
+                FAIL("Pin %s as file %s failed: %s", prog->name, prog->path, strerror(errno));
+            }
         }
     }
     return ret;
diff --git a/bpfloader/bpf_kern.c b/bpfloader/bpf_kern.c
index 1d04cda..4fe8140 100644
--- a/bpfloader/bpf_kern.c
+++ b/bpfloader/bpf_kern.c
@@ -46,15 +46,15 @@
 int xt_bpf_whitelist_prog(struct __sk_buff* skb) {
     uint32_t sock_uid = get_socket_uid(skb);
     if (is_system_uid(sock_uid)) return BPF_MATCH;
-    uint8_t* whitelistMatch = find_map_entry(BANDWIDTH_UID_MAP, &sock_uid);
-    if (whitelistMatch) return *whitelistMatch & WHITELISTMATCH;
+    uint8_t* whitelistMatch = find_map_entry(UID_OWNER_MAP, &sock_uid);
+    if (whitelistMatch) return *whitelistMatch & HAPPY_BOX_MATCH;
     return BPF_NOMATCH;
 }
 
 ELF_SEC(XT_BPF_BLACKLIST_PROG_NAME)
 int xt_bpf_blacklist_prog(struct __sk_buff* skb) {
     uint32_t sock_uid = get_socket_uid(skb);
-    uint8_t* blacklistMatch = find_map_entry(BANDWIDTH_UID_MAP, &sock_uid);
-    if (blacklistMatch) return *blacklistMatch & BLACKLISTMATCH;
+    uint8_t* blacklistMatch = find_map_entry(UID_OWNER_MAP, &sock_uid);
+    if (blacklistMatch) return *blacklistMatch & PENALTY_BOX_MATCH;
     return BPF_NOMATCH;
 }
diff --git a/bpfloader/bpf_kern.h b/bpfloader/bpf_kern.h
index b0efe77..e56033d 100644
--- a/bpfloader/bpf_kern.h
+++ b/bpfloader/bpf_kern.h
@@ -35,6 +35,7 @@
 #include <linux/in6.h>
 #include <linux/ip.h>
 #include <linux/ipv6.h>
+#include <stdbool.h>
 #include <stdint.h>
 #include "bpf/bpf_shared.h"
 
@@ -110,7 +111,7 @@
     }
 }
 
-static inline int bpf_owner_match(struct __sk_buff* skb, uint32_t uid) {
+static inline bool skip_owner_match(struct __sk_buff* skb) {
     int offset = -1;
     int ret = 0;
     if (skb->protocol == ETH_P_IP) {
@@ -120,13 +121,13 @@
         ret = bpf_skb_load_bytes(skb, offset, &proto, 1);
         if (!ret) {
             if (proto == IPPROTO_ESP) {
-                return 1;
+                return true;
             } else if (proto == IPPROTO_TCP) {
                 ret = bpf_skb_load_bytes(skb, IPPROTO_IHL_OFF, &ihl, 1);
                 ihl = ihl & 0x0F;
                 ret = bpf_skb_load_bytes(skb, ihl * 4 + TCP_FLAG_OFF, &flag, 1);
                 if (ret == 0 && (flag >> RST_OFFSET & 1)) {
-                    return BPF_PASS;
+                    return true;
                 }
             }
         }
@@ -136,40 +137,48 @@
         ret = bpf_skb_load_bytes(skb, offset, &proto, 1);
         if (!ret) {
             if (proto == IPPROTO_ESP) {
-                return BPF_PASS;
+                return true;
             } else if (proto == IPPROTO_TCP) {
                 uint16_t flag;
                 ret = bpf_skb_load_bytes(skb, sizeof(struct ipv6hdr) + TCP_FLAG_OFF, &flag, 1);
                 if (ret == 0 && (flag >> RST_OFFSET & 1)) {
-                    return BPF_PASS;
+                    return true;
                 }
             }
         }
     }
+    return false;
+}
+
+static __always_inline BpfConfig getConfig() {
+    uint32_t mapSettingKey = CONFIGURATION_KEY;
+    BpfConfig* config = find_map_entry(CONFIGURATION_MAP, &mapSettingKey);
+    if (!config) {
+        // Couldn't read configuration entry. Assume everything is disabled.
+        return DEFAULT_CONFIG;
+    }
+    return *config;
+}
+
+static inline int bpf_owner_match(struct __sk_buff* skb, uint32_t uid) {
+    if (skip_owner_match(skb)) return BPF_PASS;
 
     if ((uid <= MAX_SYSTEM_UID) && (uid >= MIN_SYSTEM_UID)) return BPF_PASS;
 
-    // In each of these maps, the entry with key UID_MAP_ENABLED tells us whether that
-    // map is enabled or not.
-    // TODO: replace this with a map of size one that contains a config structure defined in
-    // bpf_shared.h that can be written by userspace and read here.
-    uint32_t mapSettingKey = UID_MAP_ENABLED;
-    uint8_t* ownerMatch;
-    uint8_t* mapEnabled = find_map_entry(DOZABLE_UID_MAP, &mapSettingKey);
-    if (mapEnabled && *mapEnabled) {
-        ownerMatch = find_map_entry(DOZABLE_UID_MAP, &uid);
-        if (ownerMatch) return *ownerMatch;
+    BpfConfig enabledRules = getConfig();
+    if (!enabledRules) {
+        return BPF_PASS;
+    }
+
+    uint8_t* uidEntry = find_map_entry(UID_OWNER_MAP, &uid);
+    uint8_t uidRules = uidEntry ? *uidEntry : 0;
+    if ((enabledRules & DOZABLE_MATCH) && !(uidRules & DOZABLE_MATCH)) {
         return BPF_DROP;
     }
-    mapEnabled = find_map_entry(STANDBY_UID_MAP, &mapSettingKey);
-    if (mapEnabled && *mapEnabled) {
-        ownerMatch = find_map_entry(STANDBY_UID_MAP, &uid);
-        if (ownerMatch) return *ownerMatch;
+    if ((enabledRules & STANDBY_MATCH) && (uidRules & STANDBY_MATCH)) {
+        return BPF_DROP;
     }
-    mapEnabled = find_map_entry(POWERSAVE_UID_MAP, &mapSettingKey);
-    if (mapEnabled && *mapEnabled) {
-        ownerMatch = find_map_entry(POWERSAVE_UID_MAP, &uid);
-        if (ownerMatch) return *ownerMatch;
+    if ((enabledRules & POWERSAVE_MATCH) && !(uidRules & POWERSAVE_MATCH)) {
         return BPF_DROP;
     }
     return BPF_PASS;
diff --git a/libbpf/BpfUtils.cpp b/libbpf/BpfUtils.cpp
index 9a587fb..9502af6 100644
--- a/libbpf/BpfUtils.cpp
+++ b/libbpf/BpfUtils.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "BpfUtils"
+
 #include <linux/bpf.h>
 #include <linux/if_ether.h>
 #include <linux/in.h>
diff --git a/libbpf/include/bpf/BpfMap.h b/libbpf/include/bpf/BpfMap.h
index 51459f1..2e26d7a 100644
--- a/libbpf/include/bpf/BpfMap.h
+++ b/libbpf/include/bpf/BpfMap.h
@@ -165,7 +165,7 @@
         const auto deleteAllEntries = [](const Key& key, BpfMap<Key, Value>& map) {
             netdutils::Status res = map.deleteValue(key);
             if (!isOk(res) && (res.code() != ENOENT)) {
-                ALOGE("Failed to delete data(uid=%u): %s\n", key, strerror(res.code()));
+                ALOGE("Failed to delete data %s\n", strerror(res.code()));
             }
             return netdutils::status::ok;
         };
diff --git a/libbpf/include/bpf/BpfUtils.h b/libbpf/include/bpf/BpfUtils.h
index b13f6ac..5d0f248 100644
--- a/libbpf/include/bpf/BpfUtils.h
+++ b/libbpf/include/bpf/BpfUtils.h
@@ -104,6 +104,7 @@
 constexpr const int TAG_STATS_MAP_SIZE = 10000;
 constexpr const int IFACE_INDEX_NAME_MAP_SIZE = 1000;
 constexpr const int IFACE_STATS_MAP_SIZE = 1000;
+constexpr const int CONFIGURATION_MAP_SIZE = 1;
 constexpr const int UID_OWNER_MAP_SIZE = 2000;
 
 constexpr const char* BPF_EGRESS_PROG_PATH = BPF_PATH "/egress_prog";
@@ -122,10 +123,8 @@
 constexpr const char* TAG_STATS_MAP_PATH = BPF_PATH "/traffic_tag_stats_map";
 constexpr const char* IFACE_INDEX_NAME_MAP_PATH = BPF_PATH "/traffic_iface_index_name_map";
 constexpr const char* IFACE_STATS_MAP_PATH = BPF_PATH "/traffic_iface_stats_map";
-constexpr const char* DOZABLE_UID_MAP_PATH = BPF_PATH "/traffic_dozable_uid_map";
-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";
-constexpr const char* BANDWIDTH_UID_MAP_PATH = BPF_PATH "/traffic_bandwidth_uid_map";
+constexpr const char* CONFIGURATION_MAP_PATH = BPF_PATH "/traffic_configuration_map";
+constexpr const char* UID_OWNER_MAP_PATH = BPF_PATH "/traffic_uid_owner_map";
 
 constexpr const int OVERFLOW_COUNTERSET = 2;
 
diff --git a/libbpf/include/bpf/bpf_shared.h b/libbpf/include/bpf/bpf_shared.h
index f76820e..66aaac4 100644
--- a/libbpf/include/bpf/bpf_shared.h
+++ b/libbpf/include/bpf/bpf_shared.h
@@ -29,12 +29,22 @@
 #define UID_STATS_MAP 0xbfdaafffffffffff
 #define TAG_STATS_MAP 0xbfaaafffffffffff
 #define IFACE_STATS_MAP 0xbf1faceaafffffff
-#define DOZABLE_UID_MAP 0Xbfd0ab1e1dafffff
-#define STANDBY_UID_MAP 0Xbfadb1daffffffff
-#define POWERSAVE_UID_MAP 0Xbf0eae1dafffffff
-#define BANDWIDTH_UID_MAP 0xbfbad1d1daffffff
+#define CONFIGURATION_MAP 0Xbfc0fa0affffffff
+#define UID_OWNER_MAP 0xbfbad1d1daffffff
 
-enum BandwithMatchType { NO_MATCH, WHITELISTMATCH, BLACKLISTMATCH };
+enum UidOwnerMatchType {
+    NO_MATCH,
+    HAPPY_BOX_MATCH = (1 << 0),
+    PENALTY_BOX_MATCH = (1 << 1),
+    DOZABLE_MATCH = (1 << 2),
+    STANDBY_MATCH = (1 << 3),
+    POWERSAVE_MATCH = (1 << 4),
+};
+
+// TODO: change the configuration object from an 8-bit bitmask to an object with clearer
+// semantics, like a struct.
+typedef uint8_t BpfConfig;
+const BpfConfig DEFAULT_CONFIG = 0;
 
 // These are also defined in NetdConstants.h, but we want to minimize the number of headers
 // included by the BPF kernel program.
@@ -42,4 +52,4 @@
 // NetdConstants.h can also include it from there.
 #define MIN_SYSTEM_UID 0
 #define MAX_SYSTEM_UID 9999
-#define UID_MAP_ENABLED UINT32_MAX
+#define CONFIGURATION_KEY 1
diff --git a/server/BandwidthController.cpp b/server/BandwidthController.cpp
index a01ad41..fcbe266 100644
--- a/server/BandwidthController.cpp
+++ b/server/BandwidthController.cpp
@@ -152,13 +152,12 @@
  */
 
 const std::string COMMIT_AND_CLOSE = "COMMIT\n";
-const std::string HAPPY_BOX_WHITELIST_COMMAND = StringPrintf(
-    "-I bw_happy_box -m owner --uid-owner %d-%d --jump RETURN", 0, MAX_SYSTEM_UID);
-const std::string BPF_HAPPY_BOX_WHITELIST_COMMAND =
-    StringPrintf("-I bw_happy_box -m bpf --object-pinned %s -j RETURN", XT_BPF_WHITELIST_PROG_PATH);
-const std::string BPF_PENALTY_BOX_BLACKLIST_COMMAND =
-    StringPrintf("-I bw_penalty_box -m bpf --object-pinned %s -j REJECT",
-                 XT_BPF_BLACKLIST_PROG_PATH);
+const std::string HAPPY_BOX_MATCH_WHITELIST_COMMAND =
+        StringPrintf("-I bw_happy_box -m owner --uid-owner %d-%d --jump RETURN", 0, MAX_SYSTEM_UID);
+const std::string BPF_HAPPY_BOX_MATCH_WHITELIST_COMMAND = StringPrintf(
+        "-I bw_happy_box -m bpf --object-pinned %s -j RETURN", XT_BPF_WHITELIST_PROG_PATH);
+const std::string BPF_PENALTY_BOX_MATCH_BLACKLIST_COMMAND = StringPrintf(
+        "-I bw_penalty_box -m bpf --object-pinned %s -j REJECT", XT_BPF_BLACKLIST_PROG_PATH);
 
 static const std::vector<std::string> IPT_FLUSH_COMMANDS = {
     /*
@@ -218,50 +217,50 @@
 
 const std::vector<std::string> getBasicAccountingCommands(const bool useBpf) {
     const std::vector<std::string> ipt_basic_accounting_commands = {
-        "*filter",
-        // Prevents IPSec double counting (ESP and UDP-encap-ESP respectively)
-        "-A bw_INPUT -p esp -j RETURN",
-        StringPrintf("-A bw_INPUT -m mark --mark 0x%x/0x%x -j RETURN",
-                     uidBillingMask, uidBillingMask),
-        "-A bw_INPUT -m owner --socket-exists", /* This is a tracking rule. */
-        StringPrintf("-A bw_INPUT -j MARK --or-mark 0x%x", uidBillingMask),
+            "*filter",
+            // Prevents IPSec double counting (ESP and UDP-encap-ESP respectively)
+            "-A bw_INPUT -p esp -j RETURN",
+            StringPrintf("-A bw_INPUT -m mark --mark 0x%x/0x%x -j RETURN", uidBillingMask,
+                         uidBillingMask),
+            "-A bw_INPUT -m owner --socket-exists", /* This is a tracking rule. */
+            StringPrintf("-A bw_INPUT -j MARK --or-mark 0x%x", uidBillingMask),
 
-        // Prevents IPSec double counting (Tunnel mode and Transport mode,
-        // respectively)
-        "-A bw_OUTPUT -o " IPSEC_IFACE_PREFIX "+ -j RETURN",
-        "-A bw_OUTPUT -m policy --pol ipsec --dir out -j RETURN",
-        "-A bw_OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
+            // Prevents IPSec double counting (Tunnel mode and Transport mode,
+            // respectively)
+            "-A bw_OUTPUT -o " IPSEC_IFACE_PREFIX "+ -j RETURN",
+            "-A bw_OUTPUT -m policy --pol ipsec --dir out -j RETURN",
+            "-A bw_OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
 
-        "-A bw_costly_shared --jump bw_penalty_box",
-        useBpf ? BPF_PENALTY_BOX_BLACKLIST_COMMAND : "",
-        "-A bw_penalty_box --jump bw_happy_box",
-        "-A bw_happy_box --jump bw_data_saver",
-        "-A bw_data_saver -j RETURN",
-        useBpf ? BPF_HAPPY_BOX_WHITELIST_COMMAND : HAPPY_BOX_WHITELIST_COMMAND,
-        "COMMIT",
+            "-A bw_costly_shared --jump bw_penalty_box",
+            useBpf ? BPF_PENALTY_BOX_MATCH_BLACKLIST_COMMAND : "",
+            "-A bw_penalty_box --jump bw_happy_box", "-A bw_happy_box --jump bw_data_saver",
+            "-A bw_data_saver -j RETURN",
+            useBpf ? BPF_HAPPY_BOX_MATCH_WHITELIST_COMMAND : HAPPY_BOX_MATCH_WHITELIST_COMMAND,
+            "COMMIT",
 
-        "*raw",
-        // Prevents IPSec double counting (Tunnel mode and Transport mode,
-        // respectively)
-        "-A bw_raw_PREROUTING -i " IPSEC_IFACE_PREFIX "+ -j RETURN",
-        "-A bw_raw_PREROUTING -m policy --pol ipsec --dir in -j RETURN",
-        "-A bw_raw_PREROUTING -m owner --socket-exists", /* This is a tracking rule. */
-        useBpf ? StringPrintf("-A bw_raw_PREROUTING -m bpf --object-pinned %s",
-                              XT_BPF_INGRESS_PROG_PATH) : "",
-        "COMMIT",
+            "*raw",
+            // Prevents IPSec double counting (Tunnel mode and Transport mode,
+            // respectively)
+            "-A bw_raw_PREROUTING -i " IPSEC_IFACE_PREFIX "+ -j RETURN",
+            "-A bw_raw_PREROUTING -m policy --pol ipsec --dir in -j RETURN",
+            "-A bw_raw_PREROUTING -m owner --socket-exists", /* This is a tracking rule. */
+            useBpf ? StringPrintf("-A bw_raw_PREROUTING -m bpf --object-pinned %s",
+                                  XT_BPF_INGRESS_PROG_PATH)
+                   : "",
+            "COMMIT",
 
-        "*mangle",
-        // Prevents IPSec double counting (Tunnel mode and Transport mode,
-        // respectively)
-        "-A bw_mangle_POSTROUTING -o " IPSEC_IFACE_PREFIX "+ -j RETURN",
-        "-A bw_mangle_POSTROUTING -m policy --pol ipsec --dir out -j RETURN",
-        "-A bw_mangle_POSTROUTING -m owner --socket-exists", /* This is a tracking rule. */
-        StringPrintf("-A bw_mangle_POSTROUTING -j MARK --set-mark 0x0/0x%x",
-                     uidBillingMask), // Clear the mark before sending this packet
-        useBpf ? StringPrintf("-A bw_mangle_POSTROUTING -m bpf --object-pinned %s",
-                              XT_BPF_EGRESS_PROG_PATH) : "",
-        COMMIT_AND_CLOSE
-    };
+            "*mangle",
+            // Prevents IPSec double counting (Tunnel mode and Transport mode,
+            // respectively)
+            "-A bw_mangle_POSTROUTING -o " IPSEC_IFACE_PREFIX "+ -j RETURN",
+            "-A bw_mangle_POSTROUTING -m policy --pol ipsec --dir out -j RETURN",
+            "-A bw_mangle_POSTROUTING -m owner --socket-exists", /* This is a tracking rule. */
+            StringPrintf("-A bw_mangle_POSTROUTING -j MARK --set-mark 0x0/0x%x",
+                         uidBillingMask),  // Clear the mark before sending this packet
+            useBpf ? StringPrintf("-A bw_mangle_POSTROUTING -m bpf --object-pinned %s",
+                                  XT_BPF_EGRESS_PROG_PATH)
+                   : "",
+            COMMIT_AND_CLOSE};
     return ipt_basic_accounting_commands;
 }
 
@@ -370,9 +369,9 @@
                                                const std::string& chain, IptJumpOp jumpHandling,
                                                IptOp op) {
     if (mBpfSupported) {
-      Status status = gCtls->trafficCtrl.updateBandwidthUidMap(appStrUids, jumpHandling, op);
-      if (!isOk(status)) {
-          ALOGE("unable to update the Bandwidth Uid Map: %s", toString(status).c_str());
+        Status status = gCtls->trafficCtrl.updateUidOwnerMap(appStrUids, jumpHandling, op);
+        if (!isOk(status)) {
+            ALOGE("unable to update the Bandwidth Uid Map: %s", toString(status).c_str());
       }
       return status.code();
     }
diff --git a/server/FirewallController.cpp b/server/FirewallController.cpp
index ff1f19d..4e5e3e5 100644
--- a/server/FirewallController.cpp
+++ b/server/FirewallController.cpp
@@ -41,9 +41,6 @@
 using android::base::Split;
 using android::base::StringAppendF;
 using android::base::StringPrintf;
-using android::bpf::DOZABLE_UID_MAP_PATH;
-using android::bpf::POWERSAVE_UID_MAP_PATH;
-using android::bpf::STANDBY_UID_MAP_PATH;
 using android::net::gCtls;
 
 namespace {
diff --git a/server/IptablesRestoreControllerTest.cpp b/server/IptablesRestoreControllerTest.cpp
index 7ccb1ce..e34f644 100644
--- a/server/IptablesRestoreControllerTest.cpp
+++ b/server/IptablesRestoreControllerTest.cpp
@@ -40,9 +40,6 @@
 
 using android::base::Join;
 using android::base::StringPrintf;
-using android::bpf::DOZABLE_UID_MAP_PATH;
-using android::bpf::STANDBY_UID_MAP_PATH;
-using android::bpf::POWERSAVE_UID_MAP_PATH;
 using android::netdutils::ScopedMockSyscalls;
 using testing::Return;
 using testing::StrictMock;
diff --git a/server/TrafficController.cpp b/server/TrafficController.cpp
index 4426e58..bb7a0ad 100644
--- a/server/TrafficController.cpp
+++ b/server/TrafficController.cpp
@@ -71,6 +71,27 @@
 constexpr int kSockDiagMsgType = SOCK_DIAG_BY_FAMILY;
 constexpr int kSockDiagDoneMsgType = NLMSG_DONE;
 
+#define UID_MATCH_MSG_TRANS(result, target, match)       \
+    do {                                                 \
+        if (match & target) {                            \
+            result.append(StringPrintf(" %s", #target)); \
+            match &= ~target;                            \
+        }                                                \
+    } while (0)
+
+const std::string uidMatchTypeToString(uint8_t match) {
+    std::string matchType;
+    UID_MATCH_MSG_TRANS(matchType, HAPPY_BOX_MATCH, match);
+    UID_MATCH_MSG_TRANS(matchType, PENALTY_BOX_MATCH, match);
+    UID_MATCH_MSG_TRANS(matchType, DOZABLE_MATCH, match);
+    UID_MATCH_MSG_TRANS(matchType, STANDBY_MATCH, match);
+    UID_MATCH_MSG_TRANS(matchType, POWERSAVE_MATCH, match);
+    if (match) {
+        return StringPrintf("Unknown match: %u", match);
+    }
+    return matchType;
+}
+
 StatusOr<std::unique_ptr<NetlinkListenerInterface>> makeSkDestroyListener() {
     const auto& sys = sSyscalls.get();
     ASSIGN_OR_RETURN(auto event, sys.eventfd(0, EFD_CLOEXEC));
@@ -117,7 +138,7 @@
 
 Status initialOwnerMap(BpfMap<uint32_t, uint8_t>& map) {
     map.clear();
-    uint32_t mapSettingKey = UID_MAP_ENABLED;
+    uint32_t mapSettingKey = CONFIGURATION_KEY;
     uint8_t defaultMapState = 0;
     return map.writeValue(mapSettingKey, defaultMapState, BPF_NOEXIST);
 }
@@ -156,29 +177,22 @@
                                         "IfaceIndexNameMap", false));
 
     RETURN_IF_NOT_OK(
-        mDozableUidMap.getOrCreate(UID_OWNER_MAP_SIZE, DOZABLE_UID_MAP_PATH, BPF_MAP_TYPE_HASH));
-    RETURN_IF_NOT_OK(changeOwnerAndMode(DOZABLE_UID_MAP_PATH, AID_ROOT, "DozableUidMap", true));
-    RETURN_IF_NOT_OK(initialOwnerMap(mDozableUidMap));
-
-    RETURN_IF_NOT_OK(
-        mStandbyUidMap.getOrCreate(UID_OWNER_MAP_SIZE, STANDBY_UID_MAP_PATH, BPF_MAP_TYPE_HASH));
-    RETURN_IF_NOT_OK(changeOwnerAndMode(STANDBY_UID_MAP_PATH, AID_ROOT, "StandbyUidMap", true));
-    RETURN_IF_NOT_OK(initialOwnerMap(mStandbyUidMap));
-
-    RETURN_IF_NOT_OK(mPowerSaveUidMap.getOrCreate(UID_OWNER_MAP_SIZE, POWERSAVE_UID_MAP_PATH,
-                                                  BPF_MAP_TYPE_HASH));
-    RETURN_IF_NOT_OK(changeOwnerAndMode(POWERSAVE_UID_MAP_PATH, AID_ROOT, "PowerSaveUidMap", true));
-    RETURN_IF_NOT_OK(initialOwnerMap(mPowerSaveUidMap));
-
-    RETURN_IF_NOT_OK(
         mIfaceStatsMap.getOrCreate(IFACE_STATS_MAP_SIZE, IFACE_STATS_MAP_PATH, BPF_MAP_TYPE_HASH));
     RETURN_IF_NOT_OK(changeOwnerAndMode(IFACE_STATS_MAP_PATH, AID_NET_BW_STATS, "IfaceStatsMap",
                                         false));
 
-    RETURN_IF_NOT_OK(mBandwidthUidMap.getOrCreate(UID_OWNER_MAP_SIZE, BANDWIDTH_UID_MAP_PATH,
-                                                  BPF_MAP_TYPE_HASH));
-    RETURN_IF_NOT_OK(changeOwnerAndMode(BANDWIDTH_UID_MAP_PATH, AID_ROOT, "BandwidthUidMap", true));
-    mBandwidthUidMap.clear();
+    RETURN_IF_NOT_OK(mConfigurationMap.getOrCreate(CONFIGURATION_MAP_SIZE, CONFIGURATION_MAP_PATH,
+                                                   BPF_MAP_TYPE_HASH));
+    RETURN_IF_NOT_OK(
+            changeOwnerAndMode(CONFIGURATION_MAP_PATH, AID_ROOT, "ConfigurationMap", true));
+    uint32_t key = CONFIGURATION_KEY;
+    uint8_t initialConfiguration = DEFAULT_CONFIG;
+    RETURN_IF_NOT_OK(mConfigurationMap.writeValue(key, initialConfiguration, BPF_ANY));
+
+    RETURN_IF_NOT_OK(
+            mUidOwnerMap.getOrCreate(UID_OWNER_MAP_SIZE, UID_OWNER_MAP_PATH, BPF_MAP_TYPE_HASH));
+    RETURN_IF_NOT_OK(changeOwnerAndMode(UID_OWNER_MAP_PATH, AID_ROOT, "UidOwnerMap", true));
+    mUidOwnerMap.clear();
     return netdutils::status::ok;
 }
 
@@ -241,38 +255,9 @@
     std::vector<const char*> prog_args{
         "/system/bin/bpfloader",
     };
-    int ret = access(BPF_INGRESS_PROG_PATH, R_OK);
-    if (ret != 0 && errno == ENOENT) {
-        prog_args.push_back((char*)"-i");
-    }
-    ret = access(BPF_EGRESS_PROG_PATH, R_OK);
-    if (ret != 0 && errno == ENOENT) {
-        prog_args.push_back((char*)"-e");
-    }
-    ret = access(XT_BPF_INGRESS_PROG_PATH, R_OK);
-    if (ret != 0 && errno == ENOENT) {
-        prog_args.push_back((char*)"-p");
-    }
-    ret = access(XT_BPF_EGRESS_PROG_PATH, R_OK);
-    if (ret != 0 && errno == ENOENT) {
-        prog_args.push_back((char*)"-m");
-    }
-    ret = access(XT_BPF_WHITELIST_PROG_PATH, R_OK);
-    if (ret != 0 && errno == ENOENT) {
-        prog_args.push_back((char*)"-w");
-    }
-    ret = access(XT_BPF_BLACKLIST_PROG_PATH, R_OK);
-    if (ret != 0 && errno == ENOENT) {
-        prog_args.push_back((char*)"-b");
-    }
-
-    if (prog_args.size() == 1) {
-        // all program are loaded already.
-        return netdutils::status::ok;
-    }
 
     prog_args.push_back(nullptr);
-    ret = android_fork_execvp(prog_args.size(), (char**)prog_args.data(), status, false, true);
+    int ret = android_fork_execvp(prog_args.size(), (char**) prog_args.data(), status, false, true);
     if (ret) {
         ret = errno;
         ALOGE("failed to execute %s: %s", prog_args[0], strerror(errno));
@@ -429,17 +414,13 @@
     return 0;
 }
 
-Status TrafficController::updateOwnerMapEntry(BpfMap<uint32_t, uint8_t>& map, uid_t uid,
-                                              FirewallRule rule, FirewallType type) {
-    if (uid == UID_MAP_ENABLED) {
-        return statusFromErrno(-EINVAL, "This uid is reserved for map state");
-    }
-
+Status TrafficController::updateOwnerMapEntry(UidOwnerMatchType match, uid_t uid, FirewallRule rule,
+                                              FirewallType type) {
+    std::lock_guard<std::mutex> guard(mOwnerMatchMutex);
     if ((rule == ALLOW && type == WHITELIST) || (rule == DENY && type == BLACKLIST)) {
-        uint8_t flag = (type == WHITELIST) ? BPF_PASS : BPF_DROP;
-        RETURN_IF_NOT_OK(map.writeValue(uid, flag, BPF_ANY));
+        RETURN_IF_NOT_OK(addMatch(mUidOwnerMap, uid, match));
     } else if ((rule == ALLOW && type == BLACKLIST) || (rule == DENY && type == WHITELIST)) {
-        RETURN_IF_NOT_OK(map.deleteValue(uid));
+        RETURN_IF_NOT_OK(removeMatch(mUidOwnerMap, uid, match));
     } else {
         //Cannot happen.
         return statusFromErrno(-EINVAL, "");
@@ -447,24 +428,53 @@
     return netdutils::status::ok;
 }
 
-BandwithMatchType TrafficController::jumpOpToMatch(BandwidthController::IptJumpOp jumpHandling) {
+UidOwnerMatchType TrafficController::jumpOpToMatch(BandwidthController::IptJumpOp jumpHandling) {
     switch (jumpHandling) {
         case BandwidthController::IptJumpReject:
-            return BLACKLISTMATCH;
+            return PENALTY_BOX_MATCH;
         case BandwidthController::IptJumpReturn:
-            return WHITELISTMATCH;
+            return HAPPY_BOX_MATCH;
         case BandwidthController::IptJumpNoAdd:
             return NO_MATCH;
     }
 }
 
-Status TrafficController::updateBandwidthUidMap(const std::vector<std::string>& appStrUids,
-                                                BandwidthController::IptJumpOp jumpHandling,
-                                                BandwidthController::IptOp op) {
-    uint8_t command = jumpOpToMatch(jumpHandling);
-    if (command == NO_MATCH) {
-        return statusFromErrno(EINVAL, StringPrintf("invalid IptJumpOp: %d, command: %d",
-                                                    jumpHandling, command));
+Status TrafficController::removeMatch(BpfMap<uint32_t, uint8_t>& map, uint32_t uid,
+                                      UidOwnerMatchType match) {
+    auto oldMatch = map.readValue(uid);
+    if (isOk(oldMatch)) {
+        uint8_t newMatch = oldMatch.value() & ~match;
+        if (newMatch == 0) {
+            RETURN_IF_NOT_OK(map.deleteValue(uid));
+        } else {
+            RETURN_IF_NOT_OK(map.writeValue(uid, newMatch, BPF_ANY));
+        }
+    } else {
+        return statusFromErrno(ENOENT, StringPrintf("uid: %u does not exist in map", uid));
+    }
+    return netdutils::status::ok;
+}
+
+Status TrafficController::addMatch(BpfMap<uint32_t, uint8_t>& map, uint32_t uid,
+                                   UidOwnerMatchType match) {
+    auto oldMatch = map.readValue(uid);
+    if (isOk(oldMatch)) {
+        uint8_t newMatch = oldMatch.value() | match;
+        map.writeValue((uint32_t) uid, newMatch, BPF_ANY);
+    } else {
+        RETURN_IF_NOT_OK(map.writeValue(uid, match, BPF_ANY));
+    }
+    return netdutils::status::ok;
+}
+
+Status TrafficController::updateUidOwnerMap(const std::vector<std::string>& appStrUids,
+                                            BandwidthController::IptJumpOp jumpHandling,
+                                            BandwidthController::IptOp op) {
+    std::lock_guard<std::mutex> guard(mOwnerMatchMutex);
+    UidOwnerMatchType match = jumpOpToMatch(jumpHandling);
+    if (match == NO_MATCH) {
+        return statusFromErrno(
+                EINVAL, StringPrintf("invalid IptJumpOp: %d, command: %d", jumpHandling, match));
     }
     for (const auto& appStrUid : appStrUids) {
         char* endPtr;
@@ -474,27 +484,13 @@
                return statusFromErrno(errno, "invalid uid string:" + appStrUid);
         }
 
-        auto match = mBandwidthUidMap.readValue(uid);
         if (op == BandwidthController::IptOpDelete) {
-            if(!isOk(match)) {
-                return statusFromErrno(EINVAL, StringPrintf("uid(%ld): %s does not exist in map",
-                                                            uid, appStrUid.c_str()));
-            }
-            uint8_t newValue = match.value() & ~command;
-            if (newValue == 0) {
-                RETURN_IF_NOT_OK(mBandwidthUidMap.deleteValue((uint32_t)uid));
-            } else {
-                RETURN_IF_NOT_OK(mBandwidthUidMap.writeValue((uint32_t)uid, newValue, BPF_ANY));
-            }
+            RETURN_IF_NOT_OK(removeMatch(mUidOwnerMap, uid, match));
         } else if (op == BandwidthController::IptOpInsert) {
-            uint8_t newValue = command;
-            if (isOk(match)) {
-                newValue |= match.value();
-            }
-            RETURN_IF_NOT_OK(mBandwidthUidMap.writeValue((uint32_t)uid, newValue, BPF_ANY));
+            RETURN_IF_NOT_OK(addMatch(mUidOwnerMap, uid, match));
         } else {
             // Cannot happen.
-            return statusFromErrno(EINVAL, StringPrintf("invalid IptOp: %d, %d", op, command));
+            return statusFromErrno(EINVAL, StringPrintf("invalid IptOp: %d, %d", op, match));
         }
     }
     return netdutils::status::ok;
@@ -502,7 +498,6 @@
 
 int TrafficController::changeUidOwnerRule(ChildChain chain, uid_t uid, FirewallRule rule,
                                           FirewallType type) {
-    std::lock_guard<std::mutex> guard(mOwnerMatchMutex);
     if (!ebpfSupported) {
         ALOGE("bpf is not set up, should use iptables rule");
         return -ENOSYS;
@@ -510,13 +505,13 @@
     Status res;
     switch (chain) {
         case DOZABLE:
-            res = updateOwnerMapEntry(mDozableUidMap, uid, rule, type);
+            res = updateOwnerMapEntry(DOZABLE_MATCH, uid, rule, type);
             break;
         case STANDBY:
-            res = updateOwnerMapEntry(mStandbyUidMap, uid, rule, type);
+            res = updateOwnerMapEntry(STANDBY_MATCH, uid, rule, type);
             break;
         case POWERSAVE:
-            res = updateOwnerMapEntry(mPowerSaveUidMap, uid, rule, type);
+            res = updateOwnerMapEntry(POWERSAVE_MATCH, uid, rule, type);
             break;
         case NONE:
         default:
@@ -530,33 +525,32 @@
     return 0;
 }
 
-Status TrafficController::replaceUidsInMap(BpfMap<uint32_t, uint8_t>& map,
-                                           const std::vector<int32_t>& uids, FirewallRule rule,
-                                           FirewallType type) {
+Status TrafficController::replaceUidsInMap(const UidOwnerMatchType match,
+                                           const std::vector<int32_t>& uids) {
+    std::lock_guard<std::mutex> guard(mOwnerMatchMutex);
     std::set<int32_t> uidSet(uids.begin(), uids.end());
     std::vector<uint32_t> uidsToDelete;
     auto getUidsToDelete = [&uidsToDelete, &uidSet](const uint32_t& key,
                                                     const BpfMap<uint32_t, uint8_t>&) {
-        if (key != UID_MAP_ENABLED && uidSet.find((int32_t)key) == uidSet.end()) {
+        if (uidSet.find((int32_t) key) == uidSet.end()) {
             uidsToDelete.push_back(key);
         }
         return netdutils::status::ok;
     };
-    RETURN_IF_NOT_OK(map.iterate(getUidsToDelete));
+    RETURN_IF_NOT_OK(mUidOwnerMap.iterate(getUidsToDelete));
 
     for(auto uid : uidsToDelete) {
-        RETURN_IF_NOT_OK(map.deleteValue(uid));
+        RETURN_IF_NOT_OK(removeMatch(mUidOwnerMap, uid, match));
     }
 
     for (auto uid : uids) {
-        RETURN_IF_NOT_OK(updateOwnerMapEntry(map, uid, rule, type));
+        RETURN_IF_NOT_OK(addMatch(mUidOwnerMap, uid, match));
     }
     return netdutils::status::ok;
 }
 
 int TrafficController::replaceUidOwnerMap(const std::string& name, bool isWhitelist,
                                           const std::vector<int32_t>& uids) {
-    std::lock_guard<std::mutex> guard(mOwnerMatchMutex);
     FirewallRule rule;
     FirewallType type;
     if (isWhitelist) {
@@ -568,11 +562,11 @@
     }
     Status res;
     if (!name.compare(FirewallController::LOCAL_DOZABLE)) {
-        res = replaceUidsInMap(mDozableUidMap, uids, rule, type);
+        res = replaceUidsInMap(DOZABLE_MATCH, uids);
     } else if (!name.compare(FirewallController::LOCAL_STANDBY)) {
-        res = replaceUidsInMap(mStandbyUidMap, uids, rule, type);
+        res = replaceUidsInMap(STANDBY_MATCH, uids);
     } else if (!name.compare(FirewallController::LOCAL_POWERSAVE)) {
-        res = replaceUidsInMap(mPowerSaveUidMap, uids, rule, type);
+        res = replaceUidsInMap(POWERSAVE_MATCH, uids);
     } else {
         ALOGE("unknown chain name: %s", name.c_str());
         return -EINVAL;
@@ -586,22 +580,32 @@
 
 int TrafficController::toggleUidOwnerMap(ChildChain chain, bool enable) {
     std::lock_guard<std::mutex> guard(mOwnerMatchMutex);
-    uint32_t keyUid = UID_MAP_ENABLED;
-    uint8_t mapState = enable ? 1 : 0;
+    uint32_t key = CONFIGURATION_KEY;
+    auto oldConfiguration = mConfigurationMap.readValue(key);
+    if (!isOk(oldConfiguration)) {
+        ALOGE("Cannot read the old configuration from map: %s",
+              oldConfiguration.status().msg().c_str());
+        return -oldConfiguration.status().code();
+    }
     Status res;
+    BpfConfig newConfiguration;
+    uint8_t match;
     switch (chain) {
         case DOZABLE:
-            res = mDozableUidMap.writeValue(keyUid, mapState, BPF_EXIST);
+            match = DOZABLE_MATCH;
             break;
         case STANDBY:
-            res = mStandbyUidMap.writeValue(keyUid, mapState, BPF_EXIST);
+            match = STANDBY_MATCH;
             break;
         case POWERSAVE:
-            res = mPowerSaveUidMap.writeValue(keyUid, mapState, BPF_EXIST);
+            match = POWERSAVE_MATCH;
             break;
         default:
             return -EINVAL;
     }
+    newConfiguration =
+            enable ? (oldConfiguration.value() | match) : (oldConfiguration.value() & (~match));
+    res = mConfigurationMap.writeValue(key, newConfiguration, BPF_EXIST);
     if (!isOk(res)) {
         ALOGE("Failed to toggleUidOwnerMap(%d): %s", chain, res.msg().c_str());
     }
@@ -670,14 +674,10 @@
                getMapStatus(mIfaceIndexNameMap.getMap(), IFACE_INDEX_NAME_MAP_PATH).c_str());
     dw.println("mIfaceStatsMap status: %s",
                getMapStatus(mIfaceStatsMap.getMap(), IFACE_STATS_MAP_PATH).c_str());
-    dw.println("mDozableUidMap status: %s",
-               getMapStatus(mDozableUidMap.getMap(), DOZABLE_UID_MAP_PATH).c_str());
-    dw.println("mStandbyUidMap status: %s",
-               getMapStatus(mStandbyUidMap.getMap(), STANDBY_UID_MAP_PATH).c_str());
-    dw.println("mPowerSaveUidMap status: %s",
-               getMapStatus(mPowerSaveUidMap.getMap(), POWERSAVE_UID_MAP_PATH).c_str());
-    dw.println("mBandwidthUidMap status: %s",
-               getMapStatus(mBandwidthUidMap.getMap(), BANDWIDTH_UID_MAP_PATH).c_str());
+    dw.println("mConfigurationMap status: %s",
+               getMapStatus(mConfigurationMap.getMap(), CONFIGURATION_MAP_PATH).c_str());
+    dw.println("mUidOwnerMap status: %s",
+               getMapStatus(mUidOwnerMap.getMap(), UID_OWNER_MAP_PATH).c_str());
 
     dw.blankline();
     dw.println("Cgroup ingress program status: %s",
@@ -799,29 +799,24 @@
         dw.println("mIfaceStatsMap print end with error: %s", res.msg().c_str());
     }
 
-    // Print owner match uid maps
-    dumpBpfMap("mDozableUidMap", dw, "");
-    res = mDozableUidMap.iterateWithValue(printUidInfo);
-    if (!isOk(res)) {
-        dw.println("mDozableUidMap print end with error: %s", res.msg().c_str());
-    }
+    dw.blankline();
 
-    dumpBpfMap("mStandbyUidMap", dw, "");
-    res = mStandbyUidMap.iterateWithValue(printUidInfo);
-    if (!isOk(res)) {
-        dw.println("mDozableUidMap print end with error: %s", res.msg().c_str());
+    uint32_t key = CONFIGURATION_KEY;
+    auto configuration = mConfigurationMap.readValue(key);
+    if (isOk(configuration)) {
+        dw.println("current configuration: %d", configuration.value());
+    } else {
+        dw.println("mConfigurationMap read with error: %s", configuration.status().msg().c_str());
     }
-
-    dumpBpfMap("mPowerSaveUidMap", dw, "");
-    res = mPowerSaveUidMap.iterateWithValue(printUidInfo);
+    dumpBpfMap("mUidOwnerMap", dw, "");
+    const auto printUidMatchInfo = [&dw](const uint32_t& key, const uint8_t& value,
+                                         const BpfMap<uint32_t, uint8_t>&) {
+        dw.println("%u %s", key, uidMatchTypeToString(value).c_str());
+        return netdutils::status::ok;
+    };
+    res = mUidOwnerMap.iterateWithValue(printUidMatchInfo);
     if (!isOk(res)) {
-        dw.println("mDozableUidMap print end with error: %s", res.msg().c_str());
-    }
-
-    dumpBpfMap("mBandwidthUidMap", dw, "");
-    res = mBandwidthUidMap.iterateWithValue(printUidInfo);
-    if (!isOk(res)) {
-        dw.println("mBandwidthUidMap print end with error: %s", res.msg().c_str());
+        dw.println("mUidOwnerMap print end with error: %s", res.msg().c_str());
     }
 }
 
diff --git a/server/TrafficController.h b/server/TrafficController.h
index e4e32f4..afc78a5 100644
--- a/server/TrafficController.h
+++ b/server/TrafficController.h
@@ -99,18 +99,16 @@
     int replaceUidOwnerMap(const std::string& name, bool isWhitelist,
                            const std::vector<int32_t>& uids);
 
-    netdutils::Status updateOwnerMapEntry(BpfMap<uint32_t, uint8_t>& map, uid_t uid,
-                                          FirewallRule rule, FirewallType type);
+    netdutils::Status updateOwnerMapEntry(UidOwnerMatchType match, uid_t uid, FirewallRule rule,
+                                          FirewallType type);
 
     void dump(DumpWriter& dw, bool verbose);
 
-    netdutils::Status replaceUidsInMap(BpfMap<uint32_t, uint8_t>& map,
-                                       const std::vector<int32_t>& uids, FirewallRule rule,
-                                       FirewallType type);
+    netdutils::Status replaceUidsInMap(UidOwnerMatchType match, const std::vector<int32_t>& uids);
 
-    netdutils::Status updateBandwidthUidMap(const std::vector<std::string>& appStrUids,
-                                            BandwidthController::IptJumpOp jumpHandling,
-                                            BandwidthController::IptOp op);
+    netdutils::Status updateUidOwnerMap(const std::vector<std::string>& appStrUids,
+                                        BandwidthController::IptJumpOp jumpHandling,
+                                        BandwidthController::IptOp op);
     static const String16 DUMP_KEYWORD;
 
     int toggleUidOwnerMap(ChildChain chain, bool enable);
@@ -180,30 +178,24 @@
     BpfMap<uint32_t, StatsValue> mIfaceStatsMap;
 
     /*
-     * mDozableUidMap: Store uids that have related rules in dozable mode owner match
-     * chain.
-     */
-    BpfMap<uint32_t, uint8_t> mDozableUidMap GUARDED_BY(mOwnerMatchMutex);
-
-    /*
-     * mStandbyUidMap: Store uids that have related rules in standby mode owner match
-     * chain.
-     */
-    BpfMap<uint32_t, uint8_t> mStandbyUidMap GUARDED_BY(mOwnerMatchMutex);
-
-    /*
      * mPowerSaveUidMap: Store uids that have related rules in power save mode owner match
      * chain.
      */
-    BpfMap<uint32_t, uint8_t> mPowerSaveUidMap GUARDED_BY(mOwnerMatchMutex);
+    BpfMap<uint32_t, uint8_t> mConfigurationMap GUARDED_BY(mOwnerMatchMutex);
 
     /*
-     * mBandwidthUidMap: Store uids that are used for bandwidth control uid match.
+     * mUidOwnerMap: Store uids that are used for bandwidth control uid match.
      */
-    BpfMap<uint32_t, uint8_t> mBandwidthUidMap;
+    BpfMap<uint32_t, uint8_t> mUidOwnerMap GUARDED_BY(mOwnerMatchMutex);
 
     std::unique_ptr<NetlinkListenerInterface> mSkDestroyListener;
 
+    netdutils::Status removeMatch(BpfMap<uint32_t, uint8_t>& map, uint32_t uid,
+                                  UidOwnerMatchType match) REQUIRES(mOwnerMatchMutex);
+
+    netdutils::Status addMatch(BpfMap<uint32_t, uint8_t>& map, uint32_t uid,
+                               UidOwnerMatchType match) REQUIRES(mOwnerMatchMutex);
+
     bool ebpfSupported;
 
     std::mutex mOwnerMatchMutex;
@@ -213,7 +205,7 @@
 
     netdutils::Status initMaps();
 
-    BandwithMatchType jumpOpToMatch(BandwidthController::IptJumpOp jumpHandling);
+    UidOwnerMatchType jumpOpToMatch(BandwidthController::IptJumpOp jumpHandling);
     // For testing
     friend class TrafficControllerTest;
 };
diff --git a/server/TrafficControllerTest.cpp b/server/TrafficControllerTest.cpp
index 359ea8a..c3b6a6e 100644
--- a/server/TrafficControllerTest.cpp
+++ b/server/TrafficControllerTest.cpp
@@ -75,10 +75,8 @@
     BpfMap<uint32_t, StatsValue> mFakeAppUidStatsMap;
     BpfMap<StatsKey, StatsValue> mFakeUidStatsMap;
     BpfMap<StatsKey, StatsValue> mFakeTagStatsMap;
-    BpfMap<uint32_t, uint8_t> mFakeDozableUidMap;
-    BpfMap<uint32_t, uint8_t> mFakeStandbyUidMap;
-    BpfMap<uint32_t, uint8_t> mFakePowerSaveUidMap;
-    BpfMap<uint32_t, uint8_t> mFakeBandwidthUidMap;
+    BpfMap<uint32_t, uint8_t> mFakeConfigurationMap;
+    BpfMap<uint32_t, uint8_t> mFakeUidOwnerMap;
 
     void SetUp() {
         std::lock_guard<std::mutex> ownerGuard(mTc.mOwnerMatchMutex);
@@ -104,21 +102,13 @@
                                          sizeof(struct StatsValue), TEST_MAP_SIZE, 0));
         ASSERT_LE(0, mFakeTagStatsMap.getMap());
 
-        mFakeDozableUidMap.reset(
-            createMap(BPF_MAP_TYPE_HASH, sizeof(uint32_t), sizeof(uint8_t), TEST_MAP_SIZE, 0));
-        ASSERT_LE(0, mFakeDozableUidMap.getMap());
+        mFakeConfigurationMap.reset(
+                createMap(BPF_MAP_TYPE_HASH, sizeof(uint32_t), sizeof(uint8_t), 1, 0));
+        ASSERT_LE(0, mFakeConfigurationMap.getMap());
 
-        mFakeStandbyUidMap.reset(
-            createMap(BPF_MAP_TYPE_HASH, sizeof(uint32_t), sizeof(uint8_t), TEST_MAP_SIZE, 0));
-        ASSERT_LE(0, mFakeStandbyUidMap.getMap());
-
-        mFakePowerSaveUidMap.reset(
-            createMap(BPF_MAP_TYPE_HASH, sizeof(uint32_t), sizeof(uint8_t), TEST_MAP_SIZE, 0));
-        ASSERT_LE(0, mFakePowerSaveUidMap.getMap());
-
-        mFakeBandwidthUidMap.reset(
-            createMap(BPF_MAP_TYPE_HASH, sizeof(uint32_t), sizeof(uint8_t), TEST_MAP_SIZE, 0));
-        ASSERT_LE(0, mFakeBandwidthUidMap.getMap());
+        mFakeUidOwnerMap.reset(
+                createMap(BPF_MAP_TYPE_HASH, sizeof(uint32_t), sizeof(uint8_t), TEST_MAP_SIZE, 0));
+        ASSERT_LE(0, mFakeUidOwnerMap.getMap());
         // Make sure trafficController use the eBPF code path.
         mTc.ebpfSupported = true;
 
@@ -127,10 +117,8 @@
         mTc.mAppUidStatsMap.reset(mFakeAppUidStatsMap.getMap());
         mTc.mUidStatsMap.reset(mFakeUidStatsMap.getMap());
         mTc.mTagStatsMap.reset(mFakeTagStatsMap.getMap());
-        mTc.mDozableUidMap.reset(mFakeDozableUidMap.getMap());
-        mTc.mStandbyUidMap.reset(mFakeStandbyUidMap.getMap());
-        mTc.mPowerSaveUidMap.reset(mFakePowerSaveUidMap.getMap());
-        mTc.mBandwidthUidMap.reset(mFakeBandwidthUidMap.getMap());
+        mTc.mConfigurationMap.reset(mFakeConfigurationMap.getMap());
+        mTc.mUidOwnerMap.reset(mFakeUidOwnerMap.getMap());
     }
 
     int setUpSocketAndTag(int protocol, uint64_t* cookie, uint32_t tag, uid_t uid) {
@@ -166,43 +154,42 @@
         key->tag = tag;
     }
 
-    void checkUidOwnerRuleForChain(ChildChain chain, BpfMap<uint32_t, uint8_t>& targetMap) {
+    void checkUidOwnerRuleForChain(ChildChain chain, UidOwnerMatchType match) {
         uint32_t uid = TEST_UID;
         EXPECT_EQ(0, mTc.changeUidOwnerRule(chain, uid, DENY, BLACKLIST));
-        StatusOr<uint8_t> value = targetMap.readValue(uid);
+        StatusOr<uint8_t> value = mFakeUidOwnerMap.readValue(uid);
         EXPECT_TRUE(isOk(value));
-        EXPECT_EQ(BPF_DROP, value.value());
+        EXPECT_TRUE(value.value() & match);
 
         uid = TEST_UID2;
         EXPECT_EQ(0, mTc.changeUidOwnerRule(chain, uid, ALLOW, WHITELIST));
-        value = targetMap.readValue(uid);
+        value = mFakeUidOwnerMap.readValue(uid);
         EXPECT_TRUE(isOk(value));
-        EXPECT_EQ(BPF_PASS, value.value());
+        EXPECT_TRUE(value.value() & match);
 
         EXPECT_EQ(0, mTc.changeUidOwnerRule(chain, uid, DENY, WHITELIST));
-        value = targetMap.readValue(uid);
+        value = mFakeUidOwnerMap.readValue(uid);
         EXPECT_FALSE(isOk(value));
         EXPECT_EQ(ENOENT, value.status().code());
 
         uid = TEST_UID;
         EXPECT_EQ(0, mTc.changeUidOwnerRule(chain, uid, ALLOW, BLACKLIST));
-        value = targetMap.readValue(uid);
+        value = mFakeUidOwnerMap.readValue(uid);
         EXPECT_FALSE(isOk(value));
         EXPECT_EQ(ENOENT, value.status().code());
 
         uid = TEST_UID3;
         EXPECT_EQ(-ENOENT, mTc.changeUidOwnerRule(chain, uid, ALLOW, BLACKLIST));
-        value = targetMap.readValue(uid);
+        value = mFakeUidOwnerMap.readValue(uid);
         EXPECT_FALSE(isOk(value));
         EXPECT_EQ(ENOENT, value.status().code());
     }
 
-    void checkEachUidValue(const std::vector<int32_t>& uids, const uint8_t expectValue,
-                           BpfMap<uint32_t, uint8_t>& targetMap) {
+    void checkEachUidValue(const std::vector<int32_t>& uids, UidOwnerMatchType match) {
         for (uint32_t uid : uids) {
-            StatusOr<uint8_t> value = targetMap.readValue(uid);
+            StatusOr<uint8_t> value = mFakeUidOwnerMap.readValue(uid);
             EXPECT_TRUE(isOk(value));
-            EXPECT_EQ(expectValue, value.value());
+            EXPECT_TRUE(value.value() & match);
         }
         std::set<uint32_t> uidSet(uids.begin(), uids.end());
         const auto checkNoOtherUid = [&uidSet](const int32_t& key,
@@ -210,25 +197,24 @@
             EXPECT_NE(uidSet.end(), uidSet.find(key));
             return netdutils::status::ok;
         };
-        EXPECT_TRUE(isOk(targetMap.iterate(checkNoOtherUid)));
+        EXPECT_TRUE(isOk(mFakeUidOwnerMap.iterate(checkNoOtherUid)));
     }
 
     void checkUidMapReplace(const std::string& name, const std::vector<int32_t>& uids,
-                            BpfMap<uint32_t, uint8_t>& targetMap) {
+                            UidOwnerMatchType match) {
         bool isWhitelist = true;
         EXPECT_EQ(0, mTc.replaceUidOwnerMap(name, isWhitelist, uids));
-        checkEachUidValue(uids, BPF_PASS, targetMap);
+        checkEachUidValue(uids, match);
 
         isWhitelist = false;
         EXPECT_EQ(0, mTc.replaceUidOwnerMap(name, isWhitelist, uids));
-        checkEachUidValue(uids, BPF_DROP, targetMap);
+        checkEachUidValue(uids, match);
     }
-
-    void expectBandwidthMapValues(const std::vector<std::string>& appStrUids,
-                                  uint8_t expectedValue) {
+    void expectUidOwnerMapValues(const std::vector<std::string>& appStrUids,
+                                 uint8_t expectedValue) {
         for (const std::string& strUid : appStrUids) {
             uint32_t uid = stoi(strUid);
-            StatusOr<uint8_t> value = mFakeBandwidthUidMap.readValue(uid);
+            StatusOr<uint8_t> value = mFakeUidOwnerMap.readValue(uid);
             EXPECT_TRUE(isOk(value));
             EXPECT_EQ(expectedValue, value.value()) <<
                 "Expected value for UID " << uid << " to be " << expectedValue <<
@@ -248,17 +234,6 @@
         ASSERT_TRUE(isEmpty.value());
     }
 
-    void TearDown() {
-        std::lock_guard<std::mutex> ownerGuard(mTc.mOwnerMatchMutex);
-        mFakeCookieTagMap.reset();
-        mFakeUidCounterSetMap.reset();
-        mFakeAppUidStatsMap.reset();
-        mFakeUidStatsMap.reset();
-        mFakeTagStatsMap.reset();
-        mTc.mDozableUidMap.reset();
-        mTc.mStandbyUidMap.reset();
-        mTc.mPowerSaveUidMap.reset();
-    }
 };
 
 TEST_F(TrafficControllerTest, TestTagSocketV4) {
@@ -463,35 +438,35 @@
     SKIP_IF_BPF_NOT_SUPPORTED;
 
     uint32_t uid = TEST_UID;
-    ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(mFakeDozableUidMap, uid, DENY, BLACKLIST)));
-    StatusOr<uint8_t> value = mFakeDozableUidMap.readValue(uid);
+    ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(STANDBY_MATCH, uid, DENY, BLACKLIST)));
+    StatusOr<uint8_t> value = mFakeUidOwnerMap.readValue(uid);
     ASSERT_TRUE(isOk(value));
-    ASSERT_EQ(BPF_DROP, value.value());
+    ASSERT_TRUE(value.value() & STANDBY_MATCH);
+
+    ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(DOZABLE_MATCH, uid, ALLOW, WHITELIST)));
+    value = mFakeUidOwnerMap.readValue(uid);
+    ASSERT_TRUE(isOk(value));
+    ASSERT_TRUE(value.value() & DOZABLE_MATCH);
+
+    ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(DOZABLE_MATCH, uid, DENY, WHITELIST)));
+    value = mFakeUidOwnerMap.readValue(uid);
+    ASSERT_TRUE(isOk(value));
+    ASSERT_FALSE(value.value() & DOZABLE_MATCH);
+
+    ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(STANDBY_MATCH, uid, ALLOW, BLACKLIST)));
+    ASSERT_FALSE(isOk(mFakeUidOwnerMap.readValue(uid)));
 
     uid = TEST_UID2;
-    ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(mFakeDozableUidMap, uid, ALLOW, WHITELIST)));
-    value = mFakeDozableUidMap.readValue(uid);
-    ASSERT_TRUE(isOk(value));
-    ASSERT_EQ(BPF_PASS, value.value());
-
-    ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(mFakeDozableUidMap, uid, DENY, WHITELIST)));
-    ASSERT_FALSE(isOk(mFakeDozableUidMap.readValue(uid)));
-
-    uid = TEST_UID;
-    ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(mFakeDozableUidMap, uid, ALLOW, BLACKLIST)));
-    ASSERT_FALSE(isOk(mFakeDozableUidMap.readValue(uid)));
-
-    uid = TEST_UID3;
-    ASSERT_FALSE(isOk(mTc.updateOwnerMapEntry(mFakeDozableUidMap, uid, ALLOW, BLACKLIST)));
-    ASSERT_FALSE(isOk(mFakeDozableUidMap.readValue(uid)));
+    ASSERT_FALSE(isOk(mTc.updateOwnerMapEntry(STANDBY_MATCH, uid, ALLOW, BLACKLIST)));
+    ASSERT_FALSE(isOk(mFakeUidOwnerMap.readValue(uid)));
 }
 
 TEST_F(TrafficControllerTest, TestChangeUidOwnerRule) {
     SKIP_IF_BPF_NOT_SUPPORTED;
 
-    checkUidOwnerRuleForChain(DOZABLE, mFakeDozableUidMap);
-    checkUidOwnerRuleForChain(STANDBY, mFakeStandbyUidMap);
-    checkUidOwnerRuleForChain(POWERSAVE, mFakePowerSaveUidMap);
+    checkUidOwnerRuleForChain(DOZABLE, DOZABLE_MATCH);
+    checkUidOwnerRuleForChain(STANDBY, STANDBY_MATCH);
+    checkUidOwnerRuleForChain(POWERSAVE, POWERSAVE_MATCH);
     ASSERT_EQ(-EINVAL, mTc.changeUidOwnerRule(NONE, TEST_UID, ALLOW, WHITELIST));
     ASSERT_EQ(-EINVAL, mTc.changeUidOwnerRule(INVALID_CHAIN, TEST_UID, ALLOW, WHITELIST));
 }
@@ -500,59 +475,69 @@
     SKIP_IF_BPF_NOT_SUPPORTED;
 
     std::vector<int32_t> uids = {TEST_UID, TEST_UID2, TEST_UID3};
-    checkUidMapReplace("fw_dozable", uids, mFakeDozableUidMap);
-    checkUidMapReplace("fw_standby", uids, mFakeStandbyUidMap);
-    checkUidMapReplace("fw_powersave", uids, mFakePowerSaveUidMap);
+    checkUidMapReplace("fw_dozable", uids, DOZABLE_MATCH);
+    checkUidMapReplace("fw_standby", uids, STANDBY_MATCH);
+    checkUidMapReplace("fw_powersave", uids, POWERSAVE_MATCH);
     ASSERT_EQ(-EINVAL, mTc.replaceUidOwnerMap("unknow", true, uids));
 }
 
+TEST_F(TrafficControllerTest, TestReplaceSameChain) {
+    SKIP_IF_BPF_NOT_SUPPORTED;
+
+    std::vector<int32_t> uids = {TEST_UID, TEST_UID2, TEST_UID3};
+    checkUidMapReplace("fw_dozable", uids, DOZABLE_MATCH);
+    std::vector<int32_t> newUids = {TEST_UID2, TEST_UID3};
+    checkUidMapReplace("fw_dozable", newUids, DOZABLE_MATCH);
+}
+
 TEST_F(TrafficControllerTest, TestBlacklistUidMatch) {
     SKIP_IF_BPF_NOT_SUPPORTED;
 
     std::vector<std::string> appStrUids = {"1000", "1001", "10012"};
-    ASSERT_TRUE(isOk(mTc.updateBandwidthUidMap(appStrUids, BandwidthController::IptJumpReject,
-                                               BandwidthController::IptOpInsert)));
-    expectBandwidthMapValues(appStrUids, BLACKLISTMATCH);
-    ASSERT_TRUE(isOk(mTc.updateBandwidthUidMap(appStrUids, BandwidthController::IptJumpReject,
-                                               BandwidthController::IptOpDelete)));
-    expectMapEmpty(mFakeBandwidthUidMap);
+    ASSERT_TRUE(isOk(mTc.updateUidOwnerMap(appStrUids, BandwidthController::IptJumpReject,
+                                           BandwidthController::IptOpInsert)));
+    expectUidOwnerMapValues(appStrUids, PENALTY_BOX_MATCH);
+    ASSERT_TRUE(isOk(mTc.updateUidOwnerMap(appStrUids, BandwidthController::IptJumpReject,
+                                           BandwidthController::IptOpDelete)));
+    expectMapEmpty(mFakeUidOwnerMap);
 }
 
 TEST_F(TrafficControllerTest, TestWhitelistUidMatch) {
     SKIP_IF_BPF_NOT_SUPPORTED;
 
     std::vector<std::string> appStrUids = {"1000", "1001", "10012"};
-    ASSERT_TRUE(isOk(mTc.updateBandwidthUidMap(appStrUids, BandwidthController::IptJumpReturn,
-                                               BandwidthController::IptOpInsert)));
-    expectBandwidthMapValues(appStrUids, WHITELISTMATCH);
-    ASSERT_TRUE(isOk(mTc.updateBandwidthUidMap(appStrUids, BandwidthController::IptJumpReturn,
-                                               BandwidthController::IptOpDelete)));
-    expectMapEmpty(mFakeBandwidthUidMap);
+    ASSERT_TRUE(isOk(mTc.updateUidOwnerMap(appStrUids, BandwidthController::IptJumpReturn,
+                                           BandwidthController::IptOpInsert)));
+    expectUidOwnerMapValues(appStrUids, HAPPY_BOX_MATCH);
+    ASSERT_TRUE(isOk(mTc.updateUidOwnerMap(appStrUids, BandwidthController::IptJumpReturn,
+                                           BandwidthController::IptOpDelete)));
+    expectMapEmpty(mFakeUidOwnerMap);
 }
 
 TEST_F(TrafficControllerTest, TestReplaceMatchUid) {
     SKIP_IF_BPF_NOT_SUPPORTED;
 
     std::vector<std::string> appStrUids = {"1000", "1001", "10012"};
-    // Add appStrUids to the blacklist and expect that their values are all BLACKLISTMATCH.
-    ASSERT_TRUE(isOk(mTc.updateBandwidthUidMap(appStrUids, BandwidthController::IptJumpReject,
-                                               BandwidthController::IptOpInsert)));
-    expectBandwidthMapValues(appStrUids, BLACKLISTMATCH);
+    // Add appStrUids to the blacklist and expect that their values are all PENALTY_BOX_MATCH.
+    ASSERT_TRUE(isOk(mTc.updateUidOwnerMap(appStrUids, BandwidthController::IptJumpReject,
+                                           BandwidthController::IptOpInsert)));
+    expectUidOwnerMapValues(appStrUids, PENALTY_BOX_MATCH);
 
-    // Add the same UIDs to the whitelist and expect that we get BLACKLISTMATCH | WHITELISTMATCH.
-    ASSERT_TRUE(isOk(mTc.updateBandwidthUidMap(appStrUids, BandwidthController::IptJumpReturn,
-                                               BandwidthController::IptOpInsert)));
-    expectBandwidthMapValues(appStrUids, WHITELISTMATCH | BLACKLISTMATCH);
+    // Add the same UIDs to the whitelist and expect that we get PENALTY_BOX_MATCH |
+    // HAPPY_BOX_MATCH.
+    ASSERT_TRUE(isOk(mTc.updateUidOwnerMap(appStrUids, BandwidthController::IptJumpReturn,
+                                           BandwidthController::IptOpInsert)));
+    expectUidOwnerMapValues(appStrUids, HAPPY_BOX_MATCH | PENALTY_BOX_MATCH);
 
-    // Remove the same UIDs from the whitelist and check the BLACKLISTMATCH is still there.
-    ASSERT_TRUE(isOk(mTc.updateBandwidthUidMap(appStrUids, BandwidthController::IptJumpReturn,
-                                               BandwidthController::IptOpDelete)));
-    expectBandwidthMapValues(appStrUids, BLACKLISTMATCH);
+    // Remove the same UIDs from the whitelist and check the PENALTY_BOX_MATCH is still there.
+    ASSERT_TRUE(isOk(mTc.updateUidOwnerMap(appStrUids, BandwidthController::IptJumpReturn,
+                                           BandwidthController::IptOpDelete)));
+    expectUidOwnerMapValues(appStrUids, PENALTY_BOX_MATCH);
 
     // Remove the same UIDs from the blacklist and check the map is empty.
-    ASSERT_TRUE(isOk(mTc.updateBandwidthUidMap(appStrUids, BandwidthController::IptJumpReject,
-                                               BandwidthController::IptOpDelete)));
-    ASSERT_FALSE(isOk(mFakeBandwidthUidMap.getFirstKey()));
+    ASSERT_TRUE(isOk(mTc.updateUidOwnerMap(appStrUids, BandwidthController::IptJumpReject,
+                                           BandwidthController::IptOpDelete)));
+    ASSERT_FALSE(isOk(mFakeUidOwnerMap.getFirstKey()));
 }
 
 TEST_F(TrafficControllerTest, TestDeleteWrongMatchSilentlyFails) {
@@ -560,22 +545,22 @@
 
     std::vector<std::string> appStrUids = {"1000", "1001", "10012"};
     // If the uid does not exist in the map, trying to delete a rule about it will fail.
-    ASSERT_FALSE(isOk(mTc.updateBandwidthUidMap(appStrUids, BandwidthController::IptJumpReject,
-                                                BandwidthController::IptOpDelete)));
-    expectMapEmpty(mFakeBandwidthUidMap);
+    ASSERT_FALSE(isOk(mTc.updateUidOwnerMap(appStrUids, BandwidthController::IptJumpReturn,
+                                            BandwidthController::IptOpDelete)));
+    expectMapEmpty(mFakeUidOwnerMap);
 
     // Add blacklist rules for appStrUids.
-    ASSERT_TRUE(isOk(mTc.updateBandwidthUidMap(appStrUids, BandwidthController::IptJumpReturn,
-                                               BandwidthController::IptOpInsert)));
-    expectBandwidthMapValues(appStrUids, WHITELISTMATCH);
+    ASSERT_TRUE(isOk(mTc.updateUidOwnerMap(appStrUids, BandwidthController::IptJumpReturn,
+                                           BandwidthController::IptOpInsert)));
+    expectUidOwnerMapValues(appStrUids, HAPPY_BOX_MATCH);
 
     // Delete (non-existent) blacklist rules for appStrUids, and check that this silently does
     // nothing if the uid is in the map but does not have blacklist match. This is required because
     // NetworkManagementService will try to remove a uid from blacklist after adding it to the
     // whitelist and if the remove fails it will not update the uid status.
-    ASSERT_TRUE(isOk(mTc.updateBandwidthUidMap(appStrUids, BandwidthController::IptJumpReject,
-                                                BandwidthController::IptOpDelete)));
-    expectBandwidthMapValues(appStrUids, WHITELISTMATCH);
+    ASSERT_TRUE(isOk(mTc.updateUidOwnerMap(appStrUids, BandwidthController::IptJumpReject,
+                                           BandwidthController::IptOpDelete)));
+    expectUidOwnerMapValues(appStrUids, HAPPY_BOX_MATCH);
 }
 }  // namespace net
 }  // namespace android
diff --git a/tests/bpf_base_test.cpp b/tests/bpf_base_test.cpp
index 76c5bd8..ead06bd 100644
--- a/tests/bpf_base_test.cpp
+++ b/tests/bpf_base_test.cpp
@@ -77,9 +77,8 @@
     ASSERT_EQ(0, access(TAG_STATS_MAP_PATH, R_OK));
     ASSERT_EQ(0, access(IFACE_INDEX_NAME_MAP_PATH, R_OK));
     ASSERT_EQ(0, access(IFACE_STATS_MAP_PATH, R_OK));
-    ASSERT_EQ(0, access(DOZABLE_UID_MAP_PATH, R_OK));
-    ASSERT_EQ(0, access(STANDBY_UID_MAP_PATH, R_OK));
-    ASSERT_EQ(0, access(POWERSAVE_UID_MAP_PATH, R_OK));
+    ASSERT_EQ(0, access(CONFIGURATION_MAP_PATH, R_OK));
+    ASSERT_EQ(0, access(UID_OWNER_MAP_PATH, R_OK));
 }
 
 TEST_F(BpfBasicTest, TestTagSocket) {