Add binder call tetherOffloadGetAndClearStats
Provide binder calls for getting tethering statistics and clear the
stats for the given upstream.
Bug: 150736748
Test: None
Change-Id: I7bb635ee39d658961cd9515cc37e23bc3f0cd38f
Merged-In: I7bb635ee39d658961cd9515cc37e23bc3f0cd38f
diff --git a/server/TetherController.cpp b/server/TetherController.cpp
index 06740ab..6b5b060 100644
--- a/server/TetherController.cpp
+++ b/server/TetherController.cpp
@@ -1162,6 +1162,46 @@
return 0;
}
+Result<TetherController::TetherOffloadStats> TetherController::getAndClearTetherOffloadStats(
+ int ifIndex) {
+ if (!mBpfStatsMap.isValid() || !mBpfLimitMap.isValid()) return Error(ENOTSUP);
+
+ if (ifIndex <= 0) {
+ return Error(ENODEV) << "Invalid interface " << ifIndex;
+ }
+
+ // getAndClearTetherOffloadStats is called after all offload rules have already been deleted
+ // for the given upstream interface. Before starting to do cleanup stuff in this function, use
+ // synchronizeKernelRCU to make sure that all the current running eBPF programs are finished
+ // on all CPUs, especially the unfinished packet processing. After synchronizeKernelRCU
+ // returned, we can safely read or delete on the stats map or the limit map.
+ if (int res = bpf::synchronizeKernelRCU()) {
+ // Error log but don't return error. Do as much cleanup as possible.
+ ALOGE("synchronize_rcu() failed: %s", strerror(-res));
+ }
+
+ const auto stats = mBpfStatsMap.readValue(ifIndex);
+ if (!stats.ok()) {
+ return Error(stats.error().code()) << "Fail to get stats for interface index " << ifIndex;
+ }
+
+ auto res = mBpfStatsMap.deleteValue(ifIndex);
+ if (!res.ok()) {
+ return Error(res.error().code()) << "Fail to delete stats for interface index " << ifIndex;
+ }
+
+ res = mBpfLimitMap.deleteValue(ifIndex);
+ if (!res.ok()) {
+ return Error(res.error().code()) << "Fail to delete limit for interface index " << ifIndex;
+ }
+
+ return TetherOffloadStats{.ifIndex = static_cast<int>(ifIndex),
+ .rxBytes = static_cast<int64_t>(stats.value().rxBytes),
+ .rxPackets = static_cast<int64_t>(stats.value().rxPackets),
+ .txBytes = static_cast<int64_t>(stats.value().txBytes),
+ .txPackets = static_cast<int64_t>(stats.value().txPackets)};
+}
+
void TetherController::dumpIfaces(DumpWriter& dw) {
dw.println("Interface pairs:");