• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 #pragma once
18 
19 #include <android-base/logging.h>
20 #include <stdint.h>
21 
22 #include <optional>
23 #include <vector>
24 
25 #include "perfetto/public/producer.h"
26 #include "perfetto/public/te_category_macros.h"
27 #include "perfetto/public/te_macros.h"
28 #include "perfetto/public/track_event.h"
29 
30 #include "perfetto/public/abi/pb_decoder_abi.h"
31 #include "perfetto/public/pb_utils.h"
32 #include "perfetto/public/tracing_session.h"
33 
34 /**
35  * The objects declared here are intended to be managed by Java.
36  * This means the Java Garbage Collector is responsible for freeing the
37  * underlying native resources.
38  *
39  * The static methods prefixed with `delete_` are special. They are designed to be
40  * invoked by Java through the `NativeAllocationRegistry` when the
41  * corresponding Java object becomes unreachable.  These methods act as
42  * callbacks to ensure proper deallocation of native resources.
43  */
44 namespace tracing_perfetto {
45 /**
46  * @brief Represents extra data associated with a trace event.
47  * This class manages a collection of PerfettoTeHlExtra pointers.
48  */
49 class Extra;
50 
51 /**
52  * @brief Emits a trace event.
53  * @param type The type of the event.
54  * @param cat The category of the event.
55  * @param name The name of the event.
56  * @param arg_ptr Pointer to Extra data.
57  */
58 void trace_event(int type, const PerfettoTeCategory* cat, const char* name,
59                  Extra* extra);
60 
61 /**
62  * @brief Gets the process track UUID.
63  */
64 uint64_t get_process_track_uuid();
65 
66 /**
67  * @brief Gets the thread track UUID for a given PID.
68  */
69 uint64_t get_thread_track_uuid(pid_t tid);
70 
71 /**
72  * @brief Holder for all the other classes in the file.
73  */
74 class Extra {
75  public:
76   Extra();
77   void push_extra(PerfettoTeHlExtra* extra);
78   void pop_extra();
79   void clear_extras();
80   static void delete_extra(Extra* extra);
81 
82   PerfettoTeHlExtra* const* get() const;
83 
84  private:
85   DISALLOW_COPY_AND_ASSIGN(Extra);
86 
87   // These PerfettoTeHlExtra pointers are really pointers to all the other
88   // types of extras: Category, DebugArg, Counter etc. Those objects are
89   // individually managed by Java.
90   std::vector<PerfettoTeHlExtra*> extras_;
91 };
92 
93 /**
94  * @brief Represents a trace event category.
95  */
96 class Category {
97  public:
98   Category(const std::string& name, const std::string& tag,
99            const std::string& severity);
100 
101   ~Category();
102 
103   void register_category();
104 
105   void unregister_category();
106 
107   bool is_category_enabled();
108 
109   static void delete_category(Category* category);
110 
111   const PerfettoTeCategory* get() const;
112 
113  private:
114   DISALLOW_COPY_AND_ASSIGN(Category);
115   PerfettoTeCategory category_;
116   const std::string name_;
117   const std::string tag_;
118   const std::string severity_;
119 };
120 
121 /**
122  * @brief Represents one end of a flow between two events.
123  */
124 class Flow {
125  public:
126   Flow();
127 
128   void set_process_flow(uint64_t id);
129   void set_process_terminating_flow(uint64_t id);
130   static void delete_flow(Flow* flow);
131 
132   const PerfettoTeHlExtraFlow* get() const;
133 
134  private:
135   DISALLOW_COPY_AND_ASSIGN(Flow);
136   PerfettoTeHlExtraFlow flow_;
137 };
138 
139 /**
140  * @brief Represents a named track.
141  */
142 class NamedTrack {
143  public:
144   NamedTrack(uint64_t id, uint64_t parent_uuid, const std::string& name);
145 
146   static void delete_track(NamedTrack* track);
147 
148   const PerfettoTeHlExtraNamedTrack* get() const;
149 
150  private:
151   DISALLOW_COPY_AND_ASSIGN(NamedTrack);
152   const std::string name_;
153   PerfettoTeHlExtraNamedTrack track_;
154 };
155 
156 /**
157  * @brief Represents a registered track.
158  */
159 class RegisteredTrack {
160  public:
161   RegisteredTrack(uint64_t id, uint64_t parent_uuid, const std::string& name,
162                   bool is_counter);
163   ~RegisteredTrack();
164 
165   void register_track();
166   void unregister_track();
167   static void delete_track(RegisteredTrack* track);
168 
169   const PerfettoTeHlExtraRegisteredTrack* get() const;
170 
171  private:
172   DISALLOW_COPY_AND_ASSIGN(RegisteredTrack);
173   PerfettoTeRegisteredTrack registered_track_;
174   PerfettoTeHlExtraRegisteredTrack track_;
175   const std::string name_;
176   const uint64_t id_;
177   const uint64_t parent_uuid_;
178   const bool is_counter_;
179 };
180 
181 /**
182  * @brief Represents a counter track event.
183  * @tparam T The data type of the counter (int64_t or double).
184  */
185 template <typename T>
186 class Counter {
187  public:
188   template <typename>
189   struct always_false : std::false_type {};
190 
191   struct TypeMap {
192     using type = std::invoke_result_t<decltype([]() {
193       if constexpr (std::is_same_v<T, int64_t>) {
194         return std::type_identity<PerfettoTeHlExtraCounterInt64>{};
195       } else if constexpr (std::is_same_v<T, double>) {
196         return std::type_identity<PerfettoTeHlExtraCounterDouble>{};
197       } else {
198         return std::type_identity<void>{};
199       }
200     })>::type;
201 
202     static constexpr int enum_value = []() {
203       if constexpr (std::is_same_v<T, int64_t>) {
204         return PERFETTO_TE_HL_EXTRA_TYPE_COUNTER_INT64;
205       } else if constexpr (std::is_same_v<T, double>) {
206         return PERFETTO_TE_HL_EXTRA_TYPE_COUNTER_DOUBLE;
207       } else {
208         static_assert(always_false<T>::value, "Unsupported type");
209         return 0;  // Never reached, just to satisfy return type
210       }
211     }();
212   };
213 
Counter()214   Counter() {
215     static_assert(!std::is_same_v<typename TypeMap::type, void>,
216                   "Unsupported type for Counter");
217 
218     typename TypeMap::type counter;
219     counter.header = {TypeMap::enum_value};
220     counter_ = std::move(counter);
221   }
222 
set_value(T value)223   void set_value(T value) {
224     if constexpr (std::is_same_v<T, int64_t>) {
225       counter_.value = value;
226     } else if constexpr (std::is_same_v<T, double>) {
227       counter_.value = value;
228     }
229   }
230 
delete_counter(Counter * counter)231   static void delete_counter(Counter* counter) {
232     delete counter;
233   }
234 
get()235   const TypeMap::type* get() const {
236     return &counter_;
237   }
238 
239  private:
240   DISALLOW_COPY_AND_ASSIGN(Counter);
241   TypeMap::type counter_;
242 };
243 
244 /**
245  * @brief Represents a debug argument for a trace event.
246  * @tparam T The data type of the argument (bool, int64_t, double, const char*).
247  */
248 template <typename T>
249 class DebugArg {
250  public:
251   template <typename>
252   struct always_false : std::false_type {};
253 
254   struct TypeMap {
255     using type = std::invoke_result_t<decltype([]() {
256       if constexpr (std::is_same_v<T, bool>) {
257         return std::type_identity<PerfettoTeHlExtraDebugArgBool>{};
258       } else if constexpr (std::is_same_v<T, int64_t>) {
259         return std::type_identity<PerfettoTeHlExtraDebugArgInt64>{};
260       } else if constexpr (std::is_same_v<T, double>) {
261         return std::type_identity<PerfettoTeHlExtraDebugArgDouble>{};
262       } else if constexpr (std::is_same_v<T, const char*>) {
263         return std::type_identity<PerfettoTeHlExtraDebugArgString>{};
264       } else {
265         return std::type_identity<void>{};
266       }
267     })>::type;
268 
269     static constexpr int enum_value = []() {
270       if constexpr (std::is_same_v<T, bool>) {
271         return PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_BOOL;
272       } else if constexpr (std::is_same_v<T, int64_t>) {
273         return PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_INT64;
274       } else if constexpr (std::is_same_v<T, double>) {
275         return PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_DOUBLE;
276       } else if constexpr (std::is_same_v<T, const char*>) {
277         return PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_STRING;
278       } else {
279         static_assert(always_false<T>::value, "Unsupported type");
280         return 0;  // Never reached, just to satisfy return type
281       }
282     }();
283   };
284 
DebugArg(const std::string & name)285   DebugArg(const std::string& name) : name_(name) {
286     static_assert(!std::is_same_v<typename TypeMap::type, void>,
287                   "Unsupported type for DebugArg");
288 
289     typename TypeMap::type arg;
290     arg.header = {TypeMap::enum_value};
291     arg.name = name_.c_str();
292     arg_ = std::move(arg);
293   }
294 
set_value(T value)295   void set_value(T value) {
296     if constexpr (std::is_same_v<T, const char*>) {
297       arg_.value = value;
298     } else if constexpr (std::is_same_v<T, int64_t>) {
299       arg_.value = value;
300     } else if constexpr (std::is_same_v<T, bool>) {
301       arg_.value = value;
302     } else if constexpr (std::is_same_v<T, double>) {
303       arg_.value = value;
304     }
305   }
306 
delete_arg(DebugArg * arg)307   static void delete_arg(DebugArg* arg) {
308     delete arg;
309   }
310 
get()311   const TypeMap::type* get() const {
312     return &arg_;
313   }
314 
315  private:
316   DISALLOW_COPY_AND_ASSIGN(DebugArg);
317   TypeMap::type arg_;
318   const std::string name_;
319 };
320 
321 template <typename T>
322 class ProtoField {
323  public:
324   template <typename>
325   struct always_false : std::false_type {};
326 
327   struct TypeMap {
328     using type = std::invoke_result_t<decltype([]() {
329       if constexpr (std::is_same_v<T, int64_t>) {
330         return std::type_identity<PerfettoTeHlProtoFieldVarInt>{};
331       } else if constexpr (std::is_same_v<T, double>) {
332         return std::type_identity<PerfettoTeHlProtoFieldDouble>{};
333       } else if constexpr (std::is_same_v<T, const char*>) {
334         return std::type_identity<PerfettoTeHlProtoFieldCstr>{};
335       } else {
336         return std::type_identity<void>{};
337       }
338     })>::type;
339 
340     static constexpr PerfettoTeHlProtoFieldType enum_value = []() {
341       if constexpr (std::is_same_v<T, int64_t>) {
342         return PERFETTO_TE_HL_PROTO_TYPE_VARINT;
343       } else if constexpr (std::is_same_v<T, double>) {
344         return PERFETTO_TE_HL_PROTO_TYPE_DOUBLE;
345       } else if constexpr (std::is_same_v<T, const char*>) {
346         return PERFETTO_TE_HL_PROTO_TYPE_CSTR;
347       } else {
348         static_assert(always_false<T>::value, "Unsupported type");
349         return 0;  // Never reached, just to satisfy return type
350       }
351     }();
352   };
353 
ProtoField()354   ProtoField() {
355     static_assert(!std::is_same_v<typename TypeMap::type, void>,
356                   "Unsupported type for ProtoField");
357 
358     typename TypeMap::type arg;
359     arg.header.type = TypeMap::enum_value;
360     arg_ = std::move(arg);
361   }
362 
set_value(uint32_t id,T value)363   void set_value(uint32_t id, T value) {
364     if constexpr (std::is_same_v<T, int64_t>) {
365       arg_.header.id = id;
366       arg_.value = value;
367     } else if constexpr (std::is_same_v<T, double>) {
368       arg_.header.id = id;
369       arg_.value = value;
370     } else if constexpr (std::is_same_v<T, const char*>) {
371       arg_.header.id = id;
372       arg_.str = value;
373     }
374   }
375 
delete_field(ProtoField * field)376   static void delete_field(ProtoField* field) {
377     delete field;
378   }
379 
get()380   const TypeMap::type* get() const {
381     return &arg_;
382   }
383 
384  private:
385   DISALLOW_COPY_AND_ASSIGN(ProtoField);
386   TypeMap::type arg_;
387 };
388 
389 class ProtoFieldNested {
390  public:
391   ProtoFieldNested();
392 
393   void add_field(PerfettoTeHlProtoField* field);
394   void set_id(uint32_t id);
395   static void delete_field(ProtoFieldNested* field);
396 
397   const PerfettoTeHlProtoFieldNested* get() const;
398 
399  private:
400   DISALLOW_COPY_AND_ASSIGN(ProtoFieldNested);
401   PerfettoTeHlProtoFieldNested field_;
402   // These PerfettoTeHlProtoField pointers are really pointers to all the other
403   // types of protos: PerfettoTeHlProtoFieldVarInt, PerfettoTeHlProtoFieldVarInt,
404   // PerfettoTeHlProtoFieldVarInt, PerfettoTeHlProtoFieldNested. Those objects are
405   // individually managed by Java.
406   std::vector<PerfettoTeHlProtoField*> fields_;
407 };
408 
409 class Proto {
410  public:
411   Proto();
412 
413   void add_field(PerfettoTeHlProtoField* field);
414   void clear_fields();
415   static void delete_proto(Proto* proto);
416 
417   const PerfettoTeHlExtraProtoFields* get() const;
418 
419  private:
420   DISALLOW_COPY_AND_ASSIGN(Proto);
421   PerfettoTeHlExtraProtoFields proto_;
422   // These PerfettoTeHlProtoField pointers are really pointers to all the other
423   // types of protos: PerfettoTeHlProtoFieldVarInt, PerfettoTeHlProtoFieldVarInt,
424   // PerfettoTeHlProtoFieldVarInt, PerfettoTeHlProtoFieldNested. Those objects are
425   // individually managed by Java.
426   std::vector<PerfettoTeHlProtoField*> fields_;
427 };
428 
429 class Session {
430  public:
431   Session(bool is_backend_in_process, void* buf, size_t len);
432   ~Session();
433   Session(const Session&) = delete;
434   Session& operator=(const Session&) = delete;
435 
436   bool FlushBlocking(uint32_t timeout_ms);
437   void StopBlocking();
438   std::vector<uint8_t> ReadBlocking();
439 
440   static void delete_session(Session* session);
441 
442   struct PerfettoTracingSessionImpl* session_ = nullptr;
443 };
444 
445 /**
446  * @brief Activates a trigger.
447  * @param name The name of the trigger.
448  * @param ttl_ms The time-to-live of the trigger in milliseconds.
449  */
450 void activate_trigger(const char* name, uint32_t ttl_ms);
451 }  // namespace tracing_perfetto
452