Add a binder RPC for tethering stats.

Bug: 32163131
Bug: 64995262
Test: netd_{unit,integration}_test pass
Change-Id: I9c7dfdaf6b823840b1691761930b53c30a4dcbc3
diff --git a/server/NetdNativeService.cpp b/server/NetdNativeService.cpp
index 771ebda..3f10d7c 100644
--- a/server/NetdNativeService.cpp
+++ b/server/NetdNativeService.cpp
@@ -41,6 +41,7 @@
 #include "UidRanges.h"
 
 using android::base::StringPrintf;
+using android::os::PersistableBundle;
 
 namespace android {
 namespace net {
@@ -278,12 +279,63 @@
 }
 
 binder::Status NetdNativeService::tetherApplyDnsInterfaces(bool *ret) {
-    NETD_BIG_LOCK_RPC(CONNECTIVITY_INTERNAL);
+    NETD_LOCKING_RPC(NETWORK_STACK, gCtls->tetherCtrl.lock)
 
     *ret = gCtls->tetherCtrl.applyDnsInterfaces();
     return binder::Status::ok();
 }
 
+namespace {
+
+void tetherAddStats(PersistableBundle *bundle, const TetherController::TetherStats& stats) {
+    String16 iface = String16(stats.extIface.c_str());
+    std::vector<int64_t> statsVector(INetd::TETHER_STATS_ARRAY_SIZE);
+
+    bundle->getLongVector(iface, &statsVector);
+    if (statsVector.size() == 0) {
+        for (int i = 0; i < INetd::TETHER_STATS_ARRAY_SIZE; i++) statsVector.push_back(0);
+    }
+
+    // Note: currently, TetherController::addForwardChainStats swaps TX and RX counters.
+    // Specifically, when parsing iptables counters like this:
+    //
+    // Chain tetherctrl_counters (0 references)
+    //     pkts      bytes target     prot opt in     out     source               destination
+    //     4107   214602 RETURN     all  --  rndis0 rmnet_data0  0.0.0.0/0            0.0.0.0/0
+    //     6937 10361624 RETURN     all  --  rmnet_data0 rndis0  0.0.0.0/0            0.0.0.0/0
+    //
+    // it will return a TetherStatsList with one element that has intIface rndis0 and extIface
+    // rmnet_data0 (correct) but with rxBytes=214602 and txBytes=10361624 (swapped). Because the
+    // code in getTetherStats and the corresponding code in NetworkManagementService swaps the
+    // counters again, this all works.
+    //
+    // TODO: once "bandwidth gettetherstats" is gone, swap the counters in addForwardChainStats.
+    statsVector[INetd::TETHER_STATS_RX_BYTES]   += stats.txBytes;
+    statsVector[INetd::TETHER_STATS_RX_PACKETS] += stats.txPackets;
+    statsVector[INetd::TETHER_STATS_TX_BYTES]   += stats.rxBytes;
+    statsVector[INetd::TETHER_STATS_TX_PACKETS] += stats.rxPackets;
+
+    bundle->putLongVector(iface, statsVector);
+}
+
+}  // namespace
+
+binder::Status NetdNativeService::tetherGetStats(PersistableBundle *bundle) {
+    NETD_LOCKING_RPC(NETWORK_STACK, gCtls->tetherCtrl.lock)
+
+    std::string extraProcessingInfo;
+    const auto& statsList = gCtls->tetherCtrl.getTetherStats(extraProcessingInfo);
+    if (!isOk(statsList)) {
+        return toBinderStatus(statsList);
+    }
+
+    for (const auto& stats : statsList.value()) {
+        tetherAddStats(bundle, stats);
+    }
+
+    return binder::Status::ok();
+}
+
 binder::Status NetdNativeService::interfaceAddAddress(const std::string &ifName,
         const std::string &addrString, int prefixLength) {
     ENFORCE_PERMISSION(CONNECTIVITY_INTERNAL);