// 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 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 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 controller = gin::CreateHandle( isolate, new StatsCollectionController(collector_for_controller.Pass())); DCHECK(!controller.IsEmpty()); v8::Local 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::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