Merge "Merge all uid owner match map into one"
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) {