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::OnceCallback<void (const base::FilePath &)> callback)18 void CreateTemporaryFileOnBackgroundThread(
19 scoped_refptr<base::SequencedTaskRunner> message_loop_proxy,
20 base::OnceCallback<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,
26 base::BindOnce(std::move(callback), file_path));
27 }
28
29 // Release the wrapped callback object after completion.
30 class CefCompletionCallbackWrapper : public CefCompletionCallback {
31 public:
CefCompletionCallbackWrapper(CefRefPtr<CefCompletionCallback> callback)32 explicit CefCompletionCallbackWrapper(
33 CefRefPtr<CefCompletionCallback> callback)
34 : callback_(callback) {}
35
36 CefCompletionCallbackWrapper(const CefCompletionCallbackWrapper&) = delete;
37 CefCompletionCallbackWrapper& operator=(const CefCompletionCallbackWrapper&) =
38 delete;
39
OnComplete()40 void OnComplete() override {
41 if (callback_) {
42 callback_->OnComplete();
43 callback_ = nullptr;
44 }
45 }
46
47 private:
48 CefRefPtr<CefCompletionCallback> callback_;
49
50 IMPLEMENT_REFCOUNTING(CefCompletionCallbackWrapper);
51 };
52
53 } // namespace
54
55 using content::TracingController;
56
CefTraceSubscriber()57 CefTraceSubscriber::CefTraceSubscriber()
58 : collecting_trace_data_(false), weak_factory_(this) {
59 CEF_REQUIRE_UIT();
60 }
61
~CefTraceSubscriber()62 CefTraceSubscriber::~CefTraceSubscriber() {
63 CEF_REQUIRE_UIT();
64 if (collecting_trace_data_)
65 TracingController::GetInstance()->StopTracing(nullptr);
66 }
67
BeginTracing(const std::string & categories,CefRefPtr<CefCompletionCallback> callback)68 bool CefTraceSubscriber::BeginTracing(
69 const std::string& categories,
70 CefRefPtr<CefCompletionCallback> callback) {
71 CEF_REQUIRE_UIT();
72
73 if (collecting_trace_data_)
74 return false;
75
76 collecting_trace_data_ = true;
77
78 TracingController::StartTracingDoneCallback done_callback;
79 if (callback.get()) {
80 // Work around a bug introduced in http://crbug.com/542390#c22 that keeps a
81 // reference to |done_callback| after execution.
82 callback = new CefCompletionCallbackWrapper(callback);
83 done_callback =
84 base::BindOnce(&CefCompletionCallback::OnComplete, callback.get());
85 }
86
87 TracingController::GetInstance()->StartTracing(
88 base::trace_event::TraceConfig(categories, ""), std::move(done_callback));
89 return true;
90 }
91
EndTracing(const base::FilePath & tracing_file,CefRefPtr<CefEndTracingCallback> callback)92 bool CefTraceSubscriber::EndTracing(const base::FilePath& tracing_file,
93 CefRefPtr<CefEndTracingCallback> callback) {
94 CEF_REQUIRE_UIT();
95
96 if (!collecting_trace_data_)
97 return false;
98
99 if (!callback.get()) {
100 // Discard the trace data.
101 collecting_trace_data_ = false;
102 TracingController::GetInstance()->StopTracing(nullptr);
103 return true;
104 }
105
106 if (tracing_file.empty()) {
107 // Create a new temporary file path on the FILE thread, then continue.
108 CEF_POST_USER_VISIBLE_TASK(
109 base::BindOnce(CreateTemporaryFileOnBackgroundThread,
110 base::ThreadTaskRunnerHandle::Get(),
111 base::BindOnce(&CefTraceSubscriber::ContinueEndTracing,
112 weak_factory_.GetWeakPtr(), callback)));
113 return true;
114 }
115
116 auto result_callback =
117 base::BindOnce(&CefTraceSubscriber::OnTracingFileResult,
118 weak_factory_.GetWeakPtr(), callback, tracing_file);
119
120 TracingController::GetInstance()->StopTracing(
121 TracingController::CreateFileEndpoint(tracing_file,
122 std::move(result_callback)));
123 return true;
124 }
125
ContinueEndTracing(CefRefPtr<CefEndTracingCallback> callback,const base::FilePath & tracing_file)126 void CefTraceSubscriber::ContinueEndTracing(
127 CefRefPtr<CefEndTracingCallback> callback,
128 const base::FilePath& tracing_file) {
129 CEF_REQUIRE_UIT();
130 if (!tracing_file.empty())
131 EndTracing(tracing_file, callback);
132 }
133
OnTracingFileResult(CefRefPtr<CefEndTracingCallback> callback,const base::FilePath & tracing_file)134 void CefTraceSubscriber::OnTracingFileResult(
135 CefRefPtr<CefEndTracingCallback> callback,
136 const base::FilePath& tracing_file) {
137 CEF_REQUIRE_UIT();
138
139 collecting_trace_data_ = false;
140
141 callback->OnEndTracingComplete(tracing_file.value());
142 }
143