Shared library ABI for tracing session

So that clients of the shared library can start tracing session and read
tracing data.

This is mostly useful for testing the shared library itself.

Bug: 184929776
Change-Id: Ic88d11e2c533bf4bf0b06b1d1c01686332c0c8c8
diff --git a/include/perfetto/public/abi/tracing_session_abi.h b/include/perfetto/public/abi/tracing_session_abi.h
new file mode 100644
index 0000000..bb044d9
--- /dev/null
+++ b/include/perfetto/public/abi/tracing_session_abi.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#ifndef INCLUDE_PERFETTO_PUBLIC_ABI_TRACING_SESSION_ABI_H_
+#define INCLUDE_PERFETTO_PUBLIC_ABI_TRACING_SESSION_ABI_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "perfetto/public/abi/backend_type.h"
+#include "perfetto/public/abi/export.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Opaque pointer to the internal representation of a tracing session.
+struct PerfettoTracingSessionImpl;
+
+PERFETTO_SDK_EXPORT struct PerfettoTracingSessionImpl*
+PerfettoTracingSessionCreate(PerfettoBackendTypes backend);
+
+PERFETTO_SDK_EXPORT void PerfettoTracingSessionSetup(
+    struct PerfettoTracingSessionImpl*,
+    void* cfg_begin,
+    size_t cfg_len);
+
+PERFETTO_SDK_EXPORT void PerfettoTracingSessionStartAsync(
+    struct PerfettoTracingSessionImpl*);
+
+PERFETTO_SDK_EXPORT void PerfettoTracingSessionStartBlocking(
+    struct PerfettoTracingSessionImpl*);
+
+PERFETTO_SDK_EXPORT void PerfettoTracingSessionStopAsync(
+    struct PerfettoTracingSessionImpl*);
+
+PERFETTO_SDK_EXPORT void PerfettoTracingSessionStopBlocking(
+    struct PerfettoTracingSessionImpl*);
+
+// Called back to read pieces of tracing data. `data` points to a chunk of trace
+// data, `size` bytes long. `has_more` is true if there is more tracing data and
+// the callback will be invoked again.
+typedef void (*PerfettoTracingSessionReadCb)(struct PerfettoTracingSessionImpl*,
+                                             const void* data,
+                                             size_t size,
+                                             bool has_more,
+                                             void* user_arg);
+
+// Repeatedly calls cb with data from the tracing session. `user_arg` is passed
+// as is to the callback.
+PERFETTO_SDK_EXPORT void PerfettoTracingSessionReadTraceBlocking(
+    struct PerfettoTracingSessionImpl*,
+    PerfettoTracingSessionReadCb cb,
+    void* user_arg);
+
+PERFETTO_SDK_EXPORT void PerfettoTracingSessionDestroy(
+    struct PerfettoTracingSessionImpl*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // INCLUDE_PERFETTO_PUBLIC_ABI_TRACING_SESSION_ABI_H_
diff --git a/src/shared_lib/BUILD.gn b/src/shared_lib/BUILD.gn
index c653a81..91927df 100644
--- a/src/shared_lib/BUILD.gn
+++ b/src/shared_lib/BUILD.gn
@@ -26,6 +26,7 @@
     "producer.cc",
     "stream_writer.cc",
     "stream_writer.h",
+    "tracing_session.cc",
   ]
   defines = [ "PERFETTO_SHLIB_SDK_IMPLEMENTATION" ]
 }
diff --git a/src/shared_lib/tracing_session.cc b/src/shared_lib/tracing_session.cc
new file mode 100644
index 0000000..313a88d
--- /dev/null
+++ b/src/shared_lib/tracing_session.cc
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2022 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 "perfetto/public/abi/tracing_session_abi.h"
+
+#include <condition_variable>
+#include <mutex>
+
+#include "perfetto/tracing/backend_type.h"
+#include "perfetto/tracing/tracing.h"
+#include "protos/perfetto/config/trace_config.gen.h"
+
+struct PerfettoTracingSessionImpl* PerfettoTracingSessionCreate(
+    PerfettoBackendTypes backend) {
+  uint32_t backend_type = 0;
+  if (backend & PERFETTO_BACKEND_IN_PROCESS) {
+    backend_type |= perfetto::kInProcessBackend;
+  }
+  if (backend & PERFETTO_BACKEND_SYSTEM) {
+    backend_type |= perfetto::kSystemBackend;
+  }
+  std::unique_ptr<perfetto::TracingSession> tracing_session =
+      perfetto::Tracing::NewTrace(
+          static_cast<perfetto::BackendType>(backend_type));
+  return reinterpret_cast<struct PerfettoTracingSessionImpl*>(
+      tracing_session.release());
+}
+
+void PerfettoTracingSessionSetup(struct PerfettoTracingSessionImpl* session,
+                                 void* cfg_begin,
+                                 size_t cfg_len) {
+  auto* ts = reinterpret_cast<perfetto::TracingSession*>(session);
+  perfetto::TraceConfig cfg;
+  cfg.ParseFromArray(cfg_begin, cfg_len);
+  ts->Setup(cfg);
+}
+
+void PerfettoTracingSessionStartAsync(
+    struct PerfettoTracingSessionImpl* session) {
+  auto* ts = reinterpret_cast<perfetto::TracingSession*>(session);
+  ts->Start();
+}
+
+void PerfettoTracingSessionStartBlocking(
+    struct PerfettoTracingSessionImpl* session) {
+  auto* ts = reinterpret_cast<perfetto::TracingSession*>(session);
+  ts->StartBlocking();
+}
+
+void PerfettoTracingSessionStopAsync(
+    struct PerfettoTracingSessionImpl* session) {
+  auto* ts = reinterpret_cast<perfetto::TracingSession*>(session);
+  ts->Stop();
+}
+
+void PerfettoTracingSessionStopBlocking(
+    struct PerfettoTracingSessionImpl* session) {
+  auto* ts = reinterpret_cast<perfetto::TracingSession*>(session);
+  ts->StopBlocking();
+}
+
+void PerfettoTracingSessionReadTraceBlocking(
+    struct PerfettoTracingSessionImpl* session,
+    PerfettoTracingSessionReadCb callback,
+    void* user_arg) {
+  auto* ts = reinterpret_cast<perfetto::TracingSession*>(session);
+
+  std::mutex mutex;
+  std::condition_variable cv;
+
+  bool all_read = false;
+
+  ts->ReadTrace([&mutex, &all_read, &cv, session, callback, user_arg](
+                    perfetto::TracingSession::ReadTraceCallbackArgs args) {
+    callback(session, static_cast<const void*>(args.data), args.size,
+             args.has_more, user_arg);
+    std::unique_lock<std::mutex> lock(mutex);
+    all_read = !args.has_more;
+    if (all_read)
+      cv.notify_one();
+  });
+
+  {
+    std::unique_lock<std::mutex> lock(mutex);
+    cv.wait(lock, [&all_read] { return all_read; });
+  }
+}
+
+void PerfettoTracingSessionDestroy(struct PerfettoTracingSessionImpl* session) {
+  auto* ts = reinterpret_cast<perfetto::TracingSession*>(session);
+  delete ts;
+}