• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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