1 /* 2 * Copyright (C) 2025 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef SRC_ANDROID_SDK_PERFETTO_SDK_FOR_JNI_TRACING_SDK_H_ 18 #define SRC_ANDROID_SDK_PERFETTO_SDK_FOR_JNI_TRACING_SDK_H_ 19 20 #include <stdint.h> 21 22 #include <optional> 23 #include <string> 24 #include <vector> 25 26 #include "perfetto/ext/base/sys_types.h" // for pid_t 27 #include "perfetto/public/tracing_session.h" 28 #include "perfetto/public/track_event.h" 29 30 // Macro copied from 31 // https://source.corp.google.com/h/googleplex-android/platform/superproject/main/+/main:system/libbase/include/android-base/macros.h;l=45;drc=bd641075ad60ed703baf59f63a9153d96d96b98e 32 // A macro to disallow the copy constructor and operator= functions 33 // This must be placed in the private: declarations for a class. 34 // 35 // For disallowing only assign or copy, delete the relevant operator or 36 // constructor, for example: 37 // void operator=(const TypeName&) = delete; 38 // Note, that most uses of DISALLOW_ASSIGN and DISALLOW_COPY are broken 39 // semantically, one should either use disallow both or neither. Try to 40 // avoid these in new code. 41 #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ 42 TypeName(const TypeName&) = delete; \ 43 void operator=(const TypeName&) = delete 44 45 /** 46 * The objects declared here are intended to be managed by Java. 47 * This means the Java Garbage Collector is responsible for freeing the 48 * underlying native resources. 49 * 50 * The static methods prefixed with `delete_` are special. They are designed to 51 * be invoked by Java through the `NativeAllocationRegistry` when the 52 * corresponding Java object becomes unreachable. These methods act as 53 * callbacks to ensure proper deallocation of native resources. 54 */ 55 namespace perfetto { 56 namespace sdk_for_jni { 57 /** 58 * @brief Initializes the global perfetto instance. 59 * @param backend_in_process use in-process or system backend 60 */ 61 void register_perfetto(bool backend_in_process = false); 62 63 /** 64 * @brief Represents extra data associated with a trace event. 65 * This class manages a collection of PerfettoTeHlExtra pointers. 66 */ 67 class Extra; 68 69 /** 70 * @brief Emits a trace event. 71 * @param type The type of the event. 72 * @param cat The category of the event. 73 * @param name The name of the event. 74 * @param extra Pointer to Extra data. 75 */ 76 void trace_event(int type, 77 const PerfettoTeCategory* cat, 78 const char* name, 79 Extra* extra); 80 81 /** 82 * @brief Gets the process track UUID. 83 */ 84 uint64_t get_process_track_uuid(); 85 86 /** 87 * @brief Gets the thread track UUID for a given PID. 88 */ 89 uint64_t get_thread_track_uuid(pid_t tid); 90 91 /** 92 * @brief Holder for all the other classes in the file. 93 */ 94 class Extra { 95 public: 96 Extra(); 97 void push_extra(PerfettoTeHlExtra* extra); 98 void pop_extra(); 99 void clear_extras(); 100 static void delete_extra(Extra* extra); 101 102 PerfettoTeHlExtra* const* get() const; 103 104 private: 105 DISALLOW_COPY_AND_ASSIGN(Extra); 106 107 // These PerfettoTeHlExtra pointers are really pointers to all the other 108 // types of extras: Category, DebugArg, Counter etc. Those objects are 109 // individually managed by Java. 110 std::vector<PerfettoTeHlExtra*> extras_; 111 }; 112 113 /** 114 * @brief Represents a trace event category. 115 */ 116 class Category { 117 public: 118 Category(const std::string& name, 119 const std::string& tag, 120 const std::string& severity); 121 122 ~Category(); 123 124 void register_category(); 125 126 void unregister_category(); 127 128 bool is_category_enabled(); 129 130 static void delete_category(Category* category); 131 132 const PerfettoTeCategory* get() const; 133 134 private: 135 DISALLOW_COPY_AND_ASSIGN(Category); 136 PerfettoTeCategory category_; 137 const std::string name_; 138 const std::string tag_; 139 const std::string severity_; 140 }; 141 142 /** 143 * @brief Represents one end of a flow between two events. 144 */ 145 class Flow { 146 public: 147 Flow(); 148 149 void set_process_flow(uint64_t id); 150 void set_process_terminating_flow(uint64_t id); 151 static void delete_flow(Flow* flow); 152 153 const PerfettoTeHlExtraFlow* get() const; 154 155 private: 156 DISALLOW_COPY_AND_ASSIGN(Flow); 157 PerfettoTeHlExtraFlow flow_; 158 }; 159 160 /** 161 * @brief Represents a named track. 162 */ 163 class NamedTrack { 164 public: 165 NamedTrack(uint64_t id, uint64_t parent_uuid, const std::string& name); 166 167 static void delete_track(NamedTrack* track); 168 169 const PerfettoTeHlExtraNamedTrack* get() const; 170 171 private: 172 DISALLOW_COPY_AND_ASSIGN(NamedTrack); 173 const std::string name_; 174 PerfettoTeHlExtraNamedTrack track_; 175 }; 176 177 /** 178 * @brief Represents a registered track. 179 */ 180 class RegisteredTrack { 181 public: 182 RegisteredTrack(uint64_t id, 183 uint64_t parent_uuid, 184 const std::string& name, 185 bool is_counter); 186 ~RegisteredTrack(); 187 188 void register_track(); 189 void unregister_track(); 190 static void delete_track(RegisteredTrack* track); 191 192 const PerfettoTeHlExtraRegisteredTrack* get() const; 193 194 private: 195 DISALLOW_COPY_AND_ASSIGN(RegisteredTrack); 196 PerfettoTeRegisteredTrack registered_track_; 197 PerfettoTeHlExtraRegisteredTrack track_; 198 const std::string name_; 199 const uint64_t id_; 200 const uint64_t parent_uuid_; 201 const bool is_counter_; 202 }; 203 204 /** 205 * @brief Represents a counter track event. 206 * @tparam T The data type of the counter (int64_t or double). 207 */ 208 template <typename T> 209 class Counter { 210 public: 211 template <typename> 212 struct always_false : std::false_type {}; 213 214 template <class I> 215 struct type_identity { 216 using type = I; 217 }; 218 219 struct TypeMap { 220 template <typename CounterT> get_counter_typeTypeMap221 static constexpr auto get_counter_type() { 222 if constexpr (std::is_same_v<CounterT, int64_t>) { 223 return type_identity<PerfettoTeHlExtraCounterInt64>{}; 224 } else if constexpr (std::is_same_v<CounterT, double>) { 225 return type_identity<PerfettoTeHlExtraCounterDouble>{}; 226 } else { 227 return type_identity<void>{}; 228 } 229 } 230 using type = typename decltype(get_counter_type<T>())::type; 231 232 static constexpr int enum_value = []() { 233 if constexpr (std::is_same_v<T, int64_t>) { 234 return PERFETTO_TE_HL_EXTRA_TYPE_COUNTER_INT64; 235 } else if constexpr (std::is_same_v<T, double>) { 236 return PERFETTO_TE_HL_EXTRA_TYPE_COUNTER_DOUBLE; 237 } else { 238 static_assert(always_false<T>::value, "Unsupported type"); 239 return 0; // Never reached, just to satisfy return type 240 } 241 }(); 242 }; 243 Counter()244 Counter() { 245 static_assert(!std::is_same_v<typename TypeMap::type, void>, 246 "Unsupported type for Counter"); 247 248 typename TypeMap::type counter; 249 counter.header = {TypeMap::enum_value}; 250 counter_ = std::move(counter); 251 } 252 set_value(T value)253 void set_value(T value) { 254 if constexpr (std::is_same_v<T, int64_t>) { 255 counter_.value = value; 256 } else if constexpr (std::is_same_v<T, double>) { 257 counter_.value = value; 258 } 259 } 260 delete_counter(Counter * counter)261 static void delete_counter(Counter* counter) { delete counter; } 262 get()263 const typename TypeMap::type* get() const { return &counter_; } 264 265 private: 266 DISALLOW_COPY_AND_ASSIGN(Counter); 267 typename TypeMap::type counter_; 268 }; 269 270 /** 271 * @brief Represents a debug argument for a trace event. 272 * @tparam T The data type of the argument (bool, int64_t, double, const char*). 273 */ 274 template <typename T> 275 class DebugArg { 276 public: 277 template <typename> 278 struct always_false : std::false_type {}; 279 280 template <class I> 281 struct type_identity { 282 using type = I; 283 }; 284 285 struct TypeMap { 286 template <typename DebugArgT> get_debug_arg_typeTypeMap287 static constexpr auto get_debug_arg_type() { 288 if constexpr (std::is_same_v<DebugArgT, bool>) { 289 return type_identity<PerfettoTeHlExtraDebugArgBool>{}; 290 } else if constexpr (std::is_same_v<DebugArgT, int64_t>) { 291 return type_identity<PerfettoTeHlExtraDebugArgInt64>{}; 292 } else if constexpr (std::is_same_v<DebugArgT, double>) { 293 return type_identity<PerfettoTeHlExtraDebugArgDouble>{}; 294 } else if constexpr (std::is_same_v<DebugArgT, const char*>) { 295 return type_identity<PerfettoTeHlExtraDebugArgString>{}; 296 } else { 297 return type_identity<void>{}; 298 } 299 } 300 using type = typename decltype(get_debug_arg_type<T>())::type; 301 302 static constexpr int enum_value = []() { 303 if constexpr (std::is_same_v<T, bool>) { 304 return PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_BOOL; 305 } else if constexpr (std::is_same_v<T, int64_t>) { 306 return PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_INT64; 307 } else if constexpr (std::is_same_v<T, double>) { 308 return PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_DOUBLE; 309 } else if constexpr (std::is_same_v<T, const char*>) { 310 return PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_STRING; 311 } else { 312 static_assert(always_false<T>::value, "Unsupported type"); 313 return 0; // Never reached, just to satisfy return type 314 } 315 }(); 316 }; 317 DebugArg(const std::string & name)318 DebugArg(const std::string& name) : name_(name) { 319 static_assert(!std::is_same_v<typename TypeMap::type, void>, 320 "Unsupported type for DebugArg"); 321 322 typename TypeMap::type arg; 323 arg.header = {TypeMap::enum_value}; 324 arg.name = name_.c_str(); 325 arg_ = std::move(arg); 326 } 327 set_value(T value)328 void set_value(T value) { 329 if constexpr (std::is_same_v<T, const char*>) { 330 arg_.value = value; 331 } else if constexpr (std::is_same_v<T, int64_t>) { 332 arg_.value = value; 333 } else if constexpr (std::is_same_v<T, bool>) { 334 arg_.value = value; 335 } else if constexpr (std::is_same_v<T, double>) { 336 arg_.value = value; 337 } 338 } 339 delete_arg(DebugArg * arg)340 static void delete_arg(DebugArg* arg) { delete arg; } 341 get()342 const typename TypeMap::type* get() const { return &arg_; } 343 344 private: 345 DISALLOW_COPY_AND_ASSIGN(DebugArg); 346 typename TypeMap::type arg_; 347 const std::string name_; 348 }; 349 350 template <typename T> 351 class ProtoField { 352 public: 353 template <typename> 354 struct always_false : std::false_type {}; 355 356 template <class I> 357 struct type_identity { 358 using type = I; 359 }; 360 361 struct TypeMap { 362 template <typename ProtoT> get_proto_typeTypeMap363 static constexpr auto get_proto_type() { 364 if constexpr (std::is_same_v<ProtoT, int64_t>) { 365 return type_identity<PerfettoTeHlProtoFieldVarInt>{}; 366 } else if constexpr (std::is_same_v<ProtoT, double>) { 367 return type_identity<PerfettoTeHlProtoFieldDouble>{}; 368 } else if constexpr (std::is_same_v<ProtoT, const char*>) { 369 return type_identity<PerfettoTeHlProtoFieldCstr>{}; 370 } else { 371 return type_identity<void>{}; 372 } 373 } 374 using type = typename decltype(get_proto_type<T>())::type; 375 376 static constexpr PerfettoTeHlProtoFieldType enum_value = []() { 377 if constexpr (std::is_same_v<T, int64_t>) { 378 return PERFETTO_TE_HL_PROTO_TYPE_VARINT; 379 } else if constexpr (std::is_same_v<T, double>) { 380 return PERFETTO_TE_HL_PROTO_TYPE_DOUBLE; 381 } else if constexpr (std::is_same_v<T, const char*>) { 382 return PERFETTO_TE_HL_PROTO_TYPE_CSTR; 383 } else { 384 static_assert(always_false<T>::value, "Unsupported type"); 385 return 0; // Never reached, just to satisfy return type 386 } 387 }(); 388 }; 389 ProtoField()390 ProtoField() { 391 static_assert(!std::is_same_v<typename TypeMap::type, void>, 392 "Unsupported type for ProtoField"); 393 394 typename TypeMap::type arg; 395 arg.header.type = TypeMap::enum_value; 396 arg_ = std::move(arg); 397 } 398 set_value(uint32_t id,T value)399 void set_value(uint32_t id, T value) { 400 if constexpr (std::is_same_v<T, int64_t>) { 401 arg_.header.id = id; 402 arg_.value = value; 403 } else if constexpr (std::is_same_v<T, double>) { 404 arg_.header.id = id; 405 arg_.value = value; 406 } else if constexpr (std::is_same_v<T, const char*>) { 407 arg_.header.id = id; 408 arg_.str = value; 409 } 410 } 411 delete_field(ProtoField * field)412 static void delete_field(ProtoField* field) { delete field; } 413 get()414 const typename TypeMap::type* get() const { return &arg_; } 415 416 private: 417 DISALLOW_COPY_AND_ASSIGN(ProtoField); 418 typename TypeMap::type arg_; 419 }; 420 421 class ProtoFieldNested { 422 public: 423 ProtoFieldNested(); 424 425 void add_field(PerfettoTeHlProtoField* field); 426 void set_id(uint32_t id); 427 static void delete_field(ProtoFieldNested* field); 428 429 const PerfettoTeHlProtoFieldNested* get() const; 430 431 private: 432 DISALLOW_COPY_AND_ASSIGN(ProtoFieldNested); 433 PerfettoTeHlProtoFieldNested field_; 434 // These PerfettoTeHlProtoField pointers are really pointers to all the other 435 // types of protos: PerfettoTeHlProtoFieldVarInt, 436 // PerfettoTeHlProtoFieldVarInt, PerfettoTeHlProtoFieldVarInt, 437 // PerfettoTeHlProtoFieldNested. Those objects are individually managed by 438 // Java. 439 std::vector<PerfettoTeHlProtoField*> fields_; 440 }; 441 442 class Proto { 443 public: 444 Proto(); 445 446 void add_field(PerfettoTeHlProtoField* field); 447 void clear_fields(); 448 static void delete_proto(Proto* proto); 449 450 const PerfettoTeHlExtraProtoFields* get() const; 451 452 private: 453 DISALLOW_COPY_AND_ASSIGN(Proto); 454 PerfettoTeHlExtraProtoFields proto_; 455 // These PerfettoTeHlProtoField pointers are really pointers to all the other 456 // types of protos: PerfettoTeHlProtoFieldVarInt, 457 // PerfettoTeHlProtoFieldVarInt, PerfettoTeHlProtoFieldVarInt, 458 // PerfettoTeHlProtoFieldNested. Those objects are individually managed by 459 // Java. 460 std::vector<PerfettoTeHlProtoField*> fields_; 461 }; 462 463 class Session { 464 public: 465 Session(bool is_backend_in_process, void* buf, size_t len); 466 ~Session(); 467 Session(const Session&) = delete; 468 Session& operator=(const Session&) = delete; 469 470 bool FlushBlocking(uint32_t timeout_ms); 471 void StopBlocking(); 472 std::vector<uint8_t> ReadBlocking(); 473 474 static void delete_session(Session* session); 475 476 struct PerfettoTracingSessionImpl* session_ = nullptr; 477 }; 478 479 /** 480 * @brief Activates a trigger. 481 * @param name The name of the trigger. 482 * @param ttl_ms The time-to-live of the trigger in milliseconds. 483 */ 484 void activate_trigger(const char* name, uint32_t ttl_ms); 485 } // namespace sdk_for_jni 486 } // namespace perfetto 487 488 #endif // SRC_ANDROID_SDK_PERFETTO_SDK_FOR_JNI_TRACING_SDK_H_ 489