OLD | NEW |
---|---|
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/tracing/arc_tracing_agent.h" | 5 #include "content/browser/tracing/arc_tracing_agent.h" |
6 | 6 |
7 #include <string.h> | |
8 #include <sys/socket.h> | |
9 | |
10 #include <memory> | |
7 #include <string> | 11 #include <string> |
12 #include <utility> | |
8 | 13 |
9 #include "base/bind.h" | 14 #include "base/bind.h" |
15 #include "base/files/file.h" | |
16 #include "base/files/file_descriptor_watcher_posix.h" | |
10 #include "base/logging.h" | 17 #include "base/logging.h" |
11 #include "base/memory/singleton.h" | 18 #include "base/memory/singleton.h" |
12 #include "base/threading/thread_checker.h" | 19 #include "base/memory/weak_ptr.h" |
20 #include "base/threading/sequenced_task_runner_handle.h" | |
13 #include "base/threading/thread_task_runner_handle.h" | 21 #include "base/threading/thread_task_runner_handle.h" |
22 #include "base/time/time.h" | |
23 #include "base/trace_event/trace_buffer.h" | |
24 #include "content/public/browser/browser_thread.h" | |
25 | |
26 using base::trace_event::TraceEvent; | |
27 using base::trace_event::TraceBuffer; | |
28 using base::trace_event::TraceBufferChunk; | |
14 | 29 |
15 namespace content { | 30 namespace content { |
16 | 31 |
17 namespace { | 32 namespace { |
18 | 33 |
34 constexpr int kArcTraceMessageLength = 1024 + 512; | |
Luis Héctor Chávez
2017/03/22 17:04:58
nit: size_t
shunhsingou
2017/03/28 13:54:15
Done.
| |
19 constexpr char kArcTracingAgentName[] = "arc"; | 35 constexpr char kArcTracingAgentName[] = "arc"; |
20 constexpr char kArcTraceLabel[] = "ArcTraceEvents"; | 36 constexpr char kArcTraceLabel[] = "ArcTraceEvents"; |
21 | 37 |
22 void OnStopTracing(bool success) { | 38 // Number of chunks for the ring buffer. |
23 DLOG_IF(WARNING, !success) << "Failed to stop ARC tracing."; | 39 constexpr int kTraceEventChunks = |
Luis Héctor Chávez
2017/03/22 17:04:57
nit: size_t
shunhsingou
2017/03/28 13:54:14
Done.
| |
40 64000 / TraceBufferChunk::kTraceBufferChunkSize; | |
41 | |
42 bool CreateSocketPair(base::ScopedFD* one, base::ScopedFD* two) { | |
Luis Héctor Chávez
2017/03/22 17:04:57
I see that you copied this from base/posix/unix_do
shunhsingou
2017/03/28 13:54:14
Done.
| |
43 int raw_socks[2]; | |
44 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, raw_socks) == -1) | |
45 return false; | |
46 one->reset(raw_socks[0]); | |
47 two->reset(raw_socks[1]); | |
48 return true; | |
24 } | 49 } |
25 | 50 |
26 class ArcTracingAgentImpl : public ArcTracingAgent { | 51 class ArcTracingAgentImpl : public ArcTracingAgent { |
27 public: | 52 public: |
28 // base::trace_event::TracingAgent overrides: | 53 // base::trace_event::TracingAgent overrides: |
29 std::string GetTracingAgentName() override { return kArcTracingAgentName; } | 54 std::string GetTracingAgentName() override { return kArcTracingAgentName; } |
30 | 55 |
31 std::string GetTraceEventLabel() override { return kArcTraceLabel; } | 56 std::string GetTraceEventLabel() override { return kArcTraceLabel; } |
32 | 57 |
33 void StartAgentTracing(const base::trace_event::TraceConfig& trace_config, | 58 void StartAgentTracing(const base::trace_event::TraceConfig& trace_config, |
34 const StartAgentTracingCallback& callback) override { | 59 const StartAgentTracingCallback& callback) override { |
35 DCHECK(thread_checker_.CalledOnValidThread()); | 60 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
36 // delegate_ may be nullptr if ARC is not enabled on the system. In such | 61 // delegate_ may be nullptr if ARC is not enabled on the system. In such |
37 // case, simply do nothing. | 62 // case, simply do nothing. |
38 if (!delegate_) { | 63 if (!delegate_) { |
39 // Use PostTask as the convention of TracingAgent. The caller expects | 64 // Use PostTask as the convention of TracingAgent. The caller expects |
40 // callback to be called after this function returns. | 65 // callback to be called after this function returns. |
41 base::ThreadTaskRunnerHandle::Get()->PostTask( | 66 base::ThreadTaskRunnerHandle::Get()->PostTask( |
42 FROM_HERE, base::Bind(callback, GetTracingAgentName(), false)); | 67 FROM_HERE, base::Bind(callback, GetTracingAgentName(), false)); |
43 return; | 68 return; |
44 } | 69 } |
45 | 70 base::ScopedFD write_fd, read_fd; |
46 delegate_->StartTracing(trace_config, | 71 CreateSocketPair(&read_fd, &write_fd); |
Luis Héctor Chávez
2017/03/22 17:04:58
Make this fail if CreateSocketPair() returns false
shunhsingou
2017/03/28 13:54:15
Done.
| |
72 data_file_.reset(new base::File(read_fd.release())); | |
Luis Héctor Chávez
2017/03/22 17:04:57
nit: data_file_ = base::MakeUnique<base::File>(rea
shunhsingou
2017/03/28 13:54:14
This data member is removed.
| |
73 CreateBuffer(); | |
74 BrowserThread::PostTask( | |
75 BrowserThread::IO, FROM_HERE, | |
76 base::Bind(&ArcTracingAgentImpl::InitFileDescriptorWatcher, | |
77 weak_ptr_factory_.GetWeakPtr(), | |
78 data_file_->GetPlatformFile())); | |
79 delegate_->StartTracing(trace_config, std::move(write_fd), | |
47 base::Bind(callback, GetTracingAgentName())); | 80 base::Bind(callback, GetTracingAgentName())); |
48 } | 81 } |
49 | 82 |
50 void StopAgentTracing(const StopAgentTracingCallback& callback) override { | 83 void StopAgentTracing(const StopAgentTracingCallback& callback) override { |
51 DCHECK(thread_checker_.CalledOnValidThread()); | 84 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
85 | |
86 if (!callback_.is_null()) { | |
87 DLOG(WARNING) << "Already working on stopping ArcTracingAgent."; | |
88 return; | |
89 } | |
90 callback_ = callback; | |
Luis Héctor Chávez
2017/03/22 17:04:57
You don't need to do this. You can instead do
del
shunhsingou
2017/03/28 13:54:14
Done. My original thought is that we still need an
| |
52 if (delegate_) | 91 if (delegate_) |
Luis Héctor Chávez
2017/03/22 17:04:58
nit: you cannot elide braces since the body spans
shunhsingou
2017/03/28 13:54:15
Done.
| |
53 delegate_->StopTracing(base::Bind(OnStopTracing)); | 92 delegate_->StopTracing( |
54 | 93 base::Bind(&ArcTracingAgentImpl::OnArcTracingStopped, |
55 // Trace data is collect via systrace (debugd) in dev-mode. Simply | 94 weak_ptr_factory_.GetWeakPtr())); |
56 // return empty data here. | |
57 std::string no_data; | |
58 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
59 FROM_HERE, | |
60 base::Bind(callback, GetTracingAgentName(), GetTraceEventLabel(), | |
61 base::RefCountedString::TakeString(&no_data))); | |
62 } | 95 } |
63 | 96 |
64 // ArcTracingAgent overrides: | 97 // ArcTracingAgent overrides: |
65 void SetDelegate(Delegate* delegate) override { | 98 void SetDelegate(Delegate* delegate) override { |
66 DCHECK(thread_checker_.CalledOnValidThread()); | 99 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
67 delegate_ = delegate; | 100 delegate_ = delegate; |
68 } | 101 } |
69 | 102 |
70 static ArcTracingAgentImpl* GetInstance() { | 103 static ArcTracingAgentImpl* GetInstance() { |
71 return base::Singleton<ArcTracingAgentImpl>::get(); | 104 return base::Singleton<ArcTracingAgentImpl>::get(); |
72 } | 105 } |
73 | 106 |
74 private: | 107 private: |
75 // This allows constructor and destructor to be private and usable only | 108 // This allows constructor and destructor to be private and usable only |
76 // by the Singleton class. | 109 // by the Singleton class. |
77 friend struct base::DefaultSingletonTraits<ArcTracingAgentImpl>; | 110 friend struct base::DefaultSingletonTraits<ArcTracingAgentImpl>; |
78 | 111 |
79 ArcTracingAgentImpl() = default; | 112 ArcTracingAgentImpl() : weak_ptr_factory_(this) {} |
113 | |
80 ~ArcTracingAgentImpl() override = default; | 114 ~ArcTracingAgentImpl() override = default; |
81 | 115 |
116 void CreateBuffer() { | |
117 trace_buffer_.reset( | |
118 TraceBuffer::CreateTraceBufferRingBuffer(kTraceEventChunks)); | |
119 chunk_.reset(nullptr); | |
Luis Héctor Chávez
2017/03/22 17:04:58
nit: chunk_.reset();
shunhsingou
2017/03/28 13:54:14
Done.
| |
120 chunk_index_ = 0; | |
121 } | |
122 | |
123 void OnTraceDataAvailable() { | |
Luis Héctor Chávez
2017/03/22 17:04:58
Can you move all the buffer-related stuff to anoth
shunhsingou
2017/03/28 13:54:14
Done.
| |
124 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
125 char buf[kArcTraceMessageLength + 1]; | |
126 int n = | |
127 data_file_->ReadAtCurrentPosNoBestEffort(buf, kArcTraceMessageLength); | |
Luis Héctor Chávez
2017/03/22 17:04:58
I'm a bit worried that we might need to use recv()
shunhsingou
2017/03/28 13:54:14
Done.
| |
128 if (n == 0) | |
Luis Héctor Chávez
2017/03/22 17:04:58
What about errors?
shunhsingou
2017/03/28 13:54:15
Done.
| |
129 return; | |
130 | |
131 buf[n] = 0; | |
132 char* data = new char[n + 1]; | |
Luis Héctor Chávez
2017/03/22 17:04:57
you're leaking this :(
shunhsingou
2017/03/28 13:54:14
Done. It's now free in StopTracing.
| |
133 memcpy(data, buf, n + 1); | |
Luis Héctor Chávez
2017/03/22 18:23:04
You need to add
if (n > kArcTraceMessageLength) {
shunhsingou
2017/03/28 13:54:14
Done.
| |
134 | |
135 // Save data into trace buffer. | |
136 if (!chunk_) | |
137 chunk_ = trace_buffer_->GetChunk(&chunk_index_); | |
138 size_t event_index; | |
139 TraceEvent* event = chunk_->AddTraceEvent(&event_index); | |
140 | |
141 // Here we don't actually parse the data, which should already be a valid | |
Luis Héctor Chávez
2017/03/22 17:04:57
This is a dangerous assumption :( What happens if
shunhsingou
2017/03/28 13:54:15
Done add a validation check here.
| |
142 // trace JSON object. We only use |TraceEvent| for saving data in | |
143 // |TraceBuffer| and |TraceBufferChunk|. So we can just put everything in | |
144 // |name|, and only fetch the |name| field after finishing tracing to | |
145 // avoid unnecessary deserialize and serialize from/to JSON. | |
146 event->Initialize(0, base::TimeTicks(), base::ThreadTicks(), 0, nullptr, | |
147 data, nullptr, 0, 0, 0, nullptr, nullptr, nullptr, | |
148 nullptr, 0); | |
149 | |
150 if (chunk_->IsFull()) { | |
151 trace_buffer_->ReturnChunk(chunk_index_, std::move(chunk_)); | |
152 chunk_ = trace_buffer_->GetChunk(&chunk_index_); | |
153 } | |
154 } | |
155 | |
156 void InitFileDescriptorWatcher(int fd) { | |
157 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
158 fd_watcher_ = base::FileDescriptorWatcher::WatchReadable( | |
159 fd, base::Bind(&ArcTracingAgentImpl::OnTraceDataAvailable, | |
160 weak_ptr_factory_.GetWeakPtr())); | |
161 } | |
162 | |
163 void OnArcTracingStopped(bool success) { | |
164 if (!success) { | |
165 DLOG(WARNING) << "Failed to stop ARC tracing."; | |
166 std::string no_data; | |
167 base::ResetAndReturn(&callback_) | |
168 .Run(GetTracingAgentName(), GetTraceEventLabel(), | |
169 base::RefCountedString::TakeString(&no_data)); | |
170 return; | |
171 } | |
172 BrowserThread::PostTask( | |
173 BrowserThread::IO, FROM_HERE, | |
174 base::Bind(&ArcTracingAgentImpl::StopTracingInIOThread, | |
175 weak_ptr_factory_.GetWeakPtr())); | |
176 } | |
177 | |
178 void StopTracingInIOThread() { | |
179 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
180 close(read_fd_.release()); | |
Luis Héctor Chávez
2017/03/22 18:09:34
nit: read_fd_.reset();
shunhsingou
2017/03/28 13:54:15
Done.
| |
181 // Stop fd_watcher_. | |
182 fd_watcher_.reset(nullptr); | |
Luis Héctor Chávez
2017/03/22 18:09:34
nit: fd_watcher_.reset();
shunhsingou
2017/03/28 13:54:14
Done.
| |
183 if (chunk_) | |
184 trace_buffer_->ReturnChunk(chunk_index_, std::move(chunk_)); | |
185 | |
186 bool append_comma = false; | |
187 std::string data; | |
188 while (const TraceBufferChunk* chunk = trace_buffer_->NextChunk()) { | |
189 for (size_t i = 0; i < chunk->size(); ++i) { | |
190 const TraceEvent* event = chunk->GetEventAt(i); | |
191 if (append_comma) | |
192 data.append(","); | |
193 // See comment in |OnTraceDataAvailable|. We put the whole valid JSON | |
194 // object in |name|. | |
195 data.append(event->name()); | |
196 append_comma = true; | |
197 } | |
198 } | |
199 base::ResetAndReturn(&callback_) | |
200 .Run(GetTracingAgentName(), GetTraceEventLabel(), | |
201 base::RefCountedString::TakeString(&data)); | |
202 } | |
203 | |
82 Delegate* delegate_ = nullptr; // Owned by ArcServiceLauncher. | 204 Delegate* delegate_ = nullptr; // Owned by ArcServiceLauncher. |
83 base::ThreadChecker thread_checker_; | 205 base::ScopedFD read_fd_; |
206 std::unique_ptr<base::File> data_file_; | |
207 std::unique_ptr<base::FileDescriptorWatcher::Controller> fd_watcher_; | |
208 std::unique_ptr<TraceBuffer> trace_buffer_; | |
209 std::unique_ptr<TraceBufferChunk> chunk_; | |
210 size_t chunk_index_; | |
211 StopAgentTracingCallback callback_; | |
212 | |
213 // NOTE: Weak pointers must be invalidated before all other member variables | |
214 // so it must be the last member. | |
215 base::WeakPtrFactory<ArcTracingAgentImpl> weak_ptr_factory_; | |
84 | 216 |
85 DISALLOW_COPY_AND_ASSIGN(ArcTracingAgentImpl); | 217 DISALLOW_COPY_AND_ASSIGN(ArcTracingAgentImpl); |
86 }; | 218 }; |
87 | 219 |
88 } // namespace | 220 } // namespace |
89 | 221 |
90 // static | 222 // static |
91 ArcTracingAgent* ArcTracingAgent::GetInstance() { | 223 ArcTracingAgent* ArcTracingAgent::GetInstance() { |
92 return ArcTracingAgentImpl::GetInstance(); | 224 return ArcTracingAgentImpl::GetInstance(); |
93 } | 225 } |
94 | 226 |
95 ArcTracingAgent::ArcTracingAgent() = default; | 227 ArcTracingAgent::ArcTracingAgent() = default; |
96 ArcTracingAgent::~ArcTracingAgent() = default; | 228 ArcTracingAgent::~ArcTracingAgent() = default; |
97 | 229 |
98 ArcTracingAgent::Delegate::~Delegate() = default; | 230 ArcTracingAgent::Delegate::~Delegate() = default; |
99 | 231 |
100 } // namespace content | 232 } // namespace content |
OLD | NEW |