• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "src/android_sdk/perfetto_sdk_for_jni/tracing_sdk.h"
18 
19 #include <cstdarg>
20 #include <mutex>
21 
22 #include "perfetto/ext/base/sys_types.h"  // for pid_t
23 #include "perfetto/public/abi/producer_abi.h"
24 #include "perfetto/public/producer.h"
25 #include "perfetto/public/te_macros.h"
26 #include "perfetto/public/track_event.h"
27 
28 namespace perfetto {
29 namespace sdk_for_jni {
register_perfetto(bool backend_in_process)30 void register_perfetto(bool backend_in_process) {
31   static std::once_flag registration;
32   std::call_once(registration, [backend_in_process]() {
33     struct PerfettoProducerInitArgs args = PERFETTO_PRODUCER_INIT_ARGS_INIT();
34     args.backends = backend_in_process ? PERFETTO_BACKEND_IN_PROCESS
35                                        : PERFETTO_BACKEND_SYSTEM;
36     args.shmem_size_hint_kb = 1024;
37     PerfettoProducerInit(args);
38     PerfettoTeInit();
39   });
40 }
41 
trace_event(int type,const PerfettoTeCategory * perfettoTeCategory,const char * name,Extra * extra)42 void trace_event(int type,
43                  const PerfettoTeCategory* perfettoTeCategory,
44                  const char* name,
45                  Extra* extra) {
46   bool enabled = PERFETTO_UNLIKELY(PERFETTO_ATOMIC_LOAD_EXPLICIT(
47       perfettoTeCategory->enabled, PERFETTO_MEMORY_ORDER_RELAXED));
48   if (enabled) {
49     extra->push_extra(nullptr);
50     PerfettoTeHlEmitImpl(perfettoTeCategory->impl, type,
51                          type == PERFETTO_TE_TYPE_COUNTER ? nullptr : name,
52                          extra->get());
53     extra->clear_extras();
54   }
55 }
56 
get_process_track_uuid()57 uint64_t get_process_track_uuid() {
58   return PerfettoTeProcessTrackUuid();
59 }
60 
get_thread_track_uuid(pid_t tid)61 uint64_t get_thread_track_uuid(pid_t tid) {
62   // Cating a signed pid_t to unsigned
63   return PerfettoTeProcessTrackUuid() ^ PERFETTO_STATIC_CAST(uint64_t, tid);
64 }
65 
Extra()66 Extra::Extra() {}
67 
push_extra(PerfettoTeHlExtra * ptr)68 void Extra::push_extra(PerfettoTeHlExtra* ptr) {
69   extras_.push_back(ptr);
70 }
71 
pop_extra()72 void Extra::pop_extra() {
73   extras_.pop_back();
74 }
75 
clear_extras()76 void Extra::clear_extras() {
77   extras_.clear();
78 }
79 
delete_extra(Extra * ptr)80 void Extra::delete_extra(Extra* ptr) {
81   delete ptr;
82 }
83 
get() const84 PerfettoTeHlExtra* const* Extra::get() const {
85   return extras_.data();
86 }
87 
Category(const std::string & name,const std::string & tag,const std::string & severity)88 Category::Category(const std::string& name,
89                    const std::string& tag,
90                    const std::string& severity)
91     : category_({&perfetto_atomic_false, {}, {}, 0}),
92       name_(name),
93       tag_(tag),
94       severity_(severity) {}
95 
~Category()96 Category::~Category() {
97   unregister_category();
98 }
99 
register_category()100 void Category::register_category() {
101   if (category_.impl)
102     return;
103 
104   std::vector<const char*> tags;
105   if (!tag_.empty())
106     tags.push_back(tag_.data());
107   if (!severity_.empty())
108     tags.push_back(severity_.data());
109 
110   category_.desc = {name_.c_str(), name_.c_str(), tags.data(), tags.size()};
111 
112   PerfettoTeCategoryRegister(&category_);
113   PerfettoTePublishCategories();
114 }
115 
unregister_category()116 void Category::unregister_category() {
117   if (!category_.impl)
118     return;
119 
120   PerfettoTeCategoryUnregister(&category_);
121   PerfettoTePublishCategories();
122 }
123 
is_category_enabled()124 bool Category::is_category_enabled() {
125   return PERFETTO_UNLIKELY(PERFETTO_ATOMIC_LOAD_EXPLICIT(
126       (category_).enabled, PERFETTO_MEMORY_ORDER_RELAXED));
127 }
128 
get() const129 const PerfettoTeCategory* Category::get() const {
130   return &category_;
131 }
132 
delete_category(Category * ptr)133 void Category::delete_category(Category* ptr) {
134   delete ptr;
135 }
136 
Flow()137 Flow::Flow() : flow_{} {}
138 
set_process_flow(uint64_t id)139 void Flow::set_process_flow(uint64_t id) {
140   flow_.header.type = PERFETTO_TE_HL_EXTRA_TYPE_FLOW;
141   PerfettoTeFlow ret = PerfettoTeProcessScopedFlow(id);
142   flow_.id = ret.id;
143 }
144 
set_process_terminating_flow(uint64_t id)145 void Flow::set_process_terminating_flow(uint64_t id) {
146   flow_.header.type = PERFETTO_TE_HL_EXTRA_TYPE_TERMINATING_FLOW;
147   PerfettoTeFlow ret = PerfettoTeProcessScopedFlow(id);
148   flow_.id = ret.id;
149 }
150 
get() const151 const PerfettoTeHlExtraFlow* Flow::get() const {
152   return &flow_;
153 }
154 
delete_flow(Flow * ptr)155 void Flow::delete_flow(Flow* ptr) {
156   delete ptr;
157 }
158 
NamedTrack(uint64_t id,uint64_t parent_uuid,const std::string & name)159 NamedTrack::NamedTrack(uint64_t id,
160                        uint64_t parent_uuid,
161                        const std::string& name)
162     : name_(name),
163       track_{{PERFETTO_TE_HL_EXTRA_TYPE_NAMED_TRACK},
164              name_.data(),
165              id,
166              parent_uuid} {}
167 
get() const168 const PerfettoTeHlExtraNamedTrack* NamedTrack::get() const {
169   return &track_;
170 }
171 
delete_track(NamedTrack * ptr)172 void NamedTrack::delete_track(NamedTrack* ptr) {
173   delete ptr;
174 }
175 
RegisteredTrack(uint64_t id,uint64_t parent_uuid,const std::string & name,bool is_counter)176 RegisteredTrack::RegisteredTrack(uint64_t id,
177                                  uint64_t parent_uuid,
178                                  const std::string& name,
179                                  bool is_counter)
180     : registered_track_{},
181       track_{{PERFETTO_TE_HL_EXTRA_TYPE_REGISTERED_TRACK},
182              &(registered_track_.impl)},
183       name_(name),
184       id_(id),
185       parent_uuid_(parent_uuid),
186       is_counter_(is_counter) {
187   register_track();
188 }
189 
~RegisteredTrack()190 RegisteredTrack::~RegisteredTrack() {
191   unregister_track();
192 }
193 
register_track()194 void RegisteredTrack::register_track() {
195   if (registered_track_.impl.descriptor)
196     return;
197 
198   if (is_counter_) {
199     PerfettoTeCounterTrackRegister(&registered_track_, name_.data(),
200                                    parent_uuid_);
201   } else {
202     PerfettoTeNamedTrackRegister(&registered_track_, name_.data(), id_,
203                                  parent_uuid_);
204   }
205 }
206 
unregister_track()207 void RegisteredTrack::unregister_track() {
208   if (!registered_track_.impl.descriptor)
209     return;
210   PerfettoTeRegisteredTrackUnregister(&registered_track_);
211 }
212 
get() const213 const PerfettoTeHlExtraRegisteredTrack* RegisteredTrack::get() const {
214   return &track_;
215 }
216 
delete_track(RegisteredTrack * ptr)217 void RegisteredTrack::delete_track(RegisteredTrack* ptr) {
218   delete ptr;
219 }
220 
Proto()221 Proto::Proto() : proto_({{PERFETTO_TE_HL_EXTRA_TYPE_PROTO_FIELDS}, nullptr}) {}
222 
add_field(PerfettoTeHlProtoField * ptr)223 void Proto::add_field(PerfettoTeHlProtoField* ptr) {
224   if (!fields_.empty()) {
225     fields_.pop_back();
226   }
227 
228   fields_.push_back(ptr);
229   fields_.push_back(nullptr);
230   proto_.fields = fields_.data();
231 }
232 
clear_fields()233 void Proto::clear_fields() {
234   fields_.clear();
235   proto_.fields = nullptr;
236 }
237 
delete_proto(Proto * ptr)238 void Proto::delete_proto(Proto* ptr) {
239   delete ptr;
240 }
241 
get() const242 const PerfettoTeHlExtraProtoFields* Proto::get() const {
243   return &proto_;
244 }
245 
ProtoFieldNested()246 ProtoFieldNested::ProtoFieldNested()
247     : field_({{PERFETTO_TE_HL_PROTO_TYPE_NESTED, 0}, nullptr}) {}
248 
add_field(PerfettoTeHlProtoField * ptr)249 void ProtoFieldNested::add_field(PerfettoTeHlProtoField* ptr) {
250   if (!fields_.empty()) {
251     fields_.pop_back();
252   }
253 
254   fields_.push_back(ptr);
255   fields_.push_back(nullptr);
256   field_.fields = fields_.data();
257 }
258 
set_id(uint32_t id)259 void ProtoFieldNested::set_id(uint32_t id) {
260   fields_.clear();
261   field_.header.id = id;
262   field_.fields = nullptr;
263 }
264 
delete_field(ProtoFieldNested * ptr)265 void ProtoFieldNested::delete_field(ProtoFieldNested* ptr) {
266   delete ptr;
267 }
268 
get() const269 const PerfettoTeHlProtoFieldNested* ProtoFieldNested::get() const {
270   return &field_;
271 }
272 
Session(bool is_backend_in_process,void * buf,size_t len)273 Session::Session(bool is_backend_in_process, void* buf, size_t len) {
274   session_ = PerfettoTracingSessionCreate(is_backend_in_process
275                                               ? PERFETTO_BACKEND_IN_PROCESS
276                                               : PERFETTO_BACKEND_SYSTEM);
277 
278   PerfettoTracingSessionSetup(session_, buf, len);
279 
280   PerfettoTracingSessionStartBlocking(session_);
281 }
282 
~Session()283 Session::~Session() {
284   PerfettoTracingSessionStopBlocking(session_);
285   PerfettoTracingSessionDestroy(session_);
286 }
287 
FlushBlocking(uint32_t timeout_ms)288 bool Session::FlushBlocking(uint32_t timeout_ms) {
289   return PerfettoTracingSessionFlushBlocking(session_, timeout_ms);
290 }
291 
StopBlocking()292 void Session::StopBlocking() {
293   PerfettoTracingSessionStopBlocking(session_);
294 }
295 
ReadBlocking()296 std::vector<uint8_t> Session::ReadBlocking() {
297   std::vector<uint8_t> data;
298   PerfettoTracingSessionReadTraceBlocking(
299       session_,
300       [](struct PerfettoTracingSessionImpl*, const void* trace_data,
301          size_t size, bool, void* user_arg) {
302         auto& dst = *static_cast<std::vector<uint8_t>*>(user_arg);
303         auto* src = static_cast<const uint8_t*>(trace_data);
304         dst.insert(dst.end(), src, src + size);
305       },
306       &data);
307   return data;
308 }
309 
delete_session(Session * ptr)310 void Session::delete_session(Session* ptr) {
311   delete ptr;
312 }
313 
activate_trigger(const char * name,uint32_t ttl_ms)314 void activate_trigger(const char* name, uint32_t ttl_ms) {
315   const char* names[] = {name, nullptr};
316   PerfettoProducerActivateTriggers(names, ttl_ms);
317 }
318 }  // namespace sdk_for_jni
319 }  // namespace perfetto
320