Refactor tetherGetStats by using stable aidl structure

Use stable aidl structure instead of persistbundle

Test: built, flashed, booted
      system/netd/tests/runtests.sh passes

Change-Id: Id48cea4da4f9f4406ceb3d2281a5cfaaea8ce24f
diff --git a/server/Android.bp b/server/Android.bp
index 75e7d20..75667e9 100644
--- a/server/Android.bp
+++ b/server/Android.bp
@@ -24,12 +24,22 @@
     ],
 }
 
+aidl_interface {
+    name: "netd_aidl_interface",
+    local_include_dir: "binder",
+    srcs: [
+        "binder/android/net/TetherStatsParcel.aidl",
+    ],
+    api_dir: "binder/api",
+}
+
 cc_library {
     name: "libnetdaidl",
     defaults: ["netd_defaults"],
     shared_libs: [
         "libbinder",
         "libutils",
+        "netd_aidl_interface-cpp",
     ],
     aidl: {
         export_aidl_headers: true,
@@ -86,6 +96,7 @@
         "libpcap",
         "libqtaguid",
         "libssl",
+        "netd_aidl_interface-cpp",
     ],
     aidl: {
         export_aidl_headers: true,
@@ -125,6 +136,7 @@
         "libssl",
         "libsysutils",
         "libutils",
+        "netd_aidl_interface-cpp",
     ],
     static_libs: [
         "libnetd_server",
@@ -209,5 +221,6 @@
         "libqtaguid",
         "libsysutils",
         "libutils",
+        "netd_aidl_interface-cpp",
     ],
 }
diff --git a/server/NetdNativeService.cpp b/server/NetdNativeService.cpp
index f2441f7..ff24ccd 100644
--- a/server/NetdNativeService.cpp
+++ b/server/NetdNativeService.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "Netd"
 
+#include <cinttypes>
 #include <set>
 #include <tuple>
 #include <vector>
@@ -45,7 +46,7 @@
 #include "UidRanges.h"
 
 using android::base::StringPrintf;
-using android::os::PersistableBundle;
+using android::net::TetherStatsParcel;
 
 namespace android {
 namespace net {
@@ -489,37 +490,68 @@
 
 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);
+void tetherAddStatsByInterface(TetherController::TetherStats* tetherStatsParcel,
+                               const TetherController::TetherStats& tetherStats) {
+    if (tetherStatsParcel->extIface == tetherStats.extIface) {
+        tetherStatsParcel->rxBytes += tetherStats.rxBytes;
+        tetherStatsParcel->rxPackets += tetherStats.rxPackets;
+        tetherStatsParcel->txBytes += tetherStats.txBytes;
+        tetherStatsParcel->txPackets += tetherStats.txPackets;
     }
+}
 
-    statsVector[INetd::TETHER_STATS_RX_BYTES]   += stats.rxBytes;
-    statsVector[INetd::TETHER_STATS_RX_PACKETS] += stats.rxPackets;
-    statsVector[INetd::TETHER_STATS_TX_BYTES]   += stats.txBytes;
-    statsVector[INetd::TETHER_STATS_TX_PACKETS] += stats.txPackets;
+TetherStatsParcel toTetherStatsParcel(const TetherController::TetherStats& stats) {
+    TetherStatsParcel result;
+    result.iface = stats.extIface;
+    result.rxBytes = stats.rxBytes;
+    result.rxPackets = stats.rxPackets;
+    result.txBytes = stats.txBytes;
+    result.txPackets = stats.txPackets;
+    return result;
+}
 
-    bundle->putLongVector(iface, statsVector);
+void setTetherStatsParcelVecByInterface(std::vector<TetherStatsParcel>* tetherStatsVec,
+                                        const TetherController::TetherStatsList& statsList) {
+    std::map<std::string, TetherController::TetherStats> statsMap;
+    for (const auto& stats : statsList) {
+        auto iter = statsMap.find(stats.extIface);
+        if (iter != statsMap.end()) {
+            tetherAddStatsByInterface(&(iter->second), stats);
+        } else {
+            statsMap.insert(
+                    std::pair<std::string, TetherController::TetherStats>(stats.extIface, stats));
+        }
+    }
+    for (auto iter = statsMap.begin(); iter != statsMap.end(); iter++) {
+        tetherStatsVec->push_back(toTetherStatsParcel(iter->second));
+    }
+}
+
+std::vector<std::string> tetherStatsParcelVecToStringVec(std::vector<TetherStatsParcel>* tVec) {
+    std::vector<std::string> result;
+    for (const auto& t : *tVec) {
+        result.push_back(StringPrintf("%s:%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64,
+                                      t.iface.c_str(), t.rxBytes, t.rxPackets, t.txBytes,
+                                      t.txPackets));
+    }
+    return result;
 }
 
 }  // namespace
 
-binder::Status NetdNativeService::tetherGetStats(PersistableBundle *bundle) {
+binder::Status NetdNativeService::tetherGetStats(
+        std::vector<TetherStatsParcel>* tetherStatsParcelVec) {
     NETD_LOCKING_RPC(NETWORK_STACK, gCtls->tetherCtrl.lock);
 
+    auto entry = gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__);
+
     const auto& statsList = gCtls->tetherCtrl.getTetherStats();
     if (!isOk(statsList)) {
         return asBinderStatus(statsList);
     }
-
-    for (const auto& stats : statsList.value()) {
-        tetherAddStats(bundle, stats);
-    }
-
+    setTetherStatsParcelVecByInterface(tetherStatsParcelVec, statsList.value());
+    auto statsResults = tetherStatsParcelVecToStringVec(tetherStatsParcelVec);
+    gLog.log(entry.returns(base::Join(statsResults, ";")).withAutomaticDuration());
     return binder::Status::ok();
 }
 
diff --git a/server/NetdNativeService.h b/server/NetdNativeService.h
index 89c04f7..4da1335 100644
--- a/server/NetdNativeService.h
+++ b/server/NetdNativeService.h
@@ -94,7 +94,8 @@
 
     // Tethering-related commands.
     binder::Status tetherApplyDnsInterfaces(bool *ret) override;
-    binder::Status tetherGetStats(android::os::PersistableBundle *ret) override;
+    binder::Status tetherGetStats(
+            std::vector<android::net::TetherStatsParcel>* tetherStatsVec) override;
     binder::Status tetherStart(const std::vector<std::string>& dhcpRanges) override;
     binder::Status tetherStop() override;
     binder::Status tetherIsEnabled(bool* enabled) override;
diff --git a/server/binder/android/net/INetd.aidl b/server/binder/android/net/INetd.aidl
index 5f429c6..8147afa 100644
--- a/server/binder/android/net/INetd.aidl
+++ b/server/binder/android/net/INetd.aidl
@@ -17,7 +17,7 @@
 package android.net;
 
 import android.net.UidRange;
-import android.os.PersistableBundle;
+import android.net.TetherStatsParcel;
 
 /** {@hide} */
 interface INetd {
@@ -254,24 +254,16 @@
      */
     boolean tetherApplyDnsInterfaces();
 
-    // Ordering of the elements in the arrays returned by tetherGetStats.
-    const int TETHER_STATS_RX_BYTES   = 0;
-    const int TETHER_STATS_RX_PACKETS = 1;
-    const int TETHER_STATS_TX_BYTES   = 2;
-    const int TETHER_STATS_TX_PACKETS = 3;
-    const int TETHER_STATS_ARRAY_SIZE = 4;
-
     /**
      * Return tethering statistics.
      *
-     * @return a PersistableBundle, where each entry maps the upstream interface name to an array
-     *         of longs representing stats. The array is TETHER_STATS_ARRAY_SIZE elements long and
-     *         the order of the elements is specified by the TETHER_STATS_{RX,TX}_{PACKETS,BYTES}
-     *         constants.
+     * @return an array of TetherStatsParcel, where each entry contains the upstream interface
+     *         name and its tethering statistics.
+     *         There will only ever be one entry for a given interface.
      * @throws ServiceSpecificException in case of failure, with an error code indicating the
      *         cause of the the failure.
      */
-    PersistableBundle tetherGetStats();
+    TetherStatsParcel[] tetherGetStats();
 
     /**
      * Add/Remove and IP address from an interface.
diff --git a/server/binder/android/net/TetherStatsParcel.aidl b/server/binder/android/net/TetherStatsParcel.aidl
new file mode 100644
index 0000000..25e200c
--- /dev/null
+++ b/server/binder/android/net/TetherStatsParcel.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+/**
+ * The statistics of tethering interface
+ *
+ * {@hide}
+ */
+parcelable TetherStatsParcel {
+    @utf8InCpp String iface;
+    long rxBytes;
+    long rxPackets;
+    long txBytes;
+    long txPackets;
+}