blob: 4fe677b231fcfda53d3ee5931332307d4fe462d1 [file] [log] [blame]
Igor Murashkin4cf89842020-02-20 13:27:43 -08001// Copyright (C) 2020 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "perfetto/perfetto_consumer.h"
16
Igor Murashkin70401f42020-03-04 13:57:12 -080017#include "common/trace.h"
18
Igor Murashkin4cf89842020-02-20 13:27:43 -080019#include <android-base/logging.h>
Igor Murashkinca25a5e2020-02-21 11:55:52 -080020#include <android-base/properties.h>
21#include <utils/Looper.h>
Igor Murashkin8c556192020-02-20 17:17:19 -080022#include <utils/Printer.h>
Igor Murashkin4cf89842020-02-20 13:27:43 -080023
Igor Murashkinca25a5e2020-02-21 11:55:52 -080024#include <limits>
Igor Murashkin4cf89842020-02-20 13:27:43 -080025#include <map>
26#include <memory>
Igor Murashkin8c556192020-02-20 17:17:19 -080027#include <mutex>
28#include <sstream>
Igor Murashkin4cf89842020-02-20 13:27:43 -080029#include <vector>
30
Igor Murashkin8c556192020-02-20 17:17:19 -080031#include <inttypes.h>
Igor Murashkin4cf89842020-02-20 13:27:43 -080032#include <time.h>
33
34namespace iorap::perfetto {
35
36using State = PerfettoConsumer::State;
37using Handle = PerfettoConsumer::Handle;
38static constexpr Handle kInvalidHandle = PerfettoConsumer::kInvalidHandle;
39using OnStateChangedCb = PerfettoConsumer::OnStateChangedCb;
40using TraceBuffer = PerfettoConsumer::TraceBuffer;
41
42enum class StateKind {
43 kUncreated,
44 kCreated,
45 kStartedTracing,
46 kReadTracing,
47 kTimedOutDestroyed, // same as kDestroyed but timed out.
48 kDestroyed, // calling kDestroyed before timing out.
49};
50
51std::ostream& operator<<(std::ostream& os, StateKind kind) {
52 switch (kind) {
53 case StateKind::kUncreated:
54 os << "kUncreated";
55 break;
56 case StateKind::kCreated:
57 os << "kCreated";
58 break;
59 case StateKind::kStartedTracing:
60 os << "kStartedTracing";
61 break;
62 case StateKind::kReadTracing:
63 os << "kReadTracing";
64 break;
65 case StateKind::kTimedOutDestroyed:
66 os << "kTimedOutDestroyed";
67 break;
68 case StateKind::kDestroyed:
69 os << "kDestroyed";
70 break;
71 default:
72 os << "(invalid)";
73 break;
74 }
75 return os;
76}
77
Igor Murashkin8c556192020-02-20 17:17:19 -080078std::string ToString(StateKind kind) {
79 std::stringstream ss;
80 ss << kind;
81 return ss.str();
82}
83
Igor Murashkinca25a5e2020-02-21 11:55:52 -080084static constexpr uint64_t kSecToNano = 1000000000LL;
85
Igor Murashkin4cf89842020-02-20 13:27:43 -080086static uint64_t GetTimeNanoseconds() {
87 struct timespec now;
88 clock_gettime(CLOCK_REALTIME, &now);
89
Igor Murashkinca25a5e2020-02-21 11:55:52 -080090 uint64_t now_ns = (now.tv_sec * kSecToNano + now.tv_nsec);
Igor Murashkin4cf89842020-02-20 13:27:43 -080091 return now_ns;
92}
93
94// Describe the state of our handle in detail for debugging/logging.
95struct HandleDescription {
96 Handle handle_;
George Burgess IVb054c282020-02-21 14:25:28 -080097 StateKind kind_{StateKind::kUncreated}; // Our state. required for correctness.
98 OnStateChangedCb callback_{nullptr}; // Required for Destroy callbacks.
99 void* callback_arg_{nullptr};
Igor Murashkin4cf89842020-02-20 13:27:43 -0800100
101 // For dumping to logs:
George Burgess IVb054c282020-02-21 14:25:28 -0800102 State state_{State::kSessionNotFound}; // perfetto state
Igor Murashkin4cf89842020-02-20 13:27:43 -0800103 std::optional<uint64_t> started_tracing_ns_; // when StartedTracing last called.
Igor Murashkin70401f42020-03-04 13:57:12 -0800104 std::optional<uint64_t> read_trace_ns_; // When ReadTrace last called.
George Burgess IVb054c282020-02-21 14:25:28 -0800105 std::uint64_t last_transition_ns_{0};
Igor Murashkin70401f42020-03-04 13:57:12 -0800106 std::optional<uint64_t> trace_cookie_; // atrace beginning at StartTracing.
107 bool trace_ended_{false}; // atrace ending at ReadTrace or Destroy.
George Burgess IVb054c282020-02-21 14:25:28 -0800108
109 HandleDescription(Handle handle): handle_(handle) {}
Igor Murashkin4cf89842020-02-20 13:27:43 -0800110};
111
112// pimpl idiom to hide the implementation details from header
113//
114// Track and verify that our perfetto usage is sane.
115struct PerfettoConsumerImpl::Impl {
Igor Murashkinca25a5e2020-02-21 11:55:52 -0800116 Impl() : raw_{new PerfettoConsumerRawImpl{}},
117 message_handler_{new TraceMessageHandler{this}} {
118 std::thread watchdog_thread{ [this]() {
119 ::android::sp<::android::Looper> looper;
120 {
121 std::lock_guard<std::mutex> guard{looper_mutex_};
122 looper = ::android::Looper::prepare(/*opts*/0);
123 looper_ = looper;
124 }
125
126 static constexpr int kTimeoutMillis = std::numeric_limits<int>::max();
127
128 while (true) {
129 // Execute any pending callbacks, otherwise just block forever.
130 int result = looper->pollAll(kTimeoutMillis);
131
132 if (result == ::android::Looper::POLL_ERROR) {
133 LOG(ERROR) << "PerfettoConsumerImpl::Looper got a POLL_ERROR";
134 } else {
135 LOG(DEBUG) << "PerfettoConsumerImpl::Looper result was " << result;
136 }
137 }
138 }};
139
140 // Let thread run freely on its own.
141 watchdog_thread.detach();
142
143 // Block until looper_ is prepared.
144 while (true) {
145 std::lock_guard<std::mutex> guard{looper_mutex_};
146 if (looper_ != nullptr) {
147 break;
148 }
149 }
Igor Murashkin4cf89842020-02-20 13:27:43 -0800150 }
151
152 private:
153 std::unique_ptr<PerfettoConsumerRawImpl> raw_;
154 std::map<Handle, HandleDescription> states_;
155
156 // We need this to be a counter to avoid memory leaks.
157 Handle last_created_{0};
158 Handle last_destroyed_{0};
Igor Murashkin70401f42020-03-04 13:57:12 -0800159 uint64_t trace_cookie_{0};
Igor Murashkin4cf89842020-02-20 13:27:43 -0800160
Igor Murashkinca25a5e2020-02-21 11:55:52 -0800161 std::mutex mutex_; // Guard above values.
162
163 ::android::sp<::android::Looper> looper_;
164 std::mutex looper_mutex_; // Guard looper_.
165
166 struct TraceMessageHandler : public ::android::MessageHandler {
167 TraceMessageHandler(Impl* impl) : impl_{impl} {
168 CHECK(impl != nullptr);
169 }
170
171 Impl* impl_;
172
173 virtual void handleMessage(const ::android::Message& message) override {
174 impl_->OnTraceMessage(static_cast<Handle>(message.what));
175 }
176 };
177
178 ::android::sp<TraceMessageHandler> message_handler_;
Igor Murashkin8c556192020-02-20 17:17:19 -0800179
Igor Murashkin4cf89842020-02-20 13:27:43 -0800180 public:
181 Handle Create(const void* config_proto,
182 size_t config_len,
183 OnStateChangedCb callback,
184 void* callback_arg) {
185 LOG(VERBOSE) << "PerfettoConsumer::Create("
186 << "config_len=" << config_len << ")";
187 Handle handle = raw_->Create(config_proto, config_len, callback, callback_arg);
188
Igor Murashkin8c556192020-02-20 17:17:19 -0800189 std::lock_guard<std::mutex> guard{mutex_};
190
Igor Murashkin4cf89842020-02-20 13:27:43 -0800191 // Assume every Handle starts at 0 and then increments by 1 every Create.
192 ++last_created_;
193 CHECK_EQ(last_created_, handle) << "perfetto handle had unexpected behavior.";
194 // Without this^ increment-by-1 behavior our detection of untracked state values is broken.
195 // If we have to, we can go with Untracked=Uncreated|Destroyed but it's better to distinguish
196 // the two if possible.
197
George Burgess IVb054c282020-02-21 14:25:28 -0800198 HandleDescription handle_desc{handle};
Igor Murashkin4cf89842020-02-20 13:27:43 -0800199 handle_desc.handle_ = handle;
Igor Murashkinca25a5e2020-02-21 11:55:52 -0800200 handle_desc.callback_ = callback;
201 handle_desc.callback_arg_ = callback_arg;
Igor Murashkin4cf89842020-02-20 13:27:43 -0800202 UpdateHandleDescription(/*inout*/&handle_desc, StateKind::kCreated);
203
204 // assume we never wrap around due to using int64
George Burgess IVb054c282020-02-21 14:25:28 -0800205 bool inserted = states_.insert({handle, handle_desc}).second;
206 CHECK(inserted) << "perfetto handle was re-used: " << handle;
Igor Murashkin4cf89842020-02-20 13:27:43 -0800207
208 return handle;
209 }
210
211 void StartTracing(Handle handle) {
212 LOG(DEBUG) << "PerfettoConsumer::StartTracing(handle=" << handle << ")";
Igor Murashkin8c556192020-02-20 17:17:19 -0800213
Igor Murashkin70401f42020-03-04 13:57:12 -0800214 uint64_t trace_cookie;
Igor Murashkinca25a5e2020-02-21 11:55:52 -0800215 {
216 std::lock_guard<std::mutex> guard{mutex_};
Igor Murashkin8c556192020-02-20 17:17:19 -0800217
Igor Murashkinca25a5e2020-02-21 11:55:52 -0800218 auto it = states_.find(handle);
219 if (it == states_.end()) {
220 LOG(ERROR) << "Cannot StartTracing(" << handle << "), untracked handle";
221 return;
222 }
223 HandleDescription& handle_desc = it->second;
224
225 raw_->StartTracing(handle);
226 UpdateHandleDescription(/*inout*/&handle_desc, StateKind::kStartedTracing);
Igor Murashkin4cf89842020-02-20 13:27:43 -0800227 }
Igor Murashkin4cf89842020-02-20 13:27:43 -0800228
Igor Murashkinca25a5e2020-02-21 11:55:52 -0800229 // Use a looper here to add a timeout and immediately destroy the trace buffer.
230 CHECK_LE(static_cast<int64_t>(handle), static_cast<int64_t>(std::numeric_limits<int>::max()));
231 int message_code = static_cast<int>(handle);
232 ::android::Message message{message_code};
Igor Murashkin4cf89842020-02-20 13:27:43 -0800233
Igor Murashkinca25a5e2020-02-21 11:55:52 -0800234 std::lock_guard<std::mutex> looper_guard{looper_mutex_};
235 looper_->sendMessageDelayed(static_cast<nsecs_t>(GetPropertyTraceTimeoutNs()),
236 message_handler_,
237 message);
Igor Murashkin4cf89842020-02-20 13:27:43 -0800238 }
239
240 TraceBuffer ReadTrace(Handle handle) {
241 LOG(DEBUG) << "PerfettoConsumer::ReadTrace(handle=" << handle << ")";
Igor Murashkin8c556192020-02-20 17:17:19 -0800242
243 std::lock_guard<std::mutex> guard{mutex_};
244
Igor Murashkin4cf89842020-02-20 13:27:43 -0800245 auto it = states_.find(handle);
246 if (it == states_.end()) {
247 LOG(ERROR) << "Cannot ReadTrace(" << handle << "), untracked handle";
248 return TraceBuffer{};
249 }
250
251 HandleDescription& handle_desc = it->second;
252
253 TraceBuffer trace_buffer = raw_->ReadTrace(handle);
254 UpdateHandleDescription(/*inout*/&handle_desc, StateKind::kReadTracing);
255
256 return trace_buffer;
257 }
258
259 void Destroy(Handle handle) {
George Burgess IVb054c282020-02-21 14:25:28 -0800260 HandleDescription handle_desc{handle};
Igor Murashkinca25a5e2020-02-21 11:55:52 -0800261 TryDestroy(handle, /*do_destroy*/true, /*out*/&handle_desc);;
262 }
263
264 bool TryDestroy(Handle handle, bool do_destroy, /*out*/HandleDescription* handle_desc_out) {
265 CHECK(handle_desc_out != nullptr);
266
Igor Murashkin4cf89842020-02-20 13:27:43 -0800267 LOG(VERBOSE) << "PerfettoConsumer::Destroy(handle=" << handle << ")";
Igor Murashkin8c556192020-02-20 17:17:19 -0800268
269 std::lock_guard<std::mutex> guard{mutex_};
270
Igor Murashkin4cf89842020-02-20 13:27:43 -0800271 auto it = states_.find(handle);
272 if (it == states_.end()) {
273 // Leniency for calling Destroy multiple times. It's not a mistake.
274 LOG(ERROR) << "Cannot Destroy(" << handle << "), untracked handle";
Igor Murashkinca25a5e2020-02-21 11:55:52 -0800275 return false;
Igor Murashkin4cf89842020-02-20 13:27:43 -0800276 }
277
278 HandleDescription& handle_desc = it->second;
279
Igor Murashkinca25a5e2020-02-21 11:55:52 -0800280 if (do_destroy) {
281 raw_->Destroy(handle);
282 }
Igor Murashkin4cf89842020-02-20 13:27:43 -0800283 UpdateHandleDescription(/*inout*/&handle_desc, StateKind::kDestroyed);
284
Igor Murashkinca25a5e2020-02-21 11:55:52 -0800285 *handle_desc_out = handle_desc;
286
Igor Murashkin4cf89842020-02-20 13:27:43 -0800287 // No longer track this handle to avoid memory leaks.
288 last_destroyed_ = handle;
289 states_.erase(it);
Igor Murashkinca25a5e2020-02-21 11:55:52 -0800290
291 return true;
Igor Murashkin4cf89842020-02-20 13:27:43 -0800292 }
293
294 State PollState(Handle handle) {
295 // Just pass-through the call, we never use it directly anyway.
296 return raw_->PollState(handle);
297 }
298
299 // Either fetch or infer the current handle state from a handle.
300 // Meant for debugging/logging only.
301 HandleDescription GetOrInferHandleDescription(Handle handle) {
Igor Murashkin8c556192020-02-20 17:17:19 -0800302 std::lock_guard<std::mutex> guard{mutex_};
303
Igor Murashkin4cf89842020-02-20 13:27:43 -0800304 auto it = states_.find(handle);
305 if (it == states_.end()) {
George Burgess IVb054c282020-02-21 14:25:28 -0800306 HandleDescription state{handle};
Igor Murashkin4cf89842020-02-20 13:27:43 -0800307 // If it's untracked it hasn't been created yet, or it was already destroyed.
308 if (IsDestroyed(handle)) {
309 UpdateHandleDescription(/*inout*/&state, StateKind::kDestroyed);
310 } else {
311 if (!IsUncreated(handle)) {
312 LOG(WARNING) << "bad state detection";
313 }
Igor Murashkinca25a5e2020-02-21 11:55:52 -0800314 UpdateHandleDescription(/*inout*/&state, StateKind::kUncreated);
Igor Murashkin4cf89842020-02-20 13:27:43 -0800315 }
316 return state;
317 }
318 return it->second;
319 }
320
Igor Murashkinca25a5e2020-02-21 11:55:52 -0800321 void OnTraceMessage(Handle handle) {
322 LOG(VERBOSE) << "OnTraceMessage(" << static_cast<int64_t>(handle) << ")";
George Burgess IVb054c282020-02-21 14:25:28 -0800323 HandleDescription handle_desc{handle};
Igor Murashkinca25a5e2020-02-21 11:55:52 -0800324 {
325 std::lock_guard<std::mutex> guard{mutex_};
326
327 auto it = states_.find(handle);
328 if (it == states_.end()) {
329 // Handle values are never re-used, so we can simply ignore the message here
330 // instead of having to remove it from the message queue.
331 LOG(VERBOSE) << "OnTraceMessage(" << static_cast<int64_t>(handle)
332 << ") no longer tracked handle";
333 return;
334 }
335 handle_desc = it->second;
336 }
337
338 // First check. Has this trace been active for too long?
339 uint64_t now_ns = GetTimeNanoseconds();
340 if (handle_desc.kind_ == StateKind::kStartedTracing) {
341 // Ignore other kinds of traces because they don't exhaust perfetto resources.
342 CHECK(handle_desc.started_tracing_ns_.has_value()) << static_cast<int64_t>(handle);
343
344 uint64_t started_tracing_ns = *handle_desc.started_tracing_ns_;
345
346 if ((now_ns - started_tracing_ns) > GetPropertyTraceTimeoutNs()) {
347 LOG(WARNING) << "Perfetto Handle timed out after " << (now_ns - started_tracing_ns) << "ns"
348 << ", forcibly destroying";
349
350 // Let the callback handler call Destroy.
351 handle_desc.callback_(handle, State::kTraceFailed, handle_desc.callback_arg_);
352 }
353 }
354
355 // Second check. Are there too many traces now? Cull the old traces.
356 std::vector<HandleDescription> handle_list;
357 do {
358 std::lock_guard<std::mutex> guard{mutex_};
359
360 size_t max_trace_count = GetPropertyMaxTraceCount();
361 if (states_.size() > max_trace_count) {
362 size_t overflow_count = states_.size() - max_trace_count;
363 LOG(WARNING) << "Too many perfetto handles, overflowed by " << overflow_count
364 << ", pruning down to " << max_trace_count;
365 } else {
366 break;
367 }
368
369 size_t prune_count = states_.size() - max_trace_count;
370 auto it = states_.begin();
371 for (size_t i = 0; i < prune_count; ++i) {
372 // Simply prune by handle 1,2,3,4...
373 // We could do better with a timestamp if we wanted to.
374 ++it;
375 handle_list.push_back(it->second);
376 }
377 } while (false);
378
379 for (HandleDescription& handle_desc : handle_list) {
380 LOG(DEBUG) << "Perfetto handle pruned: " << static_cast<int64_t>(handle);
381
382 // Let the callback handler call Destroy.
383 handle_desc.callback_(handle, State::kTraceFailed, handle_desc.callback_arg_);
384 }
385 }
386
Igor Murashkin4cf89842020-02-20 13:27:43 -0800387 private:
Igor Murashkinca25a5e2020-02-21 11:55:52 -0800388 static uint64_t GetPropertyTraceTimeoutNs() {
389 static uint64_t value = // property is timeout in seconds
390 ::android::base::GetUintProperty<uint64_t>("iorapd.perfetto.timeout", /*default*/10);
391 return value * kSecToNano;
392 }
393
394 static size_t GetPropertyMaxTraceCount() {
395 static size_t value =
396 ::android::base::GetUintProperty<size_t>("iorapd.perfetto.max_traces", /*default*/5);
397 return value;
398 }
399
Igor Murashkin4cf89842020-02-20 13:27:43 -0800400 void UpdateHandleDescription(/*inout*/HandleDescription* handle_desc, StateKind kind) {
401 CHECK(handle_desc != nullptr);
402 handle_desc->kind_ = kind;
403 handle_desc->state_ = raw_->PollState(handle_desc->handle_);
404
405 handle_desc->last_transition_ns_ = GetTimeNanoseconds();
406 if (kind == StateKind::kStartedTracing) {
Igor Murashkin70401f42020-03-04 13:57:12 -0800407 if (!handle_desc->started_tracing_ns_) {
408 handle_desc->started_tracing_ns_ = handle_desc->last_transition_ns_;
409
410 handle_desc->trace_cookie_ = ++trace_cookie_;
411
412 atrace_async_begin(ATRACE_TAG_ACTIVITY_MANAGER,
413 "Perfetto Scoped Trace",
414 *handle_desc->trace_cookie_);
415 atrace_int(ATRACE_TAG_ACTIVITY_MANAGER,
416 "Perfetto::Trace Handle",
417 static_cast<int32_t>(handle_desc->handle_));
418 }
419 }
420
421 if (kind == StateKind::kReadTracing) {
422 if (!handle_desc->read_trace_ns_) {
423 handle_desc->read_trace_ns_ = handle_desc->last_transition_ns_;
424
Igor Murashkine399ac42020-03-10 11:05:21 -0700425 if (handle_desc->trace_cookie_.has_value() && !handle_desc->trace_ended_) {
426 atrace_async_end(ATRACE_TAG_ACTIVITY_MANAGER,
427 "Perfetto Scoped Trace",
428 handle_desc->trace_cookie_.value());
Igor Murashkin70401f42020-03-04 13:57:12 -0800429
Igor Murashkine399ac42020-03-10 11:05:21 -0700430 handle_desc->trace_ended_ = true;
431 }
Igor Murashkin70401f42020-03-04 13:57:12 -0800432 }
433 }
434
435 // If Destroy is called prior to ReadTrace, mark the atrace as finished.
Igor Murashkine399ac42020-03-10 11:05:21 -0700436 if (kind == StateKind::kDestroyed && handle_desc->trace_cookie_ && !handle_desc->trace_ended_) {
Igor Murashkin70401f42020-03-04 13:57:12 -0800437 atrace_async_end(ATRACE_TAG_ACTIVITY_MANAGER,
438 "Perfetto Scoped Trace",
439 *handle_desc->trace_cookie_);
440 handle_desc->trace_ended_ = true;
Igor Murashkin4cf89842020-02-20 13:27:43 -0800441 }
442 }
443
444 // The following state detection is for debugging only.
445 // We figure out if something is destroyed, uncreated, or live.
446
447 // Does not distinguish between kTimedOutDestroyed and kDestroyed.
448 bool IsDestroyed(Handle handle) const {
449 auto it = states_.find(handle);
450 if (it != states_.end()) {
451 // Tracked values are not destroyed yet.
452 return false;
453 }
454
455 if (handle == kInvalidHandle) {
456 return false;
457 }
458
459 // The following assumes handles are incrementally generated:
460 if (it == states_.end()) {
461 // value is in range of [0, last_destroyed] => destroyed.
462 return handle <= last_destroyed_;
463 }
464
465 auto min_it = states_.begin();
466 if (handle < min_it->first) {
467 // value smaller than anything tracked: it was destroyed and we stopped tracking it.
468 return true;
469 }
470
471 auto max_it = states_.rbegin();
472 if (handle > max_it->first) {
473 // value too big: it's uncreated;
474 return false;
475 }
476
477 // else it was a value that was previously tracked within [min,max] but no longer
478 return true;
479 }
480
481 bool IsUncreated(Handle handle) const {
482 auto it = states_.find(handle);
483 if (it != states_.end()) {
484 // Tracked values are not uncreated.
485 return false;
486 }
487
488 if (handle == kInvalidHandle) {
489 // Strangely enough, an invalid handle can never be created.
490 return true;
491 }
492
493 // The following assumes handles are incrementally generated:
494 if (it == states_.end()) {
495 // value is in range of (last_destroyed, inf) => uncreated.
496 return handle > last_destroyed_;
497 }
498
499 auto min_it = states_.begin();
500 if (handle < min_it->first) {
501 // value smaller than anything tracked: it was destroyed and we stopped tracking it.
502 return false;
503 }
504
505 auto max_it = states_.rbegin();
506 if (handle > max_it->first) {
507 // value too big: it's uncreated;
508 return true;
509 }
510
511 // else it was a value that was previously tracked within [min,max] but no longer
512 return false;
513 }
514
515 public:
Igor Murashkin8c556192020-02-20 17:17:19 -0800516 void Dump(::android::Printer& printer) {
517 // Locking can fail if we dump during a deadlock, so just do a best-effort lock here.
518 bool is_it_locked = mutex_.try_lock();
519
520 printer.printFormatLine("Perfetto consumer state:");
Igor Murashkinca25a5e2020-02-21 11:55:52 -0800521 if (!is_it_locked) {
522 printer.printLine(""""" (possible deadlock)");
523 }
Igor Murashkin8c556192020-02-20 17:17:19 -0800524 printer.printFormatLine(" Last destroyed handle: %" PRId64, last_destroyed_);
525 printer.printFormatLine(" Last created handle: %" PRId64, last_created_);
526 printer.printFormatLine("");
527 printer.printFormatLine(" In-flight handles:");
528
529 for (auto it = states_.begin(); it != states_.end(); ++it) {
530 HandleDescription& handle_desc = it->second;
531 uint64_t started_tracing =
532 handle_desc.started_tracing_ns_ ? *handle_desc.started_tracing_ns_ : 0;
533 printer.printFormatLine(" Handle %" PRId64, handle_desc.handle_);
534 printer.printFormatLine(" Kind: %s", ToString(handle_desc.kind_).c_str());
535 printer.printFormatLine(" Perfetto State: %d", static_cast<int>(handle_desc.state_));
536 printer.printFormatLine(" Started tracing at: %" PRIu64, started_tracing);
537 printer.printFormatLine(" Last transition at: %" PRIu64,
538 handle_desc.last_transition_ns_);
539 }
540 if (states_.empty()) {
541 printer.printFormatLine(" (None)");
542 }
543
544 printer.printFormatLine("");
545
546 if (is_it_locked) { // u.b. if calling unlock on an unlocked mutex.
547 mutex_.unlock();
548 }
549 }
550
Igor Murashkin4cf89842020-02-20 13:27:43 -0800551 static PerfettoConsumerImpl::Impl* GetImplSingleton() {
552 static PerfettoConsumerImpl::Impl impl;
553 return &impl;
554 }
555};
556
557// Use a singleton because fruit instantiates a new PerfettoConsumer object for every
558// new rx chain in RxProducerFactory. However, we want to track all perfetto transitions globally
559// through 1 impl object.
560//
561// TODO: Avoiding a singleton would mean a more significant refactoring to remove the fruit/perfetto
562// usage.
563
564
565//
566// Forward all calls to PerfettoConsumerImpl::Impl
567//
568
569PerfettoConsumerImpl::~PerfettoConsumerImpl() {
570 // delete impl_; // TODO: no singleton
571}
572
573void PerfettoConsumerImpl::Initialize() {
574 // impl_ = new PerfettoConsumerImpl::Impl(); // TODO: no singleton
575 impl_ = PerfettoConsumerImpl::Impl::GetImplSingleton();
576}
577
Igor Murashkin8c556192020-02-20 17:17:19 -0800578void PerfettoConsumerImpl::Dump(::android::Printer& printer) {
579 PerfettoConsumerImpl::Impl::GetImplSingleton()->Dump(/*borrow*/printer);
580}
581
Igor Murashkin4cf89842020-02-20 13:27:43 -0800582PerfettoConsumer::Handle PerfettoConsumerImpl::Create(const void* config_proto,
583 size_t config_len,
584 PerfettoConsumer::OnStateChangedCb callback,
585 void* callback_arg) {
586 return impl_->Create(config_proto,
587 config_len,
588 callback,
589 callback_arg);
590}
591
592void PerfettoConsumerImpl::StartTracing(PerfettoConsumer::Handle handle) {
593 impl_->StartTracing(handle);
594}
595
596PerfettoConsumer::TraceBuffer PerfettoConsumerImpl::ReadTrace(PerfettoConsumer::Handle handle) {
597 return impl_->ReadTrace(handle);
598}
599
600void PerfettoConsumerImpl::Destroy(PerfettoConsumer::Handle handle) {
601 impl_->Destroy(handle);
602}
603
604PerfettoConsumer::State PerfettoConsumerImpl::PollState(PerfettoConsumer::Handle handle) {
605 return impl_->PollState(handle);
606}
607
608} // namespace iorap::perfetto