Loading libs/tracing_perfetto/Android.bp +5 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ cc_library_shared { srcs: [ "tracing_perfetto.cpp", "tracing_perfetto_internal.cpp", "tracing_sdk.cpp", ], shared_libs: [ Loading @@ -45,6 +46,10 @@ cc_library_shared { "libperfetto_c", ], export_shared_lib_headers: [ "libperfetto_c", ], host_supported: true, // for vndbinder vendor_available: true, Loading libs/tracing_perfetto/include/tracing_sdk.h 0 → 100644 +461 −0 Original line number Diff line number Diff line /* * 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 libs/tracing_perfetto/tests/Android.bp +32 −1 Original line number Diff line number Diff line Loading @@ -21,12 +21,44 @@ package { 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", Loading @@ -42,7 +74,6 @@ cc_test { ], srcs: [ "tracing_perfetto_test.cpp", "utils.cpp", ], test_suites: ["device-tests"], } libs/tracing_perfetto/tests/include/utils.h 0 → 100644 +124 −0 Original line number Diff line number Diff line /* * 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 libs/tracing_perfetto/tests/tracing_perfetto_test.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -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" Loading Loading
libs/tracing_perfetto/Android.bp +5 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ cc_library_shared { srcs: [ "tracing_perfetto.cpp", "tracing_perfetto_internal.cpp", "tracing_sdk.cpp", ], shared_libs: [ Loading @@ -45,6 +46,10 @@ cc_library_shared { "libperfetto_c", ], export_shared_lib_headers: [ "libperfetto_c", ], host_supported: true, // for vndbinder vendor_available: true, Loading
libs/tracing_perfetto/include/tracing_sdk.h 0 → 100644 +461 −0 Original line number Diff line number Diff line /* * 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
libs/tracing_perfetto/tests/Android.bp +32 −1 Original line number Diff line number Diff line Loading @@ -21,12 +21,44 @@ package { 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", Loading @@ -42,7 +74,6 @@ cc_test { ], srcs: [ "tracing_perfetto_test.cpp", "utils.cpp", ], test_suites: ["device-tests"], }
libs/tracing_perfetto/tests/include/utils.h 0 → 100644 +124 −0 Original line number Diff line number Diff line /* * 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
libs/tracing_perfetto/tests/tracing_perfetto_test.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -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" Loading