Add Perfetto part of NetworkTraceHandler

This adds the DataSource base class, data source registration and
overrides the lifecycle methods.

Adding the Perfetto SDK increases the size of the tethering apex by
450kb (~150 KB for the compressed apex).

Bug: 246985031
Test: atest libnetworkstats_test
Change-Id: Ie2e8f3e43c8080434408f752346e575a19e9042e
diff --git a/service-t/native/libs/libnetworkstats/Android.bp b/service-t/native/libs/libnetworkstats/Android.bp
index 5cb27e6..aa1ee41 100644
--- a/service-t/native/libs/libnetworkstats/Android.bp
+++ b/service-t/native/libs/libnetworkstats/Android.bp
@@ -31,6 +31,12 @@
         "libbase",
         "liblog",
     ],
+    static_libs: [
+        "libperfetto_client_experimental",
+    ],
+    export_static_lib_headers: [
+        "libperfetto_client_experimental",
+    ],
     export_include_dirs: ["include"],
     cflags: [
         "-Wall",
@@ -66,6 +72,7 @@
     static_libs: [
         "libgmock",
         "libnetworkstats",
+        "libperfetto_client_experimental",
     ],
     shared_libs: [
         "libbase",
diff --git a/service-t/native/libs/libnetworkstats/NetworkTraceHandler.cpp b/service-t/native/libs/libnetworkstats/NetworkTraceHandler.cpp
index c679357..a57dba3 100644
--- a/service-t/native/libs/libnetworkstats/NetworkTraceHandler.cpp
+++ b/service-t/native/libs/libnetworkstats/NetworkTraceHandler.cpp
@@ -18,11 +18,90 @@
 
 #include "netdbpf/NetworkTraceHandler.h"
 
+#include <arpa/inet.h>
 #include <bpf/BpfUtils.h>
 #include <log/log.h>
+#include <perfetto/config/android/network_trace_config.pbzero.h>
+#include <perfetto/trace/android/network_trace.pbzero.h>
+#include <perfetto/trace/profiling/profile_packet.pbzero.h>
+#include <perfetto/tracing/platform.h>
+
+// Note: this is initializing state for a templated Perfetto type that resides
+// in the `perfetto` namespace. This must be defined in the global scope.
+PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(android::bpf::NetworkTraceHandler);
 
 namespace android {
 namespace bpf {
+using ::perfetto::protos::pbzero::NetworkPacketEvent;
+using ::perfetto::protos::pbzero::NetworkPacketTraceConfig;
+using ::perfetto::protos::pbzero::TracePacket;
+using ::perfetto::protos::pbzero::TrafficDirection;
+
+// static
+void NetworkTraceHandler::RegisterDataSource() {
+  ALOGD("Registering Perfetto data source");
+  perfetto::DataSourceDescriptor dsd;
+  dsd.set_name("android.network_packets");
+  NetworkTraceHandler::Register(dsd);
+}
+
+NetworkTraceHandler::NetworkTraceHandler()
+    : NetworkTraceHandler([this](const PacketTrace& pkt) {
+        NetworkTraceHandler::Trace(
+            [this, pkt](NetworkTraceHandler::TraceContext ctx) {
+              Fill(pkt, *ctx.NewTracePacket());
+            });
+      }) {}
+
+void NetworkTraceHandler::OnSetup(const SetupArgs& args) {
+  const std::string& raw = args.config->network_packet_trace_config_raw();
+  NetworkPacketTraceConfig::Decoder config(raw);
+
+  mPollMs = config.poll_ms();
+  if (mPollMs < 100) {
+    ALOGI("poll_ms is missing or below the 100ms minimum. Increasing to 100ms");
+    mPollMs = 100;
+  }
+}
+
+void NetworkTraceHandler::OnStart(const StartArgs&) {
+  if (!Start()) return;
+  mTaskRunner = perfetto::Platform::GetDefaultPlatform()->CreateTaskRunner({});
+  Loop();
+}
+
+void NetworkTraceHandler::OnStop(const StopArgs&) {
+  Stop();
+  mTaskRunner.reset();
+}
+
+void NetworkTraceHandler::Loop() {
+  mTaskRunner->PostDelayedTask([this]() { Loop(); }, mPollMs);
+  ConsumeAll();
+}
+
+void NetworkTraceHandler::Fill(const PacketTrace& src, TracePacket& dst) {
+  dst.set_timestamp(src.timestampNs);
+  auto* event = dst.set_network_packet();
+  event->set_direction(src.egress ? TrafficDirection::DIR_EGRESS
+                                  : TrafficDirection::DIR_INGRESS);
+  event->set_length(src.length);
+  event->set_uid(src.uid);
+  event->set_tag(src.tag);
+
+  event->set_local_port(src.egress ? ntohs(src.sport) : ntohs(src.dport));
+  event->set_remote_port(src.egress ? ntohs(src.dport) : ntohs(src.sport));
+
+  event->set_ip_proto(src.ipProto);
+  event->set_tcp_flags(src.tcpFlags);
+
+  char ifname[IF_NAMESIZE] = {};
+  if (if_indextoname(src.ifindex, ifname) == ifname) {
+    event->set_interface(std::string(ifname));
+  } else {
+    event->set_interface("error");
+  }
+}
 
 bool NetworkTraceHandler::Start() {
   ALOGD("Starting datasource");
diff --git a/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTraceHandler.h b/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTraceHandler.h
index 67fcf41..d7c9432 100644
--- a/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTraceHandler.h
+++ b/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTraceHandler.h
@@ -16,6 +16,9 @@
 
 #pragma once
 
+#include <perfetto/base/task_runner.h>
+#include <perfetto/tracing.h>
+
 #include <string>
 #include <unordered_map>
 
@@ -28,18 +31,38 @@
 namespace android {
 namespace bpf {
 
-class NetworkTraceHandler {
+class NetworkTraceHandler : public perfetto::DataSource<NetworkTraceHandler> {
  public:
-  // Initialize with a callback capable of intercepting data.
+  // Registers this DataSource.
+  static void RegisterDataSource();
+
+  // Initialize with the default Perfetto callback.
+  NetworkTraceHandler();
+
+  // Testonly: initialize with a callback capable of intercepting data.
   NetworkTraceHandler(std::function<void(const PacketTrace&)> callback)
       : mCallback(std::move(callback)) {}
 
-  // Standalone functions without perfetto dependency.
+  // Testonly: standalone functions without perfetto dependency.
   bool Start();
   bool Stop();
   bool ConsumeAll();
 
+  // perfetto::DataSource overrides:
+  void OnSetup(const SetupArgs&) override;
+  void OnStart(const StartArgs&) override;
+  void OnStop(const StopArgs&) override;
+
+  // Convert a PacketTrace into a Perfetto trace packet.
+  void Fill(const PacketTrace& src,
+            ::perfetto::protos::pbzero::TracePacket& dst);
+
  private:
+  void Loop();
+
+  // How often to poll the ring buffer, defined by the trace config.
+  uint32_t mPollMs;
+
   // The function to process PacketTrace, typically a Perfetto sink.
   std::function<void(const PacketTrace&)> mCallback;
 
@@ -48,6 +71,10 @@
 
   // The packet tracing config map (really a 1-element array).
   BpfMap<uint32_t, bool> mConfigurationMap;
+
+  // This must be the last member, causing it to be the first deleted. If it is
+  // not, members required for callbacks can be deleted before it's stopped.
+  std::unique_ptr<perfetto::base::TaskRunner> mTaskRunner;
 };
 
 }  // namespace bpf