blob: 70ab672c83614bb8057ee4c3cfeefe8c586ef49c [file] [log] [blame]
// Copyright 2015 The Chromium 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 "components/html_viewer/stats_collection_controller.h"
#include "base/command_line.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram.h"
#include "base/metrics/statistics_recorder.h"
#include "base/time/time.h"
#include "components/startup_metric_utils/startup_metric_utils.h"
#include "gin/handle.h"
#include "gin/object_template_builder.h"
#include "mojo/application/public/cpp/application_impl.h"
#include "mojo/services/tracing/public/cpp/switches.h"
#include "third_party/WebKit/public/web/WebKit.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
namespace html_viewer {
namespace {
// Initialize the histogram data using the given startup performance times.
// TODO(msw): Use TimeTicks to avoid system clock changes: crbug.com/521164
void GetStartupPerformanceTimesCallbackImpl(
tracing::StartupPerformanceTimesPtr times) {
base::StatisticsRecorder::Initialize();
startup_metric_utils::RecordStartupProcessCreationTime(
base::Time::FromInternalValue(times->shell_process_creation_time));
// TODO(msw): Record the MojoMain() entry point time of mojo:browser instead?
startup_metric_utils::RecordMainEntryPointTime(
base::Time::FromInternalValue(times->shell_main_entry_point_time));
// TODO(msw): Determine if this is the first run.
startup_metric_utils::RecordBrowserMainMessageLoopStart(
base::Time::FromInternalValue(times->browser_message_loop_start_time),
false);
startup_metric_utils::RecordBrowserWindowDisplay(
base::Time::FromInternalValue(times->browser_window_display_time));
startup_metric_utils::RecordBrowserOpenTabsDelta(
base::TimeDelta::FromInternalValue(times->browser_open_tabs_time_delta));
startup_metric_utils::RecordFirstWebContentsMainFrameLoad(
base::Time::FromInternalValue(
times->first_web_contents_main_frame_load_time));
startup_metric_utils::RecordFirstWebContentsNonEmptyPaint(
base::Time::FromInternalValue(
times->first_visually_non_empty_layout_time));
}
} // namespace
// static
gin::WrapperInfo StatsCollectionController::kWrapperInfo = {
gin::kEmbedderNativeGin};
// static
tracing::StartupPerformanceDataCollectorPtr StatsCollectionController::Install(
blink::WebFrame* frame,
mojo::ApplicationImpl* app) {
// Only make startup tracing available when running in the context of a test.
if (!app ||
!base::CommandLine::ForCurrentProcess()->HasSwitch(
tracing::kEnableStatsCollectionBindings)) {
return nullptr;
}
v8::Isolate* isolate = blink::mainThreadIsolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = frame->mainWorldScriptContext();
if (context.IsEmpty())
return nullptr;
v8::Context::Scope context_scope(context);
mojo::URLRequestPtr request(mojo::URLRequest::New());
request->url = mojo::String::From("mojo:tracing");
scoped_ptr<mojo::ApplicationConnection> connection =
app->ConnectToApplication(request.Pass());
if (!connection)
return nullptr;
tracing::StartupPerformanceDataCollectorPtr collector_for_controller;
tracing::StartupPerformanceDataCollectorPtr collector_for_caller;
connection->ConnectToService(&collector_for_controller);
connection->ConnectToService(&collector_for_caller);
gin::Handle<StatsCollectionController> controller = gin::CreateHandle(
isolate, new StatsCollectionController(collector_for_controller.Pass()));
DCHECK(!controller.IsEmpty());
v8::Local<v8::Object> global = context->Global();
global->Set(gin::StringToV8(isolate, "statsCollectionController"),
controller.ToV8());
return collector_for_caller.Pass();
}
// static
tracing::StartupPerformanceDataCollectorPtr
StatsCollectionController::ConnectToDataCollector(mojo::ApplicationImpl* app) {
// Only make startup tracing available when running in the context of a test.
if (!app ||
!base::CommandLine::ForCurrentProcess()->HasSwitch(
tracing::kEnableStatsCollectionBindings)) {
return nullptr;
}
mojo::URLRequestPtr request(mojo::URLRequest::New());
request->url = mojo::String::From("mojo:tracing");
tracing::StartupPerformanceDataCollectorPtr collector;
app->ConnectToService(request.Pass(), &collector);
return collector.Pass();
}
StatsCollectionController::StatsCollectionController(
tracing::StartupPerformanceDataCollectorPtr collector)
: startup_performance_data_collector_(collector.Pass()) {}
StatsCollectionController::~StatsCollectionController() {}
gin::ObjectTemplateBuilder StatsCollectionController::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return gin::Wrappable<StatsCollectionController>::GetObjectTemplateBuilder(
isolate)
.SetMethod("getHistogram", &StatsCollectionController::GetHistogram)
.SetMethod("getBrowserHistogram",
&StatsCollectionController::GetBrowserHistogram);
}
std::string StatsCollectionController::GetHistogram(
const std::string& histogram_name) {
DCHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
tracing::kEnableStatsCollectionBindings));
static bool startup_histogram_initialized = false;
if (!startup_histogram_initialized) {
// Get the startup performance times from the tracing service.
auto callback = base::Bind(&GetStartupPerformanceTimesCallbackImpl);
startup_performance_data_collector_->GetStartupPerformanceTimes(callback);
startup_performance_data_collector_.WaitForIncomingResponse();
DCHECK(base::StatisticsRecorder::IsActive());
startup_histogram_initialized = true;
}
std::string histogram_json = "{}";
base::HistogramBase* histogram =
base::StatisticsRecorder::FindHistogram(histogram_name);
if (histogram)
histogram->WriteJSON(&histogram_json);
return histogram_json;
}
std::string StatsCollectionController::GetBrowserHistogram(
const std::string& histogram_name) {
return GetHistogram(histogram_name);
}
} // namespace html_viewer