Merge changes I15a26ba7,Ia3223ba8

* changes:
  Add test for the NetworkTraceHandler
  Parse new config options and to batch in callback
diff --git a/service-t/native/libs/libnetworkstats/Android.bp b/service-t/native/libs/libnetworkstats/Android.bp
index f2c569f..f40d388 100644
--- a/service-t/native/libs/libnetworkstats/Android.bp
+++ b/service-t/native/libs/libnetworkstats/Android.bp
@@ -62,6 +62,7 @@
     header_libs: ["bpf_connectivity_headers"],
     srcs: [
         "BpfNetworkStatsTest.cpp",
+        "NetworkTraceHandlerTest.cpp",
         "NetworkTracePollerTest.cpp",
     ],
     cflags: [
@@ -74,6 +75,8 @@
         "libgmock",
         "libnetworkstats",
         "libperfetto_client_experimental",
+        "libprotobuf-cpp-lite",
+        "perfetto_trace_protos",
     ],
     shared_libs: [
         "libbase",
diff --git a/service-t/native/libs/libnetworkstats/NetworkTraceHandler.cpp b/service-t/native/libs/libnetworkstats/NetworkTraceHandler.cpp
index 8e70950..cd62bc5 100644
--- a/service-t/native/libs/libnetworkstats/NetworkTraceHandler.cpp
+++ b/service-t/native/libs/libnetworkstats/NetworkTraceHandler.cpp
@@ -57,11 +57,16 @@
 }
 
 // static
-NetworkTracePoller NetworkTraceHandler::sPoller([](const PacketTrace& pkt) {
-  NetworkTraceHandler::Trace([pkt](NetworkTraceHandler::TraceContext ctx) {
-    NetworkTraceHandler::Fill(pkt, *ctx.NewTracePacket());
-  });
-});
+NetworkTracePoller NetworkTraceHandler::sPoller(
+    [](const std::vector<PacketTrace>& packets) {
+      // Trace calls the provided callback for each active session. The context
+      // gets a reference to the NetworkTraceHandler instance associated with
+      // the session and delegates writing. The corresponding handler will write
+      // with the setting specified in the trace config.
+      NetworkTraceHandler::Trace([&](NetworkTraceHandler::TraceContext ctx) {
+        ctx.GetDataSourceLocked()->Write(packets, ctx);
+      });
+    });
 
 void NetworkTraceHandler::OnSetup(const SetupArgs& args) {
   const std::string& raw = args.config->network_packet_trace_config_raw();
@@ -72,6 +77,12 @@
     ALOGI("poll_ms is missing or below the 100ms minimum. Increasing to 100ms");
     mPollMs = 100;
   }
+
+  mInternLimit = config.intern_limit();
+  mAggregationThreshold = config.aggregation_threshold();
+  mDropLocalPort = config.drop_local_port();
+  mDropRemotePort = config.drop_remote_port();
+  mDropTcpFlags = config.drop_tcp_flags();
 }
 
 void NetworkTraceHandler::OnStart(const StartArgs&) {
@@ -83,6 +94,13 @@
   mStarted = false;
 }
 
+void NetworkTraceHandler::Write(const std::vector<PacketTrace>& packets,
+                                NetworkTraceHandler::TraceContext& ctx) {
+  for (const PacketTrace& pkt : packets) {
+    Fill(pkt, *ctx.NewTracePacket());
+  }
+}
+
 // static class method
 void NetworkTraceHandler::Fill(const PacketTrace& src, TracePacket& dst) {
   dst.set_timestamp(src.timestampNs);
diff --git a/service-t/native/libs/libnetworkstats/NetworkTraceHandlerTest.cpp b/service-t/native/libs/libnetworkstats/NetworkTraceHandlerTest.cpp
new file mode 100644
index 0000000..2318da5
--- /dev/null
+++ b/service-t/native/libs/libnetworkstats/NetworkTraceHandlerTest.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <vector>
+
+#include "netdbpf/NetworkTraceHandler.h"
+#include "protos/perfetto/trace/android/network_trace.pb.h"
+#include "protos/perfetto/trace/trace.pb.h"
+#include "protos/perfetto/trace/trace_packet.pb.h"
+
+namespace android {
+namespace bpf {
+using ::perfetto::protos::NetworkPacketEvent;
+using ::perfetto::protos::Trace;
+using ::perfetto::protos::TracePacket;
+using ::perfetto::protos::TrafficDirection;
+
+// This handler makes OnStart and OnStop a no-op so that tracing is not really
+// started on the device.
+class HandlerForTest : public NetworkTraceHandler {
+ public:
+  void OnStart(const StartArgs&) override {}
+  void OnStop(const StopArgs&) override {}
+};
+
+class NetworkTraceHandlerTest : public testing::Test {
+ protected:
+  // Starts a tracing session with the handler under test.
+  std::unique_ptr<perfetto::TracingSession> StartTracing() {
+    perfetto::TracingInitArgs args;
+    args.backends = perfetto::kInProcessBackend;
+    perfetto::Tracing::Initialize(args);
+
+    perfetto::DataSourceDescriptor dsd;
+    dsd.set_name("test.network_packets");
+    HandlerForTest::Register(dsd);
+
+    perfetto::TraceConfig cfg;
+    cfg.add_buffers()->set_size_kb(1024);
+    cfg.add_data_sources()->mutable_config()->set_name("test.network_packets");
+
+    auto session = perfetto::Tracing::NewTrace(perfetto::kInProcessBackend);
+    session->Setup(cfg);
+    session->StartBlocking();
+    return session;
+  }
+
+  // Stops the trace session and reports all relevant trace packets.
+  bool StopTracing(perfetto::TracingSession* session,
+                   std::vector<TracePacket>* output) {
+    session->StopBlocking();
+
+    Trace trace;
+    std::vector<char> raw_trace = session->ReadTraceBlocking();
+    if (!trace.ParseFromArray(raw_trace.data(), raw_trace.size())) {
+      ADD_FAILURE() << "trace.ParseFromArray failed";
+      return false;
+    }
+
+    // This is a real trace and includes irrelevant trace packets such as trace
+    // metadata. The following strips the results to just the packets we want.
+    for (const auto& pkt : trace.packet()) {
+      if (pkt.has_network_packet()) {
+        output->emplace_back(pkt);
+      }
+    }
+
+    return true;
+  }
+
+  // This runs a trace with a single call to Write.
+  bool TraceAndSortPackets(const std::vector<PacketTrace>& input,
+                           std::vector<TracePacket>* output) {
+    auto session = StartTracing();
+    HandlerForTest::Trace([&](HandlerForTest::TraceContext ctx) {
+      ctx.GetDataSourceLocked()->Write(input, ctx);
+      ctx.Flush();
+    });
+
+    if (!StopTracing(session.get(), output)) {
+      return false;
+    }
+
+    // Sort to provide deterministic ordering regardless of Perfetto internals
+    // or implementation-defined (e.g. hash map) reshuffling.
+    std::sort(output->begin(), output->end(),
+              [](const TracePacket& a, const TracePacket& b) {
+                return a.timestamp() < b.timestamp();
+              });
+
+    return true;
+  }
+};
+
+TEST_F(NetworkTraceHandlerTest, WriteBasicFields) {
+  std::vector<PacketTrace> input = {
+      PacketTrace{
+          .timestampNs = 1000,
+          .length = 100,
+          .uid = 10,
+          .tag = 123,
+          .ipProto = 6,
+          .tcpFlags = 1,
+      },
+  };
+
+  std::vector<TracePacket> events;
+  ASSERT_TRUE(TraceAndSortPackets(input, &events));
+
+  ASSERT_EQ(events.size(), 1);
+  EXPECT_THAT(events[0].timestamp(), 1000);
+  EXPECT_THAT(events[0].network_packet().length(), 100);
+  EXPECT_THAT(events[0].network_packet().uid(), 10);
+  EXPECT_THAT(events[0].network_packet().tag(), 123);
+  EXPECT_THAT(events[0].network_packet().ip_proto(), 6);
+  EXPECT_THAT(events[0].network_packet().tcp_flags(), 1);
+}
+
+TEST_F(NetworkTraceHandlerTest, WriteDirectionAndPorts) {
+  std::vector<PacketTrace> input = {
+      PacketTrace{
+          .timestampNs = 1,
+          .sport = htons(8080),
+          .dport = htons(443),
+          .egress = true,
+      },
+      PacketTrace{
+          .timestampNs = 2,
+          .sport = htons(443),
+          .dport = htons(8080),
+          .egress = false,
+      },
+  };
+
+  std::vector<TracePacket> events;
+  ASSERT_TRUE(TraceAndSortPackets(input, &events));
+
+  ASSERT_EQ(events.size(), 2);
+  EXPECT_THAT(events[0].network_packet().local_port(), 8080);
+  EXPECT_THAT(events[0].network_packet().remote_port(), 443);
+  EXPECT_THAT(events[0].network_packet().direction(),
+              TrafficDirection::DIR_EGRESS);
+  EXPECT_THAT(events[1].network_packet().local_port(), 8080);
+  EXPECT_THAT(events[1].network_packet().remote_port(), 443);
+  EXPECT_THAT(events[1].network_packet().direction(),
+              TrafficDirection::DIR_INGRESS);
+}
+
+}  // namespace bpf
+}  // namespace android
diff --git a/service-t/native/libs/libnetworkstats/NetworkTracePoller.cpp b/service-t/native/libs/libnetworkstats/NetworkTracePoller.cpp
index 34dbf9e..3abb49a 100644
--- a/service-t/native/libs/libnetworkstats/NetworkTracePoller.cpp
+++ b/service-t/native/libs/libnetworkstats/NetworkTracePoller.cpp
@@ -116,12 +116,16 @@
     return false;
   }
 
-  base::Result<int> ret = mRingBuffer->ConsumeAll(mCallback);
+  std::vector<PacketTrace> packets;
+  base::Result<int> ret = mRingBuffer->ConsumeAll(
+      [&](const PacketTrace& pkt) { packets.push_back(pkt); });
   if (!ret.ok()) {
     ALOGW("Failed to poll ringbuf: %s", ret.error().message().c_str());
     return false;
   }
 
+  mCallback(packets);
+
   return true;
 }
 
diff --git a/service-t/native/libs/libnetworkstats/NetworkTracePollerTest.cpp b/service-t/native/libs/libnetworkstats/NetworkTracePollerTest.cpp
index 28ec208..725cec1 100644
--- a/service-t/native/libs/libnetworkstats/NetworkTracePollerTest.cpp
+++ b/service-t/native/libs/libnetworkstats/NetworkTracePollerTest.cpp
@@ -100,7 +100,7 @@
 };
 
 TEST_F(NetworkTracePollerTest, PollWhileInactive) {
-  NetworkTracePoller handler([&](const PacketTrace& pkt) {});
+  NetworkTracePoller handler([&](const std::vector<PacketTrace>& pkt) {});
 
   // One succeed after start and before stop.
   EXPECT_FALSE(handler.ConsumeAll());
@@ -113,7 +113,7 @@
 TEST_F(NetworkTracePollerTest, ConcurrentSessions) {
   // Simulate two concurrent sessions (two starts followed by two stops). Check
   // that tracing is stopped only after both sessions finish.
-  NetworkTracePoller handler([&](const PacketTrace& pkt) {});
+  NetworkTracePoller handler([&](const std::vector<PacketTrace>& pkt) {});
 
   ASSERT_TRUE(handler.Start(kNeverPoll));
   EXPECT_TRUE(handler.ConsumeAll());
@@ -135,10 +135,12 @@
   // Record all packets with the bound address and current uid. This callback is
   // involked only within ConsumeAll, at which point the port should have
   // already been filled in and all packets have been processed.
-  NetworkTracePoller handler([&](const PacketTrace& pkt) {
-    if (pkt.sport != server_port && pkt.dport != server_port) return;
-    if (pkt.uid != getuid()) return;
-    packets.push_back(pkt);
+  NetworkTracePoller handler([&](const std::vector<PacketTrace>& pkts) {
+    for (const PacketTrace& pkt : pkts) {
+      if (pkt.sport != server_port && pkt.dport != server_port) return;
+      if (pkt.uid != getuid()) return;
+      packets.push_back(pkt);
+    }
   });
 
   ASSERT_TRUE(handler.Start(kNeverPoll));
diff --git a/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTraceHandler.h b/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTraceHandler.h
index 1266237..9520d7b 100644
--- a/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTraceHandler.h
+++ b/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTraceHandler.h
@@ -46,14 +46,26 @@
   void OnStart(const StartArgs&) override;
   void OnStop(const StopArgs&) override;
 
+  // Writes the packets as Perfetto TracePackets, creating packets as needed
+  // using the provided callback (which allows easy testing).
+  void Write(const std::vector<PacketTrace>& packets,
+             NetworkTraceHandler::TraceContext& ctx);
+
  private:
   // Convert a PacketTrace into a Perfetto trace packet.
   static void Fill(const PacketTrace& src,
                    ::perfetto::protos::pbzero::TracePacket& dst);
 
   static internal::NetworkTracePoller sPoller;
-  uint32_t mPollMs;
   bool mStarted;
+
+  // Values from config, see proto for details.
+  uint32_t mPollMs;
+  uint32_t mInternLimit;
+  uint32_t mAggregationThreshold;
+  bool mDropLocalPort;
+  bool mDropRemotePort;
+  bool mDropTcpFlags;
 };
 
 }  // namespace bpf
diff --git a/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTracePoller.h b/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTracePoller.h
index b0189a7..adde51e 100644
--- a/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTracePoller.h
+++ b/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTracePoller.h
@@ -38,9 +38,10 @@
 // it is not meant to be used elsewhere.
 class NetworkTracePoller {
  public:
+  using EventSink = std::function<void(const std::vector<PacketTrace>&)>;
+
   // Testonly: initialize with a callback capable of intercepting data.
-  NetworkTracePoller(std::function<void(const PacketTrace&)> callback)
-      : mCallback(std::move(callback)) {}
+  NetworkTracePoller(EventSink callback) : mCallback(std::move(callback)) {}
 
   // Starts tracing with the given poll interval.
   bool Start(uint32_t pollMs) EXCLUDES(mMutex);
@@ -67,7 +68,7 @@
   uint32_t mPollMs GUARDED_BY(mMutex);
 
   // The function to process PacketTrace, typically a Perfetto sink.
-  std::function<void(const PacketTrace&)> mCallback GUARDED_BY(mMutex);
+  EventSink mCallback GUARDED_BY(mMutex);
 
   // The BPF ring buffer handle.
   std::unique_ptr<BpfRingbuf<PacketTrace>> mRingBuffer GUARDED_BY(mMutex);