Use a separate map to store per app stats
To avoid iterating through the eBPF map to get the total stats of a
specific uid. A new bpf map called appUidStatsMap is added to the
trafficController so that TrafficStats API can directly read that map
for per uid total stats regardless of tag, counterSet and iface
information. This could make this call more efficient and solve the
possible racing problem.
Bug: 79171384
Test: netd_unit_test, libbpf_test, netd_integration_test
Change-Id: I47a4ac3466caa729c5730a498a2de226303d6b77
diff --git a/server/TrafficController.cpp b/server/TrafficController.cpp
index d8eb6b6..d6a6480 100644
--- a/server/TrafficController.cpp
+++ b/server/TrafficController.cpp
@@ -149,6 +149,11 @@
"UidCounterSetMap", false));
RETURN_IF_NOT_OK(
+ mAppUidStatsMap.getOrCreate(UID_STATS_MAP_SIZE, APP_UID_STATS_MAP_PATH, BPF_MAP_TYPE_HASH));
+ RETURN_IF_NOT_OK(
+ changeOwnerAndMode(APP_UID_STATS_MAP_PATH, AID_NET_BW_STATS, "AppUidStatsMap", false));
+
+ RETURN_IF_NOT_OK(
mUidStatsMap.getOrCreate(UID_STATS_MAP_SIZE, UID_STATS_MAP_PATH, BPF_MAP_TYPE_HASH));
RETURN_IF_NOT_OK(changeOwnerAndMode(UID_STATS_MAP_PATH, AID_NET_BW_STATS, "UidStatsMap",
false));
@@ -391,6 +396,18 @@
strerror(res.code()));
}
mUidStatsMap.iterate(deleteMatchedUidTagEntries);
+
+ auto deleteAppUidStatsEntry = [uid](const uint32_t& key, BpfMap<uint32_t, StatsValue>& map) {
+ if (key == uid) {
+ Status res = map.deleteValue(key);
+ if (isOk(res) || (res.code() == ENOENT)) {
+ return netdutils::status::ok;
+ }
+ ALOGE("Failed to delete data(uid=%u): %s", key, strerror(res.code()));
+ }
+ return netdutils::status::ok;
+ };
+ mAppUidStatsMap.iterate(deleteAppUidStatsEntry);
return 0;
}
@@ -589,6 +606,8 @@
getMapStatus(mCookieTagMap.getMap(), COOKIE_TAG_MAP_PATH).c_str());
dw.println("mUidCounterSetMap status: %s",
getMapStatus(mUidCounterSetMap.getMap(), UID_COUNTERSET_MAP_PATH).c_str());
+ dw.println("mAppUidStatsMap status: %s",
+ getMapStatus(mAppUidStatsMap.getMap(), APP_UID_STATS_MAP_PATH).c_str());
dw.println("mUidStatsMap status: %s",
getMapStatus(mUidStatsMap.getMap(), UID_STATS_MAP_PATH).c_str());
dw.println("mTagStatsMap status: %s",
@@ -644,6 +663,20 @@
dw.println("mUidCounterSetMap print end with error: %s", res.msg().c_str());
}
+ // Print AppUidStatsMap content
+ std::string appUidStatsHeader = StringPrintf("uid rxBytes rxPackets txBytes txPackets");
+ dumpBpfMap("mAppUidStatsMap:", dw, appUidStatsHeader);
+ auto printAppUidStatsInfo = [&dw](const uint32_t& key, const StatsValue& value,
+ const BpfMap<uint32_t, StatsValue>&) {
+ dw.println("%u %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, key, value.rxBytes,
+ value.rxPackets, value.txBytes, value.txPackets);
+ return netdutils::status::ok;
+ };
+ res = mAppUidStatsMap.iterateWithValue(printAppUidStatsInfo);
+ if (!res.ok()) {
+ dw.println("mAppUidStatsMap print end with error: %s", res.msg().c_str());
+ }
+
// Print uidStatsMap content
std::string statsHeader = StringPrintf("ifaceIndex ifaceName tag_hex uid_int cnt_set rxBytes"
" rxPackets txBytes txPackets");