blob: 6c5c3c10bc59ad18dd0f8035340f3e21cbd0be14 [file] [log] [blame]
// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.
#include "libcef/browser/trace_subscriber.h"
#include "include/cef_trace.h"
#include "libcef/browser/thread_util.h"
#include "base/files/file_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
#include "content/public/browser/tracing_controller.h"
namespace {
// Create the temporary file and then execute |callback| on the thread
// represented by |message_loop_proxy|.
void CreateTemporaryFileOnBackgroundThread(
scoped_refptr<base::SequencedTaskRunner> message_loop_proxy,
base::Callback<void(const base::FilePath&)> callback) {
CEF_REQUIRE_BLOCKING();
base::FilePath file_path;
if (!base::CreateTemporaryFile(&file_path))
LOG(ERROR) << "Failed to create temporary file.";
message_loop_proxy->PostTask(FROM_HERE, base::Bind(callback, file_path));
}
// Release the wrapped callback object after completion.
class CefCompletionCallbackWrapper : public CefCompletionCallback {
public:
explicit CefCompletionCallbackWrapper(
CefRefPtr<CefCompletionCallback> callback)
: callback_(callback) {}
void OnComplete() override {
if (callback_) {
callback_->OnComplete();
callback_ = nullptr;
}
}
private:
CefRefPtr<CefCompletionCallback> callback_;
IMPLEMENT_REFCOUNTING(CefCompletionCallbackWrapper);
DISALLOW_COPY_AND_ASSIGN(CefCompletionCallbackWrapper);
};
} // namespace
using content::TracingController;
CefTraceSubscriber::CefTraceSubscriber()
: collecting_trace_data_(false), weak_factory_(this) {
CEF_REQUIRE_UIT();
}
CefTraceSubscriber::~CefTraceSubscriber() {
CEF_REQUIRE_UIT();
if (collecting_trace_data_)
TracingController::GetInstance()->StopTracing(nullptr);
}
bool CefTraceSubscriber::BeginTracing(
const std::string& categories,
CefRefPtr<CefCompletionCallback> callback) {
CEF_REQUIRE_UIT();
if (collecting_trace_data_)
return false;
collecting_trace_data_ = true;
TracingController::StartTracingDoneCallback done_callback;
if (callback.get()) {
// Work around a bug introduced in http://crbug.com/542390#c22 that keeps a
// reference to |done_callback| after execution.
callback = new CefCompletionCallbackWrapper(callback);
done_callback =
base::BindOnce(&CefCompletionCallback::OnComplete, callback.get());
}
TracingController::GetInstance()->StartTracing(
base::trace_event::TraceConfig(categories, ""), std::move(done_callback));
return true;
}
bool CefTraceSubscriber::EndTracing(const base::FilePath& tracing_file,
CefRefPtr<CefEndTracingCallback> callback) {
CEF_REQUIRE_UIT();
if (!collecting_trace_data_)
return false;
if (!callback.get()) {
// Discard the trace data.
collecting_trace_data_ = false;
TracingController::GetInstance()->StopTracing(nullptr);
return true;
}
if (tracing_file.empty()) {
// Create a new temporary file path on the FILE thread, then continue.
CEF_POST_USER_VISIBLE_TASK(
base::Bind(CreateTemporaryFileOnBackgroundThread,
base::ThreadTaskRunnerHandle::Get(),
base::Bind(&CefTraceSubscriber::ContinueEndTracing,
weak_factory_.GetWeakPtr(), callback)));
return true;
}
base::Closure result_callback =
base::Bind(&CefTraceSubscriber::OnTracingFileResult,
weak_factory_.GetWeakPtr(), callback, tracing_file);
TracingController::GetInstance()->StopTracing(
TracingController::CreateFileEndpoint(tracing_file, result_callback));
return true;
}
void CefTraceSubscriber::ContinueEndTracing(
CefRefPtr<CefEndTracingCallback> callback,
const base::FilePath& tracing_file) {
CEF_REQUIRE_UIT();
if (!tracing_file.empty())
EndTracing(tracing_file, callback);
}
void CefTraceSubscriber::OnTracingFileResult(
CefRefPtr<CefEndTracingCallback> callback,
const base::FilePath& tracing_file) {
CEF_REQUIRE_UIT();
collecting_trace_data_ = false;
callback->OnEndTracingComplete(tracing_file.value());
}