Support a PerfettoTrace Java API

Added a layer on top of the Perfetto C SDK that allows
creating equivalent 'PerfettoTeHl' structs on the heap.

This makes it possible for Java objects to control the
lifetime of these objects through JNI.

Each PerfettoTeHl struct has an equivalent C++ class allocated
on the heap which is in turn managed by an equivalent Java
class managed by the Java heap.

This design allows us to allocate objects once and re-use them
to serialize the trace event data from Java into the shmem.

The Java layer is responsible for caching the Perfetto Java
objects to avoid GC churn.

Test: atest PerfettoTraceTest
Change-Id: Ibb08e8b6cab7d86ac2c1d57c621c9074a4cb4077
Bug: 303199244
Flag: android.os.perfetto_sdk_tracing_v2
diff --git a/libs/tracing_perfetto/Android.bp b/libs/tracing_perfetto/Android.bp
index 9a2d4f7..8e1f115 100644
--- a/libs/tracing_perfetto/Android.bp
+++ b/libs/tracing_perfetto/Android.bp
@@ -37,6 +37,7 @@
     srcs: [
         "tracing_perfetto.cpp",
         "tracing_perfetto_internal.cpp",
+        "tracing_sdk.cpp",
     ],
 
     shared_libs: [
@@ -46,6 +47,10 @@
         "android.os.flags-aconfig-cc-host",
     ],
 
+    export_shared_lib_headers: [
+        "libperfetto_c",
+    ],
+
     host_supported: true,
     // for vndbinder
     vendor_available: true,
diff --git a/libs/tracing_perfetto/include/tracing_sdk.h b/libs/tracing_perfetto/include/tracing_sdk.h
new file mode 100644
index 0000000..4a6e849
--- /dev/null
+++ b/libs/tracing_perfetto/include/tracing_sdk.h
@@ -0,0 +1,461 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+#include <stdint.h>
+
+#include <optional>
+#include <vector>
+
+#include "perfetto/public/producer.h"
+#include "perfetto/public/te_category_macros.h"
+#include "perfetto/public/te_macros.h"
+#include "perfetto/public/track_event.h"
+
+/**
+ * The objects declared here are intended to be managed by Java.
+ * This means the Java Garbage Collector is responsible for freeing the
+ * underlying native resources.
+ *
+ * The static methods prefixed with `delete_` are special. They are designed to be
+ * invoked by Java through the `NativeAllocationRegistry` when the
+ * corresponding Java object becomes unreachable.  These methods act as
+ * callbacks to ensure proper deallocation of native resources.
+ */
+namespace tracing_perfetto {
+/**
+ * @brief Represents extra data associated with a trace event.
+ * This class manages a collection of PerfettoTeHlExtra pointers.
+ */
+class Extra;
+
+/**
+ * @brief Emits a trace event.
+ * @param type The type of the event.
+ * @param cat The category of the event.
+ * @param name The name of the event.
+ * @param arg_ptr Pointer to Extra data.
+ */
+void trace_event(int type, const PerfettoTeCategory* cat, const char* name,
+                 Extra* extra);
+
+/**
+ * @brief Gets the process track UUID.
+ */
+uint64_t get_process_track_uuid();
+
+/**
+ * @brief Gets the thread track UUID for a given PID.
+ */
+uint64_t get_thread_track_uuid(pid_t tid);
+
+/**
+ * @brief Holder for all the other classes in the file.
+ */
+class Extra {
+ public:
+  Extra();
+  void push_extra(PerfettoTeHlExtra* extra);
+  void pop_extra();
+  void clear_extras();
+  static void delete_extra(Extra* extra);
+
+  PerfettoTeHlExtra* const* get() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Extra);
+
+  // These PerfettoTeHlExtra pointers are really pointers to all the other
+  // types of extras: Category, DebugArg, Counter etc. Those objects are
+  // individually managed by Java.
+  std::vector<PerfettoTeHlExtra*> extras_;
+};
+
+/**
+ * @brief Represents a trace event category.
+ */
+class Category {
+ public:
+  Category(const std::string& name, const std::string& tag,
+           const std::string& severity);
+
+  ~Category();
+
+  void register_category();
+
+  void unregister_category();
+
+  bool is_category_enabled();
+
+  static void delete_category(Category* category);
+
+  const PerfettoTeCategory* get() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Category);
+  PerfettoTeCategory category_;
+  const std::string name_;
+  const std::string tag_;
+  const std::string severity_;
+};
+
+/**
+ * @brief Represents one end of a flow between two events.
+ */
+class Flow {
+ public:
+  Flow();
+
+  void set_process_flow(uint64_t id);
+  void set_process_terminating_flow(uint64_t id);
+  static void delete_flow(Flow* flow);
+
+  const PerfettoTeHlExtraFlow* get() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Flow);
+  PerfettoTeHlExtraFlow flow_;
+};
+
+/**
+ * @brief Represents a named track.
+ */
+class NamedTrack {
+ public:
+  NamedTrack(uint64_t id, uint64_t parent_uuid, const std::string& name);
+
+  static void delete_track(NamedTrack* track);
+
+  const PerfettoTeHlExtraNamedTrack* get() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NamedTrack);
+  const std::string name_;
+  PerfettoTeHlExtraNamedTrack track_;
+};
+
+/**
+ * @brief Represents a registered track.
+ */
+class RegisteredTrack {
+ public:
+  RegisteredTrack(uint64_t id, uint64_t parent_uuid, const std::string& name,
+                  bool is_counter);
+  ~RegisteredTrack();
+
+  void register_track();
+  void unregister_track();
+  static void delete_track(RegisteredTrack* track);
+
+  const PerfettoTeHlExtraRegisteredTrack* get() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RegisteredTrack);
+  PerfettoTeRegisteredTrack registered_track_;
+  PerfettoTeHlExtraRegisteredTrack track_;
+  const std::string name_;
+  const uint64_t id_;
+  const uint64_t parent_uuid_;
+  const bool is_counter_;
+};
+
+/**
+ * @brief Represents a counter track event.
+ * @tparam T The data type of the counter (int64_t or double).
+ */
+template <typename T>
+class Counter {
+ public:
+  template <typename>
+  struct always_false : std::false_type {};
+
+  struct TypeMap {
+    using type = std::invoke_result_t<decltype([]() {
+      if constexpr (std::is_same_v<T, int64_t>) {
+        return std::type_identity<PerfettoTeHlExtraCounterInt64>{};
+      } else if constexpr (std::is_same_v<T, double>) {
+        return std::type_identity<PerfettoTeHlExtraCounterDouble>{};
+      } else {
+        return std::type_identity<void>{};
+      }
+    })>::type;
+
+    static constexpr int enum_value = []() {
+      if constexpr (std::is_same_v<T, int64_t>) {
+        return PERFETTO_TE_HL_EXTRA_TYPE_COUNTER_INT64;
+      } else if constexpr (std::is_same_v<T, double>) {
+        return PERFETTO_TE_HL_EXTRA_TYPE_COUNTER_DOUBLE;
+      } else {
+        static_assert(always_false<T>::value, "Unsupported type");
+        return 0;  // Never reached, just to satisfy return type
+      }
+    }();
+  };
+
+  Counter() {
+    static_assert(!std::is_same_v<typename TypeMap::type, void>,
+                  "Unsupported type for Counter");
+
+    typename TypeMap::type counter;
+    counter.header = {TypeMap::enum_value};
+    counter_ = std::move(counter);
+  }
+
+  void set_value(T value) {
+    if constexpr (std::is_same_v<T, int64_t>) {
+      counter_.value = value;
+    } else if constexpr (std::is_same_v<T, double>) {
+      counter_.value = value;
+    }
+  }
+
+  static void delete_counter(Counter* counter) {
+    delete counter;
+  }
+
+  const TypeMap::type* get() const {
+    return &counter_;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Counter);
+  TypeMap::type counter_;
+};
+
+/**
+ * @brief Represents a debug argument for a trace event.
+ * @tparam T The data type of the argument (bool, int64_t, double, const char*).
+ */
+template <typename T>
+class DebugArg {
+ public:
+  template <typename>
+  struct always_false : std::false_type {};
+
+  struct TypeMap {
+    using type = std::invoke_result_t<decltype([]() {
+      if constexpr (std::is_same_v<T, bool>) {
+        return std::type_identity<PerfettoTeHlExtraDebugArgBool>{};
+      } else if constexpr (std::is_same_v<T, int64_t>) {
+        return std::type_identity<PerfettoTeHlExtraDebugArgInt64>{};
+      } else if constexpr (std::is_same_v<T, double>) {
+        return std::type_identity<PerfettoTeHlExtraDebugArgDouble>{};
+      } else if constexpr (std::is_same_v<T, const char*>) {
+        return std::type_identity<PerfettoTeHlExtraDebugArgString>{};
+      } else {
+        return std::type_identity<void>{};
+      }
+    })>::type;
+
+    static constexpr int enum_value = []() {
+      if constexpr (std::is_same_v<T, bool>) {
+        return PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_BOOL;
+      } else if constexpr (std::is_same_v<T, int64_t>) {
+        return PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_INT64;
+      } else if constexpr (std::is_same_v<T, double>) {
+        return PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_DOUBLE;
+      } else if constexpr (std::is_same_v<T, const char*>) {
+        return PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_STRING;
+      } else {
+        static_assert(always_false<T>::value, "Unsupported type");
+        return 0;  // Never reached, just to satisfy return type
+      }
+    }();
+  };
+
+  DebugArg(const std::string& name) : name_(name) {
+    static_assert(!std::is_same_v<typename TypeMap::type, void>,
+                  "Unsupported type for DebugArg");
+
+    typename TypeMap::type arg;
+    arg.header = {TypeMap::enum_value};
+    arg.name = name_.c_str();
+    arg_ = std::move(arg);
+  }
+
+  ~DebugArg() {
+    free_string_value();
+  }
+
+  void set_value(T value) {
+    if constexpr (std::is_same_v<T, const char*>) {
+      free_string_value();
+      arg_.value = value;
+    } else if constexpr (std::is_same_v<T, int64_t>) {
+      arg_.value = value;
+    } else if constexpr (std::is_same_v<T, bool>) {
+      arg_.value = value;
+    } else if constexpr (std::is_same_v<T, double>) {
+      arg_.value = value;
+    }
+  }
+
+  static void delete_arg(DebugArg* arg) {
+    delete arg;
+  }
+
+  const TypeMap::type* get() const {
+    return &arg_;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DebugArg);
+  TypeMap::type arg_;
+  const std::string name_;
+
+  constexpr void free_string_value() {
+    if constexpr (std::is_same_v<typename TypeMap::type,
+                                 PerfettoTeHlExtraDebugArgString>) {
+      if (arg_.value) {
+        free((void*)arg_.value);
+        arg_.value = nullptr;
+      }
+    }
+  }
+};
+
+template <typename T>
+class ProtoField {
+ public:
+  template <typename>
+  struct always_false : std::false_type {};
+
+  struct TypeMap {
+    using type = std::invoke_result_t<decltype([]() {
+      if constexpr (std::is_same_v<T, int64_t>) {
+        return std::type_identity<PerfettoTeHlProtoFieldVarInt>{};
+      } else if constexpr (std::is_same_v<T, double>) {
+        return std::type_identity<PerfettoTeHlProtoFieldDouble>{};
+      } else if constexpr (std::is_same_v<T, const char*>) {
+        return std::type_identity<PerfettoTeHlProtoFieldCstr>{};
+      } else {
+        return std::type_identity<void>{};
+      }
+    })>::type;
+
+    static constexpr PerfettoTeHlProtoFieldType enum_value = []() {
+      if constexpr (std::is_same_v<T, int64_t>) {
+        return PERFETTO_TE_HL_PROTO_TYPE_VARINT;
+      } else if constexpr (std::is_same_v<T, double>) {
+        return PERFETTO_TE_HL_PROTO_TYPE_DOUBLE;
+      } else if constexpr (std::is_same_v<T, const char*>) {
+        return PERFETTO_TE_HL_PROTO_TYPE_CSTR;
+      } else {
+        static_assert(always_false<T>::value, "Unsupported type");
+        return 0;  // Never reached, just to satisfy return type
+      }
+    }();
+  };
+
+  ProtoField() {
+    static_assert(!std::is_same_v<typename TypeMap::type, void>,
+                  "Unsupported type for ProtoField");
+
+    typename TypeMap::type arg;
+    arg.header.type = TypeMap::enum_value;
+    arg_ = std::move(arg);
+  }
+
+  ~ProtoField() {
+    free_string_value();
+  }
+
+  void set_value(uint32_t id, T value) {
+    if constexpr (std::is_same_v<T, int64_t>) {
+      arg_.header.id = id;
+      arg_.value = value;
+    } else if constexpr (std::is_same_v<T, double>) {
+      arg_.header.id = id;
+      arg_.value = value;
+    } else if constexpr (std::is_same_v<T, const char*>) {
+      free_string_value();
+      arg_.header.id = id;
+      arg_.str = value;
+    }
+  }
+
+  static void delete_field(ProtoField* field) {
+    delete field;
+  }
+
+  const TypeMap::type* get() const {
+    return &arg_;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ProtoField);
+  TypeMap::type arg_;
+
+  constexpr void free_string_value() {
+    if constexpr (std::is_same_v<typename TypeMap::type,
+                                 PerfettoTeHlProtoFieldCstr>) {
+      if (arg_.str) {
+        free((void*)arg_.str);
+        arg_.str = nullptr;
+      }
+    }
+  }
+};
+
+class ProtoFieldNested {
+ public:
+  ProtoFieldNested();
+
+  void add_field(PerfettoTeHlProtoField* field);
+  void set_id(uint32_t id);
+  static void delete_field(ProtoFieldNested* field);
+
+  const PerfettoTeHlProtoFieldNested* get() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ProtoFieldNested);
+  PerfettoTeHlProtoFieldNested field_;
+  // These PerfettoTeHlProtoField pointers are really pointers to all the other
+  // types of protos: PerfettoTeHlProtoFieldVarInt, PerfettoTeHlProtoFieldVarInt,
+  // PerfettoTeHlProtoFieldVarInt, PerfettoTeHlProtoFieldNested. Those objects are
+  // individually managed by Java.
+  std::vector<PerfettoTeHlProtoField*> fields_;
+};
+
+class Proto {
+ public:
+  Proto();
+
+  void add_field(PerfettoTeHlProtoField* field);
+  void clear_fields();
+  static void delete_proto(Proto* proto);
+
+  const PerfettoTeHlExtraProtoFields* get() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Proto);
+  PerfettoTeHlExtraProtoFields proto_;
+  // These PerfettoTeHlProtoField pointers are really pointers to all the other
+  // types of protos: PerfettoTeHlProtoFieldVarInt, PerfettoTeHlProtoFieldVarInt,
+  // PerfettoTeHlProtoFieldVarInt, PerfettoTeHlProtoFieldNested. Those objects are
+  // individually managed by Java.
+  std::vector<PerfettoTeHlProtoField*> fields_;
+};
+
+/**
+ * @brief Activates a trigger.
+ * @param name The name of the trigger.
+ * @param ttl_ms The time-to-live of the trigger in milliseconds.
+ */
+void activate_trigger(const char* name, uint32_t ttl_ms);
+}  // namespace tracing_perfetto
diff --git a/libs/tracing_perfetto/tests/Android.bp b/libs/tracing_perfetto/tests/Android.bp
index d203467..0dab517 100644
--- a/libs/tracing_perfetto/tests/Android.bp
+++ b/libs/tracing_perfetto/tests/Android.bp
@@ -21,12 +21,44 @@
     default_applicable_licenses: ["frameworks_native_license"],
 }
 
+cc_library_static {
+    name: "libtracing_perfetto_test_utils",
+    export_include_dirs: [
+        "include",
+    ],
+    static_libs: [
+        "libflagtest",
+        "libgmock",
+        "perfetto_trace_protos",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-enum-compare",
+        "-Wno-unused-function",
+    ],
+
+    srcs: [
+        "utils.cpp",
+    ],
+
+    shared_libs: [
+        "libperfetto_c",
+        "liblog",
+        "libprotobuf-cpp-lite",
+    ],
+    export_shared_lib_headers: [
+        "libperfetto_c",
+    ],
+}
+
 cc_test {
     name: "libtracing_perfetto_tests",
     static_libs: [
         "libflagtest",
         "libgmock",
         "perfetto_trace_protos",
+        "libtracing_perfetto_test_utils",
     ],
     cflags: [
         "-Wall",
@@ -42,7 +74,6 @@
     ],
     srcs: [
         "tracing_perfetto_test.cpp",
-        "utils.cpp",
     ],
     test_suites: ["device-tests"],
 }
diff --git a/libs/tracing_perfetto/tests/include/utils.h b/libs/tracing_perfetto/tests/include/utils.h
new file mode 100644
index 0000000..b2630e1
--- /dev/null
+++ b/libs/tracing_perfetto/tests/include/utils.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2024 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.
+ */
+
+// Copied from //external/perfetto/src/shared_lib/test/utils.h
+
+#ifndef UTILS_H
+#define UTILS_H
+
+#include <cassert>
+#include <condition_variable>
+#include <cstdint>
+#include <functional>
+#include <iterator>
+#include <memory>
+#include <mutex>
+#include <ostream>
+#include <string>
+#include <vector>
+
+#include "perfetto/public/abi/pb_decoder_abi.h"
+#include "perfetto/public/pb_utils.h"
+#include "perfetto/public/tracing_session.h"
+
+// Pretty printer for gtest
+void PrintTo(const PerfettoPbDecoderField& field, std::ostream*);
+
+namespace perfetto {
+namespace shlib {
+namespace test_utils {
+
+class WaitableEvent {
+ public:
+  WaitableEvent() = default;
+  void Notify() {
+    std::unique_lock<std::mutex> lock(m_);
+    notified_ = true;
+    cv_.notify_one();
+  }
+  bool WaitForNotification() {
+    std::unique_lock<std::mutex> lock(m_);
+    cv_.wait(lock, [this] { return notified_; });
+    return notified_;
+  }
+  bool IsNotified() {
+    std::unique_lock<std::mutex> lock(m_);
+    return notified_;
+  }
+
+ private:
+  std::mutex m_;
+  std::condition_variable cv_;
+  bool notified_ = false;
+};
+
+class TracingSession {
+ public:
+  class Builder {
+   public:
+    Builder() = default;
+    Builder& add_enabled_category(std::string category) {
+      enabled_categories_.push_back(std::move(category));
+      return *this;
+    }
+    Builder& add_disabled_category(std::string category) {
+      disabled_categories_.push_back(std::move(category));
+      return *this;
+    }
+    Builder& add_atrace_category(std::string category) {
+      atrace_categories_.push_back(std::move(category));
+      return *this;
+    }
+    Builder& add_atrace_category_prefer_sdk(std::string category) {
+      atrace_categories_prefer_sdk_.push_back(std::move(category));
+      return *this;
+    }
+    TracingSession Build();
+
+   private:
+    std::vector<std::string> enabled_categories_;
+    std::vector<std::string> disabled_categories_;
+    std::vector<std::string> atrace_categories_;
+    std::vector<std::string> atrace_categories_prefer_sdk_;
+  };
+
+  static TracingSession Adopt(struct PerfettoTracingSessionImpl*);
+  static TracingSession FromBytes(void *buf, size_t len);
+
+  TracingSession(TracingSession&&) noexcept;
+
+  ~TracingSession();
+
+  struct PerfettoTracingSessionImpl* session() const {
+    return session_;
+  }
+
+  bool FlushBlocking(uint32_t timeout_ms);
+  void WaitForStopped();
+  void StopBlocking();
+  std::vector<uint8_t> ReadBlocking();
+
+ private:
+  TracingSession() = default;
+  struct PerfettoTracingSessionImpl* session_;
+  std::unique_ptr<WaitableEvent> stopped_;
+};
+
+}  // namespace test_utils
+}  // namespace shlib
+}  // namespace perfetto
+
+#endif  // UTILS_H
diff --git a/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp b/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp
index e9fee2e..b21a090 100644
--- a/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp
+++ b/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp
@@ -22,6 +22,7 @@
 #include <unistd.h>
 
 #include "gtest/gtest.h"
+
 #include "perfetto/public/abi/data_source_abi.h"
 #include "perfetto/public/abi/heap_buffer.h"
 #include "perfetto/public/abi/pb_decoder_abi.h"
diff --git a/libs/tracing_perfetto/tests/utils.cpp b/libs/tracing_perfetto/tests/utils.cpp
index 8c4d4a8..af61bc2 100644
--- a/libs/tracing_perfetto/tests/utils.cpp
+++ b/libs/tracing_perfetto/tests/utils.cpp
@@ -34,36 +34,17 @@
 namespace perfetto {
 namespace shlib {
 namespace test_utils {
-namespace {
-
-std::string ToHexChars(uint8_t val) {
-  std::string ret;
-  uint8_t high_nibble = (val & 0xF0) >> 4;
-  uint8_t low_nibble = (val & 0xF);
-  static const char hex_chars[] = "0123456789ABCDEF";
-  ret.push_back(hex_chars[high_nibble]);
-  ret.push_back(hex_chars[low_nibble]);
-  return ret;
-}
-
-}  // namespace
-
 TracingSession TracingSession::Builder::Build() {
   perfetto::protos::TraceConfig trace_config;
   trace_config.add_buffers()->set_size_kb(1024);
 
-  auto* track_event_ds_config = trace_config.add_data_sources()->mutable_config();
-  auto* ftrace_ds_config = trace_config.add_data_sources()->mutable_config();
-
-  track_event_ds_config->set_name("track_event");
-  track_event_ds_config->set_target_buffer(0);
-
-  ftrace_ds_config->set_name("linux.ftrace");
-  ftrace_ds_config->set_target_buffer(0);
-
   {
-    auto* ftrace_config = ftrace_ds_config->mutable_ftrace_config();
     if (!atrace_categories_.empty()) {
+      auto* ftrace_ds_config = trace_config.add_data_sources()->mutable_config();
+      ftrace_ds_config->set_name("linux.ftrace");
+      ftrace_ds_config->set_target_buffer(0);
+
+      auto* ftrace_config = ftrace_ds_config->mutable_ftrace_config();
       ftrace_config->add_ftrace_events("ftrace/print");
       for (const std::string& cat : atrace_categories_) {
         ftrace_config->add_atrace_categories(cat);
@@ -76,8 +57,14 @@
   }
 
   {
-    auto* track_event_config = track_event_ds_config->mutable_track_event_config();
     if (!enabled_categories_.empty() || !disabled_categories_.empty()) {
+      auto* track_event_ds_config = trace_config.add_data_sources()->mutable_config();
+
+      track_event_ds_config->set_name("track_event");
+      track_event_ds_config->set_target_buffer(0);
+
+      auto* track_event_config = track_event_ds_config->mutable_track_event_config();
+
       for (const std::string& cat : enabled_categories_) {
         track_event_config->add_enabled_categories(cat);
       }
@@ -88,13 +75,17 @@
     }
   }
 
-  struct PerfettoTracingSessionImpl* ts =
-      PerfettoTracingSessionCreate(PERFETTO_BACKEND_SYSTEM);
-
   std::string trace_config_string;
   trace_config.SerializeToString(&trace_config_string);
 
-  PerfettoTracingSessionSetup(ts, trace_config_string.data(), trace_config_string.length());
+  return TracingSession::FromBytes(trace_config_string.data(), trace_config_string.length());
+}
+
+TracingSession TracingSession::FromBytes(void *buf, size_t len) {
+  struct PerfettoTracingSessionImpl* ts =
+      PerfettoTracingSessionCreate(PERFETTO_BACKEND_SYSTEM);
+
+  PerfettoTracingSessionSetup(ts, buf, len);
 
   // Fails to start here
   PerfettoTracingSessionStartBlocking(ts);
@@ -177,39 +168,3 @@
 }  // namespace test_utils
 }  // namespace shlib
 }  // namespace perfetto
-
-void PrintTo(const PerfettoPbDecoderField& field, std::ostream* pos) {
-  std::ostream& os = *pos;
-  PerfettoPbDecoderStatus status =
-      static_cast<PerfettoPbDecoderStatus>(field.status);
-  switch (status) {
-    case PERFETTO_PB_DECODER_ERROR:
-      os << "MALFORMED PROTOBUF";
-      break;
-    case PERFETTO_PB_DECODER_DONE:
-      os << "DECODER DONE";
-      break;
-    case PERFETTO_PB_DECODER_OK:
-      switch (field.wire_type) {
-        case PERFETTO_PB_WIRE_TYPE_DELIMITED:
-          os << "\"";
-          for (size_t i = 0; i < field.value.delimited.len; i++) {
-            os << perfetto::shlib::test_utils::ToHexChars(
-                      field.value.delimited.start[i])
-               << " ";
-          }
-          os << "\"";
-          break;
-        case PERFETTO_PB_WIRE_TYPE_VARINT:
-          os << "varint: " << field.value.integer64;
-          break;
-        case PERFETTO_PB_WIRE_TYPE_FIXED32:
-          os << "fixed32: " << field.value.integer32;
-          break;
-        case PERFETTO_PB_WIRE_TYPE_FIXED64:
-          os << "fixed64: " << field.value.integer64;
-          break;
-      }
-      break;
-  }
-}
diff --git a/libs/tracing_perfetto/tests/utils.h b/libs/tracing_perfetto/tests/utils.h
deleted file mode 100644
index 8edb414..0000000
--- a/libs/tracing_perfetto/tests/utils.h
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * Copyright 2024 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.
- */
-
-// Copied from //external/perfetto/src/shared_lib/test/utils.h
-
-#ifndef UTILS_H
-#define UTILS_H
-
-#include <cassert>
-#include <condition_variable>
-#include <cstdint>
-#include <functional>
-#include <iterator>
-#include <memory>
-#include <mutex>
-#include <ostream>
-#include <string>
-#include <vector>
-
-#include "gmock/gmock-matchers.h"
-#include "gmock/gmock-more-matchers.h"
-#include "gtest/gtest-matchers.h"
-#include "gtest/gtest.h"
-#include "perfetto/public/abi/pb_decoder_abi.h"
-#include "perfetto/public/pb_utils.h"
-#include "perfetto/public/tracing_session.h"
-
-// Pretty printer for gtest
-void PrintTo(const PerfettoPbDecoderField& field, std::ostream*);
-
-namespace perfetto {
-namespace shlib {
-namespace test_utils {
-
-class WaitableEvent {
- public:
-  WaitableEvent() = default;
-  void Notify() {
-    std::unique_lock<std::mutex> lock(m_);
-    notified_ = true;
-    cv_.notify_one();
-  }
-  bool WaitForNotification() {
-    std::unique_lock<std::mutex> lock(m_);
-    cv_.wait(lock, [this] { return notified_; });
-    return notified_;
-  }
-  bool IsNotified() {
-    std::unique_lock<std::mutex> lock(m_);
-    return notified_;
-  }
-
- private:
-  std::mutex m_;
-  std::condition_variable cv_;
-  bool notified_ = false;
-};
-
-class TracingSession {
- public:
-  class Builder {
-   public:
-    Builder() = default;
-    Builder& add_enabled_category(std::string category) {
-      enabled_categories_.push_back(std::move(category));
-      return *this;
-    }
-    Builder& add_disabled_category(std::string category) {
-      disabled_categories_.push_back(std::move(category));
-      return *this;
-    }
-    Builder& add_atrace_category(std::string category) {
-      atrace_categories_.push_back(std::move(category));
-      return *this;
-    }
-    Builder& add_atrace_category_prefer_sdk(std::string category) {
-      atrace_categories_prefer_sdk_.push_back(std::move(category));
-      return *this;
-    }
-    TracingSession Build();
-
-   private:
-    std::vector<std::string> enabled_categories_;
-    std::vector<std::string> disabled_categories_;
-    std::vector<std::string> atrace_categories_;
-    std::vector<std::string> atrace_categories_prefer_sdk_;
-  };
-
-  static TracingSession Adopt(struct PerfettoTracingSessionImpl*);
-
-  TracingSession(TracingSession&&) noexcept;
-
-  ~TracingSession();
-
-  struct PerfettoTracingSessionImpl* session() const {
-    return session_;
-  }
-
-  bool FlushBlocking(uint32_t timeout_ms);
-  void WaitForStopped();
-  void StopBlocking();
-  std::vector<uint8_t> ReadBlocking();
-
- private:
-  TracingSession() = default;
-  struct PerfettoTracingSessionImpl* session_;
-  std::unique_ptr<WaitableEvent> stopped_;
-};
-
-template <typename FieldSkipper>
-class FieldViewBase {
- public:
-  class Iterator {
-   public:
-    using iterator_category = std::input_iterator_tag;
-    using value_type = const PerfettoPbDecoderField;
-    using pointer = value_type;
-    using reference = value_type;
-    reference operator*() const {
-      struct PerfettoPbDecoder decoder;
-      decoder.read_ptr = read_ptr_;
-      decoder.end_ptr = end_ptr_;
-      struct PerfettoPbDecoderField field;
-      do {
-        field = PerfettoPbDecoderParseField(&decoder);
-      } while (field.status == PERFETTO_PB_DECODER_OK &&
-               skipper_.ShouldSkip(field));
-      return field;
-    }
-    Iterator& operator++() {
-      struct PerfettoPbDecoder decoder;
-      decoder.read_ptr = read_ptr_;
-      decoder.end_ptr = end_ptr_;
-      PerfettoPbDecoderSkipField(&decoder);
-      read_ptr_ = decoder.read_ptr;
-      AdvanceToFirstInterestingField();
-      return *this;
-    }
-    Iterator operator++(int) {
-      Iterator tmp = *this;
-      ++(*this);
-      return tmp;
-    }
-
-    friend bool operator==(const Iterator& a, const Iterator& b) {
-      return a.read_ptr_ == b.read_ptr_;
-    }
-    friend bool operator!=(const Iterator& a, const Iterator& b) {
-      return a.read_ptr_ != b.read_ptr_;
-    }
-
-   private:
-    Iterator(const uint8_t* read_ptr, const uint8_t* end_ptr,
-             const FieldSkipper& skipper)
-        : read_ptr_(read_ptr), end_ptr_(end_ptr), skipper_(skipper) {
-      AdvanceToFirstInterestingField();
-    }
-    void AdvanceToFirstInterestingField() {
-      struct PerfettoPbDecoder decoder;
-      decoder.read_ptr = read_ptr_;
-      decoder.end_ptr = end_ptr_;
-      struct PerfettoPbDecoderField field;
-      const uint8_t* prev_read_ptr;
-      do {
-        prev_read_ptr = decoder.read_ptr;
-        field = PerfettoPbDecoderParseField(&decoder);
-      } while (field.status == PERFETTO_PB_DECODER_OK &&
-               skipper_.ShouldSkip(field));
-      if (field.status == PERFETTO_PB_DECODER_OK) {
-        read_ptr_ = prev_read_ptr;
-      } else {
-        read_ptr_ = decoder.read_ptr;
-      }
-    }
-    friend class FieldViewBase<FieldSkipper>;
-    const uint8_t* read_ptr_;
-    const uint8_t* end_ptr_;
-    const FieldSkipper& skipper_;
-  };
-  using value_type = const PerfettoPbDecoderField;
-  using const_iterator = Iterator;
-  template <typename... Args>
-  explicit FieldViewBase(const uint8_t* begin, const uint8_t* end, Args... args)
-      : begin_(begin), end_(end), s_(args...) {
-  }
-  template <typename... Args>
-  explicit FieldViewBase(const std::vector<uint8_t>& data, Args... args)
-      : FieldViewBase(data.data(), data.data() + data.size(), args...) {
-  }
-  template <typename... Args>
-  explicit FieldViewBase(const struct PerfettoPbDecoderField& field,
-                         Args... args)
-      : s_(args...) {
-    if (field.wire_type != PERFETTO_PB_WIRE_TYPE_DELIMITED) {
-      abort();
-    }
-    begin_ = field.value.delimited.start;
-    end_ = begin_ + field.value.delimited.len;
-  }
-  Iterator begin() const {
-    return Iterator(begin_, end_, s_);
-  }
-  Iterator end() const {
-    return Iterator(end_, end_, s_);
-  }
-  PerfettoPbDecoderField front() const {
-    return *begin();
-  }
-
-  size_t size() const {
-    size_t count = 0;
-    for (auto field : *this) {
-      (void)field;
-      count++;
-    }
-    return count;
-  }
-
-  bool ok() const {
-    for (auto field : *this) {
-      if (field.status != PERFETTO_PB_DECODER_OK) {
-        return false;
-      }
-    }
-    return true;
-  }
-
- private:
-  const uint8_t* begin_;
-  const uint8_t* end_;
-  FieldSkipper s_;
-};
-
-// Pretty printer for gtest
-template <typename FieldSkipper>
-void PrintTo(const FieldViewBase<FieldSkipper>& field_view, std::ostream* pos) {
-  std::ostream& os = *pos;
-  os << "{";
-  for (PerfettoPbDecoderField f : field_view) {
-    PrintTo(f, pos);
-    os << ", ";
-  }
-  os << "}";
-}
-
-class IdFieldSkipper {
- public:
-  explicit IdFieldSkipper(uint32_t id) : id_(id) {
-  }
-  explicit IdFieldSkipper(int32_t id) : id_(static_cast<uint32_t>(id)) {
-  }
-  bool ShouldSkip(const struct PerfettoPbDecoderField& field) const {
-    return field.id != id_;
-  }
-
- private:
-  uint32_t id_;
-};
-
-class NoFieldSkipper {
- public:
-  NoFieldSkipper() = default;
-  bool ShouldSkip(const struct PerfettoPbDecoderField&) const {
-    return false;
-  }
-};
-
-// View over all the fields of a contiguous serialized protobuf message.
-//
-// Examples:
-//
-// for (struct PerfettoPbDecoderField field : FieldView(msg_begin, msg_end)) {
-//   //...
-// }
-// FieldView fields2(/*PerfettoPbDecoderField*/ nested_field);
-// FieldView fields3(/*std::vector<uint8_t>*/ data);
-// size_t num = fields1.size(); // The number of fields.
-// bool ok = fields1.ok(); // Checks that the message is not malformed.
-using FieldView = FieldViewBase<NoFieldSkipper>;
-
-// Like `FieldView`, but only considers fields with a specific id.
-//
-// Examples:
-//
-// IdFieldView fields(msg_begin, msg_end, id)
-using IdFieldView = FieldViewBase<IdFieldSkipper>;
-
-// Matches a PerfettoPbDecoderField with the specified id. Accepts another
-// matcher to match the contents of the field.
-//
-// Example:
-// PerfettoPbDecoderField field = ...
-// EXPECT_THAT(field, PbField(900, VarIntField(5)));
-template <typename M>
-auto PbField(int32_t id, M m) {
-  return testing::AllOf(
-      testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
-      testing::Field(&PerfettoPbDecoderField::id, id), m);
-}
-
-// Matches a PerfettoPbDecoderField submessage field. Accepts a container
-// matcher for the subfields.
-//
-// Example:
-// PerfettoPbDecoderField field = ...
-// EXPECT_THAT(field, MsgField(ElementsAre(...)));
-template <typename M>
-auto MsgField(M m) {
-  auto f = [](const PerfettoPbDecoderField& field) { return FieldView(field); };
-  return testing::AllOf(
-      testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
-      testing::Field(&PerfettoPbDecoderField::wire_type,
-                     PERFETTO_PB_WIRE_TYPE_DELIMITED),
-      testing::ResultOf(f, m));
-}
-
-// Matches a PerfettoPbDecoderField length delimited field. Accepts a string
-// matcher.
-//
-// Example:
-// PerfettoPbDecoderField field = ...
-// EXPECT_THAT(field, StringField("string"));
-template <typename M>
-auto StringField(M m) {
-  auto f = [](const PerfettoPbDecoderField& field) {
-    return std::string(
-        reinterpret_cast<const char*>(field.value.delimited.start),
-        field.value.delimited.len);
-  };
-  return testing::AllOf(
-      testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
-      testing::Field(&PerfettoPbDecoderField::wire_type,
-                     PERFETTO_PB_WIRE_TYPE_DELIMITED),
-      testing::ResultOf(f, m));
-}
-
-// Matches a PerfettoPbDecoderField VarInt field. Accepts an integer matcher
-//
-// Example:
-// PerfettoPbDecoderField field = ...
-// EXPECT_THAT(field, VarIntField(1)));
-template <typename M>
-auto VarIntField(M m) {
-  auto f = [](const PerfettoPbDecoderField& field) {
-    return field.value.integer64;
-  };
-  return testing::AllOf(
-      testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
-      testing::Field(&PerfettoPbDecoderField::wire_type,
-                     PERFETTO_PB_WIRE_TYPE_VARINT),
-      testing::ResultOf(f, m));
-}
-
-// Matches a PerfettoPbDecoderField fixed64 field. Accepts an integer matcher
-//
-// Example:
-// PerfettoPbDecoderField field = ...
-// EXPECT_THAT(field, Fixed64Field(1)));
-template <typename M>
-auto Fixed64Field(M m) {
-  auto f = [](const PerfettoPbDecoderField& field) {
-    return field.value.integer64;
-  };
-  return testing::AllOf(
-      testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
-      testing::Field(&PerfettoPbDecoderField::wire_type,
-                     PERFETTO_PB_WIRE_TYPE_FIXED64),
-      testing::ResultOf(f, m));
-}
-
-// Matches a PerfettoPbDecoderField fixed32 field. Accepts an integer matcher
-//
-// Example:
-// PerfettoPbDecoderField field = ...
-// EXPECT_THAT(field, Fixed32Field(1)));
-template <typename M>
-auto Fixed32Field(M m) {
-  auto f = [](const PerfettoPbDecoderField& field) {
-    return field.value.integer32;
-  };
-  return testing::AllOf(
-      testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
-      testing::Field(&PerfettoPbDecoderField::wire_type,
-                     PERFETTO_PB_WIRE_TYPE_FIXED32),
-      testing::ResultOf(f, m));
-}
-
-// Matches a PerfettoPbDecoderField double field. Accepts a double matcher
-//
-// Example:
-// PerfettoPbDecoderField field = ...
-// EXPECT_THAT(field, DoubleField(1.0)));
-template <typename M>
-auto DoubleField(M m) {
-  auto f = [](const PerfettoPbDecoderField& field) {
-    return field.value.double_val;
-  };
-  return testing::AllOf(
-      testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
-      testing::Field(&PerfettoPbDecoderField::wire_type,
-                     PERFETTO_PB_WIRE_TYPE_FIXED64),
-      testing::ResultOf(f, m));
-}
-
-// Matches a PerfettoPbDecoderField float field. Accepts a float matcher
-//
-// Example:
-// PerfettoPbDecoderField field = ...
-// EXPECT_THAT(field, FloatField(1.0)));
-template <typename M>
-auto FloatField(M m) {
-  auto f = [](const PerfettoPbDecoderField& field) {
-    return field.value.float_val;
-  };
-  return testing::AllOf(
-      testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
-      testing::Field(&PerfettoPbDecoderField::wire_type,
-                     PERFETTO_PB_WIRE_TYPE_FIXED32),
-      testing::ResultOf(f, m));
-}
-
-// Matches a PerfettoPbDecoderField submessage field. Accepts a container
-// matcher for the subfields.
-//
-// Example:
-// PerfettoPbDecoderField field = ...
-// EXPECT_THAT(field, AllFieldsWithId(900, ElementsAre(...)));
-template <typename M>
-auto AllFieldsWithId(int32_t id, M m) {
-  auto f = [id](const PerfettoPbDecoderField& field) {
-    return IdFieldView(field, id);
-  };
-  return testing::AllOf(
-      testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
-      testing::Field(&PerfettoPbDecoderField::wire_type,
-                     PERFETTO_PB_WIRE_TYPE_DELIMITED),
-      testing::ResultOf(f, m));
-}
-
-}  // namespace test_utils
-}  // namespace shlib
-}  // namespace perfetto
-
-#endif  // UTILS_H
diff --git a/libs/tracing_perfetto/tracing_perfetto.cpp b/libs/tracing_perfetto/tracing_perfetto.cpp
index c35e078..4b70213 100644
--- a/libs/tracing_perfetto/tracing_perfetto.cpp
+++ b/libs/tracing_perfetto/tracing_perfetto.cpp
@@ -17,6 +17,7 @@
 #include "tracing_perfetto.h"
 
 #include <cutils/trace.h>
+
 #include <cstdarg>
 
 #include "perfetto/public/te_category_macros.h"
@@ -43,8 +44,10 @@
 void traceFormatBegin(uint64_t category, const char* fmt, ...) {
   struct PerfettoTeCategory* perfettoTeCategory =
       internal::toPerfettoCategory(category);
-  const bool preferAtrace = internal::shouldPreferAtrace(perfettoTeCategory, category);
-  const bool preferPerfetto = internal::isPerfettoCategoryEnabled(perfettoTeCategory);
+  const bool preferAtrace =
+      internal::shouldPreferAtrace(perfettoTeCategory, category);
+  const bool preferPerfetto =
+      internal::isPerfettoCategoryEnabled(perfettoTeCategory);
   if (CC_LIKELY(!(preferAtrace || preferPerfetto))) {
     return;
   }
@@ -57,7 +60,6 @@
   vsnprintf(buf, BUFFER_SIZE, fmt, ap);
   va_end(ap);
 
-
   if (preferAtrace) {
     atrace_begin(category, buf);
   } else if (preferPerfetto) {
@@ -99,26 +101,28 @@
 }
 
 void traceAsyncBeginForTrack(uint64_t category, const char* name,
-                               const char* trackName, int32_t cookie) {
+                             const char* trackName, int32_t cookie) {
   struct PerfettoTeCategory* perfettoTeCategory =
       internal::toPerfettoCategory(category);
 
   if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
     atrace_async_for_track_begin(category, trackName, name, cookie);
   } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
-    internal::perfettoTraceAsyncBeginForTrack(*perfettoTeCategory, name, trackName, cookie);
+    internal::perfettoTraceAsyncBeginForTrack(*perfettoTeCategory, name,
+                                              trackName, cookie);
   }
 }
 
 void traceAsyncEndForTrack(uint64_t category, const char* trackName,
-                             int32_t cookie) {
+                           int32_t cookie) {
   struct PerfettoTeCategory* perfettoTeCategory =
       internal::toPerfettoCategory(category);
 
   if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
     atrace_async_for_track_end(category, trackName, cookie);
   } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
-    internal::perfettoTraceAsyncEndForTrack(*perfettoTeCategory, trackName, cookie);
+    internal::perfettoTraceAsyncEndForTrack(*perfettoTeCategory, trackName,
+                                            cookie);
   }
 }
 
@@ -136,8 +140,10 @@
 void traceFormatInstant(uint64_t category, const char* fmt, ...) {
   struct PerfettoTeCategory* perfettoTeCategory =
       internal::toPerfettoCategory(category);
-  const bool preferAtrace = internal::shouldPreferAtrace(perfettoTeCategory, category);
-  const bool preferPerfetto = internal::isPerfettoCategoryEnabled(perfettoTeCategory);
+  const bool preferAtrace =
+      internal::shouldPreferAtrace(perfettoTeCategory, category);
+  const bool preferPerfetto =
+      internal::isPerfettoCategoryEnabled(perfettoTeCategory);
   if (CC_LIKELY(!(preferAtrace || preferPerfetto))) {
     return;
   }
@@ -158,7 +164,7 @@
 }
 
 void traceInstantForTrack(uint64_t category, const char* trackName,
-                            const char* name) {
+                          const char* name) {
   struct PerfettoTeCategory* perfettoTeCategory =
       internal::toPerfettoCategory(category);
 
@@ -181,20 +187,21 @@
 }
 
 void traceCounter32(uint64_t category, const char* name, int32_t value) {
-  struct PerfettoTeCategory* perfettoTeCategory = internal::toPerfettoCategory(category);
+  struct PerfettoTeCategory* perfettoTeCategory =
+      internal::toPerfettoCategory(category);
   if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
     atrace_int(category, name, value);
   } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
     internal::perfettoTraceCounter(*perfettoTeCategory, name,
-                                          static_cast<int64_t>(value));
+                                   static_cast<int64_t>(value));
   }
 }
 
 bool isTagEnabled(uint64_t category) {
   struct PerfettoTeCategory* perfettoTeCategory =
       internal::toPerfettoCategory(category);
-  return internal::isPerfettoCategoryEnabled(perfettoTeCategory)
-      || atrace_is_tag_enabled(category);
+  return internal::isPerfettoCategoryEnabled(perfettoTeCategory) ||
+         atrace_is_tag_enabled(category);
 }
 
 }  // namespace tracing_perfetto
diff --git a/libs/tracing_perfetto/tracing_sdk.cpp b/libs/tracing_perfetto/tracing_sdk.cpp
new file mode 100644
index 0000000..02e8d10
--- /dev/null
+++ b/libs/tracing_perfetto/tracing_sdk.cpp
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2024 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 "tracing_sdk.h"
+
+#include <android-base/logging.h>
+#include <cutils/trace.h>
+
+#include <cstdarg>
+#include <cstdlib>
+
+#include "perfetto/public/abi/producer_abi.h"
+#include "perfetto/public/te_category_macros.h"
+#include "perfetto/public/te_macros.h"
+#include "perfetto/public/track_event.h"
+#include "tracing_perfetto.h"
+
+namespace tracing_perfetto {
+void trace_event(int type, const PerfettoTeCategory* perfettoTeCategory,
+                 const char* name, tracing_perfetto::Extra* extra) {
+  bool enabled = PERFETTO_UNLIKELY(PERFETTO_ATOMIC_LOAD_EXPLICIT(
+      perfettoTeCategory->enabled, PERFETTO_MEMORY_ORDER_RELAXED));
+  if (enabled) {
+    extra->push_extra(nullptr);
+    PerfettoTeHlEmitImpl(perfettoTeCategory->impl, type,
+                         type == PERFETTO_TE_TYPE_COUNTER ? nullptr : name,
+                         extra->get());
+    extra->pop_extra();
+  }
+}
+
+uint64_t get_process_track_uuid() {
+  return PerfettoTeProcessTrackUuid();
+}
+
+uint64_t get_thread_track_uuid(pid_t tid) {
+  // Cating a signed pid_t to unsigned
+  return PerfettoTeProcessTrackUuid() ^ PERFETTO_STATIC_CAST(uint64_t, tid);
+}
+
+Extra::Extra() {
+}
+
+void Extra::push_extra(PerfettoTeHlExtra* ptr) {
+  extras_.push_back(ptr);
+}
+
+void Extra::pop_extra() {
+  extras_.pop_back();
+}
+
+void Extra::clear_extras() {
+  extras_.clear();
+}
+
+void Extra::delete_extra(Extra* ptr) {
+  delete ptr;
+}
+
+PerfettoTeHlExtra* const* Extra::get() const {
+  return extras_.data();
+}
+
+Category::Category(const std::string& name, const std::string& tag,
+                   const std::string& severity)
+    : category_({.enabled = &perfetto_atomic_false}),
+      name_(name),
+      tag_(tag),
+      severity_(severity) {
+}
+
+Category::~Category() {
+  unregister_category();
+}
+
+void Category::register_category() {
+  if (category_.impl) return;
+
+  std::vector<const char*> tags;
+  if (!tag_.empty()) tags.push_back(tag_.data());
+  if (!severity_.empty()) tags.push_back(severity_.data());
+
+  category_.desc = {name_.c_str(), name_.c_str(), tags.data(), tags.size()};
+
+  PerfettoTeCategoryRegister(&category_);
+  PerfettoTePublishCategories();
+}
+
+void Category::unregister_category() {
+  if (!category_.impl) return;
+
+  PerfettoTeCategoryUnregister(&category_);
+  PerfettoTePublishCategories();
+}
+
+bool Category::is_category_enabled() {
+  return PERFETTO_UNLIKELY(PERFETTO_ATOMIC_LOAD_EXPLICIT(
+      (category_).enabled, PERFETTO_MEMORY_ORDER_RELAXED));
+}
+
+const PerfettoTeCategory* Category::get() const {
+  return &category_;
+}
+
+void Category::delete_category(Category* ptr) {
+  delete ptr;
+}
+
+Flow::Flow() : flow_{} {
+}
+
+void Flow::set_process_flow(uint64_t id) {
+  flow_.header.type = PERFETTO_TE_HL_EXTRA_TYPE_FLOW;
+  PerfettoTeFlow ret = PerfettoTeProcessScopedFlow(id);
+  flow_.id = ret.id;
+}
+
+void Flow::set_process_terminating_flow(uint64_t id) {
+  flow_.header.type = PERFETTO_TE_HL_EXTRA_TYPE_TERMINATING_FLOW;
+  PerfettoTeFlow ret = PerfettoTeProcessScopedFlow(id);
+  flow_.id = ret.id;
+}
+
+const PerfettoTeHlExtraFlow* Flow::get() const {
+  return &flow_;
+}
+
+void Flow::delete_flow(Flow* ptr) {
+  delete ptr;
+}
+
+NamedTrack::NamedTrack(uint64_t id, uint64_t parent_uuid,
+                       const std::string& name)
+    : name_(name),
+      track_{{PERFETTO_TE_HL_EXTRA_TYPE_NAMED_TRACK},
+             name_.data(),
+             id,
+             parent_uuid} {
+}
+
+const PerfettoTeHlExtraNamedTrack* NamedTrack::get() const {
+  return &track_;
+}
+
+void NamedTrack::delete_track(NamedTrack* ptr) {
+  delete ptr;
+}
+
+RegisteredTrack::RegisteredTrack(uint64_t id, uint64_t parent_uuid,
+                                 const std::string& name, bool is_counter)
+    : registered_track_{},
+      track_{{PERFETTO_TE_HL_EXTRA_TYPE_REGISTERED_TRACK},
+             &(registered_track_.impl)},
+      name_(name),
+      id_(id),
+      parent_uuid_(parent_uuid),
+      is_counter_(is_counter) {
+  register_track();
+}
+
+RegisteredTrack::~RegisteredTrack() {
+  unregister_track();
+}
+
+void RegisteredTrack::register_track() {
+  if (registered_track_.impl.descriptor) return;
+
+  if (is_counter_) {
+    PerfettoTeCounterTrackRegister(&registered_track_, name_.data(),
+                                   parent_uuid_);
+  } else {
+    PerfettoTeNamedTrackRegister(&registered_track_, name_.data(), id_,
+                                 parent_uuid_);
+  }
+}
+
+void RegisteredTrack::unregister_track() {
+  if (!registered_track_.impl.descriptor) return;
+  PerfettoTeRegisteredTrackUnregister(&registered_track_);
+}
+
+const PerfettoTeHlExtraRegisteredTrack* RegisteredTrack::get() const {
+  return &track_;
+}
+
+void RegisteredTrack::delete_track(RegisteredTrack* ptr) {
+  delete ptr;
+}
+
+Proto::Proto() : proto_({PERFETTO_TE_HL_EXTRA_TYPE_PROTO_FIELDS}, nullptr) {
+}
+
+void Proto::add_field(PerfettoTeHlProtoField* ptr) {
+  if (!fields_.empty()) {
+    fields_.pop_back();
+  }
+
+  fields_.push_back(ptr);
+  fields_.push_back(nullptr);
+  proto_.fields = fields_.data();
+}
+
+void Proto::clear_fields() {
+  fields_.clear();
+  proto_.fields = nullptr;
+}
+
+void Proto::delete_proto(Proto* ptr) {
+  delete ptr;
+}
+
+const PerfettoTeHlExtraProtoFields* Proto::get() const {
+  return &proto_;
+}
+
+ProtoFieldNested::ProtoFieldNested()
+    : field_({PERFETTO_TE_HL_PROTO_TYPE_NESTED}, nullptr) {
+}
+
+void ProtoFieldNested::add_field(PerfettoTeHlProtoField* ptr) {
+  if (!fields_.empty()) {
+    fields_.pop_back();
+  }
+
+  fields_.push_back(ptr);
+  fields_.push_back(nullptr);
+  field_.fields = fields_.data();
+}
+
+void ProtoFieldNested::set_id(uint32_t id) {
+  fields_.clear();
+  field_.header.id = id;
+  field_.fields = nullptr;
+}
+
+void ProtoFieldNested::delete_field(ProtoFieldNested* ptr) {
+  delete ptr;
+}
+
+const PerfettoTeHlProtoFieldNested* ProtoFieldNested::get() const {
+  return &field_;
+}
+
+void activate_trigger(const char* name, uint32_t ttl_ms) {
+  const char* names[] = {name, nullptr};
+  PerfettoProducerActivateTriggers(names, ttl_ms);
+}
+}  // namespace tracing_perfetto