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(®istered_track_, name_.data(),
200 parent_uuid_);
201 } else {
202 PerfettoTeNamedTrackRegister(®istered_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(®istered_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