• 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::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