1 // Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that can
3 // be found in the LICENSE file.
4
5 #include "libcef/browser/trace_subscriber.h"
6 #include "include/cef_trace.h"
7 #include "libcef/browser/thread_util.h"
8
9 #include "base/files/file_util.h"
10 #include "base/threading/thread_task_runner_handle.h"
11 #include "base/trace_event/trace_event.h"
12 #include "content/public/browser/tracing_controller.h"
13
14 namespace {
15
16 // Create the temporary file and then execute |callback| on the thread
17 // represented by |message_loop_proxy|.
CreateTemporaryFileOnBackgroundThread(scoped_refptr<base::SequencedTaskRunner> message_loop_proxy,base::Callback<void (const base::FilePath &)> callback)18 void CreateTemporaryFileOnBackgroundThread(
19 scoped_refptr<base::SequencedTaskRunner> message_loop_proxy,
20 base::Callback<void(const base::FilePath&)> callback) {
21 CEF_REQUIRE_BLOCKING();
22 base::FilePath file_path;
23 if (!base::CreateTemporaryFile(&file_path))
24 LOG(ERROR) << "Failed to create temporary file.";
25 message_loop_proxy->PostTask(FROM_HERE, base::Bind(callback, file_path));
26 }
27
28 // Release the wrapped callback object after completion.
29 class CefCompletionCallbackWrapper : public CefCompletionCallback {
30 public:
CefCompletionCallbackWrapper(CefRefPtr<CefCompletionCallback> callback)31 explicit CefCompletionCallbackWrapper(
32 CefRefPtr<CefCompletionCallback> callback)
33 : callback_(callback) {}
34
OnComplete()35 void OnComplete() override {
36 if (callback_) {
37 callback_->OnComplete();
38 callback_ = nullptr;
39 }
40 }
41
42 private:
43 CefRefPtr<CefCompletionCallback> callback_;
44
45 IMPLEMENT_REFCOUNTING(CefCompletionCallbackWrapper);
46 DISALLOW_COPY_AND_ASSIGN(CefCompletionCallbackWrapper);
47 };
48
49 } // namespace
50
51 using content::TracingController;
52
CefTraceSubscriber()53 CefTraceSubscriber::CefTraceSubscriber()
54 : collecting_trace_data_(false), weak_factory_(this) {
55 CEF_REQUIRE_UIT();
56 }
57
~CefTraceSubscriber()58 CefTraceSubscriber::~CefTraceSubscriber() {
59 CEF_REQUIRE_UIT();
60 if (collecting_trace_data_)
61 TracingController::GetInstance()->StopTracing(nullptr);
62 }
63
BeginTracing(const std::string & categories,CefRefPtr<CefCompletionCallback> callback)64 bool CefTraceSubscriber::BeginTracing(
65 const std::string& categories,
66 CefRefPtr<CefCompletionCallback> callback) {
67 CEF_REQUIRE_UIT();
68
69 if (collecting_trace_data_)
70 return false;
71
72 collecting_trace_data_ = true;
73
74 TracingController::StartTracingDoneCallback done_callback;
75 if (callback.get()) {
76 // Work around a bug introduced in http://crbug.com/542390#c22 that keeps a
77 // reference to |done_callback| after execution.
78 callback = new CefCompletionCallbackWrapper(callback);
79 done_callback =
80 base::BindOnce(&CefCompletionCallback::OnComplete, callback.get());
81 }
82
83 TracingController::GetInstance()->StartTracing(
84 base::trace_event::TraceConfig(categories, ""), std::move(done_callback));
85 return true;
86 }
87
EndTracing(const base::FilePath & tracing_file,CefRefPtr<CefEndTracingCallback> callback)88 bool CefTraceSubscriber::EndTracing(const base::FilePath& tracing_file,
89 CefRefPtr<CefEndTracingCallback> callback) {
90 CEF_REQUIRE_UIT();
91
92 if (!collecting_trace_data_)
93 return false;
94
95 if (!callback.get()) {
96 // Discard the trace data.
97 collecting_trace_data_ = false;
98 TracingController::GetInstance()->StopTracing(nullptr);
99 return true;
100 }
101
102 if (tracing_file.empty()) {
103 // Create a new temporary file path on the FILE thread, then continue.
104 CEF_POST_USER_VISIBLE_TASK(
105 base::Bind(CreateTemporaryFileOnBackgroundThread,
106 base::ThreadTaskRunnerHandle::Get(),
107 base::Bind(&CefTraceSubscriber::ContinueEndTracing,
108 weak_factory_.GetWeakPtr(), callback)));
109 return true;
110 }
111
112 base::Closure result_callback =
113 base::Bind(&CefTraceSubscriber::OnTracingFileResult,
114 weak_factory_.GetWeakPtr(), callback, tracing_file);
115
116 TracingController::GetInstance()->StopTracing(
117 TracingController::CreateFileEndpoint(tracing_file, result_callback));
118 return true;
119 }
120
ContinueEndTracing(CefRefPtr<CefEndTracingCallback> callback,const base::FilePath & tracing_file)121 void CefTraceSubscriber::ContinueEndTracing(
122 CefRefPtr<CefEndTracingCallback> callback,
123 const base::FilePath& tracing_file) {
124 CEF_REQUIRE_UIT();
125 if (!tracing_file.empty())
126 EndTracing(tracing_file, callback);
127 }
128
OnTracingFileResult(CefRefPtr<CefEndTracingCallback> callback,const base::FilePath & tracing_file)129 void CefTraceSubscriber::OnTracingFileResult(
130 CefRefPtr<CefEndTracingCallback> callback,
131 const base::FilePath& tracing_file) {
132 CEF_REQUIRE_UIT();
133
134 collecting_trace_data_ = false;
135
136 callback->OnEndTracingComplete(tracing_file.value());
137 }
138