1 /*
2  * Copyright (C) 2019 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 "perfetto/tracing/tracing.h"
18 
19 #include <atomic>
20 #include <condition_variable>
21 #include <mutex>
22 
23 #include "perfetto/ext/base/waitable_event.h"
24 #include "perfetto/tracing/internal/track_event_internal.h"
25 #include "src/tracing/internal/tracing_muxer_impl.h"
26 
27 namespace perfetto {
28 namespace {
29 bool g_was_initialized = false;
30 }
31 
32 // static
InitializeInternal(const TracingInitArgs & args)33 void Tracing::InitializeInternal(const TracingInitArgs& args) {
34   static TracingInitArgs init_args;
35   if (g_was_initialized) {
36     if (!(init_args == args)) {
37       PERFETTO_ELOG(
38           "Tracing::Initialize() called more than once with different args. "
39           "This is not supported, only the first call will have effect.");
40       PERFETTO_DCHECK(false);
41     }
42     return;
43   }
44 
45   // Make sure the headers and implementation files agree on the build config.
46   PERFETTO_CHECK(args.dcheck_is_on_ == PERFETTO_DCHECK_IS_ON());
47   if (args.log_message_callback) {
48     SetLogMessageCallback(args.log_message_callback);
49   }
50   internal::TracingMuxerImpl::InitializeInstance(args);
51   internal::TrackRegistry::InitializeInstance();
52   g_was_initialized = true;
53   init_args = args;
54 }
55 
56 // static
IsInitialized()57 bool Tracing::IsInitialized() {
58   return g_was_initialized;
59 }
60 
61 //  static
NewTrace(BackendType backend)62 std::unique_ptr<TracingSession> Tracing::NewTrace(BackendType backend) {
63   return static_cast<internal::TracingMuxerImpl*>(internal::TracingMuxer::Get())
64       ->CreateTracingSession(backend);
65 }
66 
67 // Can be called from any thread.
FlushBlocking(uint32_t timeout_ms)68 bool TracingSession::FlushBlocking(uint32_t timeout_ms) {
69   std::atomic<bool> flush_result;
70   base::WaitableEvent flush_ack;
71 
72   // The non blocking Flush() can be called on any thread. It does the PostTask
73   // internally.
74   Flush(
75       [&flush_ack, &flush_result](bool res) {
76         flush_result = res;
77         flush_ack.Notify();
78       },
79       timeout_ms);
80   flush_ack.Wait();
81   return flush_result;
82 }
83 
ReadTraceBlocking()84 std::vector<char> TracingSession::ReadTraceBlocking() {
85   std::vector<char> raw_trace;
86   std::mutex mutex;
87   std::condition_variable cv;
88 
89   bool all_read = false;
90 
91   ReadTrace([&mutex, &raw_trace, &all_read, &cv](ReadTraceCallbackArgs cb) {
92     raw_trace.insert(raw_trace.end(), cb.data, cb.data + cb.size);
93     std::unique_lock<std::mutex> lock(mutex);
94     all_read = !cb.has_more;
95     if (all_read)
96       cv.notify_one();
97   });
98 
99   {
100     std::unique_lock<std::mutex> lock(mutex);
101     cv.wait(lock, [&all_read] { return all_read; });
102   }
103   return raw_trace;
104 }
105 
106 TracingSession::GetTraceStatsCallbackArgs
GetTraceStatsBlocking()107 TracingSession::GetTraceStatsBlocking() {
108   std::mutex mutex;
109   std::condition_variable cv;
110   GetTraceStatsCallbackArgs result;
111   bool stats_read = false;
112 
113   GetTraceStats(
114       [&mutex, &result, &stats_read, &cv](GetTraceStatsCallbackArgs args) {
115         result = std::move(args);
116         std::unique_lock<std::mutex> lock(mutex);
117         stats_read = true;
118         cv.notify_one();
119       });
120 
121   {
122     std::unique_lock<std::mutex> lock(mutex);
123     cv.wait(lock, [&stats_read] { return stats_read; });
124   }
125   return result;
126 }
127 
128 TracingSession::QueryServiceStateCallbackArgs
QueryServiceStateBlocking()129 TracingSession::QueryServiceStateBlocking() {
130   std::mutex mutex;
131   std::condition_variable cv;
132   QueryServiceStateCallbackArgs result;
133   bool status_read = false;
134 
135   QueryServiceState(
136       [&mutex, &result, &status_read, &cv](QueryServiceStateCallbackArgs args) {
137         result = std::move(args);
138         std::unique_lock<std::mutex> lock(mutex);
139         status_read = true;
140         cv.notify_one();
141       });
142 
143   {
144     std::unique_lock<std::mutex> lock(mutex);
145     cv.wait(lock, [&status_read] { return status_read; });
146   }
147   return result;
148 }
149 
150 }  // namespace perfetto
151