// Copyright 2013 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 "content/renderer/stats_collection_controller.h"
#include "base/json/json_writer.h"
#include "base/metrics/histogram.h"
#include "base/metrics/statistics_recorder.h"
#include "base/strings/string_util.h"
#include "content/common/child_process_messages.h"
#include "content/renderer/render_view_impl.h"
#include "gin/handle.h"
#include "gin/object_template_builder.h"
#include "gin/per_isolate_data.h"
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebKit.h"
#include "third_party/WebKit/public/web/WebView.h"
namespace content {
namespace {
bool CurrentRenderViewImpl(RenderViewImpl** out) {
blink::WebFrame* web_frame = blink::WebFrame::frameForCurrentContext();
if (!web_frame)
return false;
blink::WebView* web_view = web_frame->view();
if (!web_view)
return false;
RenderViewImpl* render_view_impl =
RenderViewImpl::FromWebView(web_view);
if (!render_view_impl)
return false;
*out = render_view_impl;
return true;
}
// Encodes a WebContentsLoadTime as JSON.
// Input:
// - |load_start_time| - time at which page load started.
// - |load_stop_time| - time at which page load stopped.
// - |result| - returned JSON.
// Example return value:
// {'load_start_ms': 1, 'load_duration_ms': 2.5}
// either value may be null if a web contents hasn't fully loaded.
// load_start_ms is represented as milliseconds since system boot.
void ConvertLoadTimeToJSON(
const base::Time& load_start_time,
const base::Time& load_stop_time,
std::string *result) {
base::DictionaryValue item;
if (load_start_time.is_null()) {
item.Set("load_start_ms", base::Value::CreateNullValue());
} else {
item.SetDouble("load_start_ms", load_start_time.ToInternalValue() / 1000);
}
if (load_start_time.is_null() || load_stop_time.is_null()) {
item.Set("load_duration_ms", base::Value::CreateNullValue());
} else {
item.SetDouble("load_duration_ms",
(load_stop_time - load_start_time).InMillisecondsF());
}
base::JSONWriter::Write(&item, result);
}
} // namespace
// static
gin::WrapperInfo StatsCollectionController::kWrapperInfo = {
gin::kEmbedderNativeGin
};
// static
void StatsCollectionController::Install(blink::WebFrame* frame) {
v8::Isolate* isolate = blink::mainThreadIsolate();
v8::HandleScope handle_scope(isolate);
v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
if (context.IsEmpty())
return;
v8::Context::Scope context_scope(context);
gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
if (data->GetObjectTemplate(&StatsCollectionController::kWrapperInfo)
.IsEmpty()) {
v8::Handle<v8::ObjectTemplate> templ =
gin::ObjectTemplateBuilder(isolate)
.SetMethod("getHistogram", &StatsCollectionController::GetHistogram)
.SetMethod("getBrowserHistogram",
&StatsCollectionController::GetBrowserHistogram)
.SetMethod("tabLoadTiming",
&StatsCollectionController::GetTabLoadTiming)
.Build();
templ->SetInternalFieldCount(gin::kNumberOfInternalFields);
data->SetObjectTemplate(&StatsCollectionController::kWrapperInfo, templ);
}
gin::Handle<StatsCollectionController> controller =
gin::CreateHandle(isolate, new StatsCollectionController());
v8::Handle<v8::Object> global = context->Global();
global->Set(gin::StringToV8(isolate, "statsCollectionController"),
controller.ToV8());
}
StatsCollectionController::StatsCollectionController() {}
StatsCollectionController::~StatsCollectionController() {}
std::string StatsCollectionController::GetHistogram(
const std::string& histogram_name) {
base::HistogramBase* histogram =
base::StatisticsRecorder::FindHistogram(histogram_name);
std::string output;
if (!histogram) {
output = "{}";
} else {
histogram->WriteJSON(&output);
}
return output;
}
std::string StatsCollectionController::GetBrowserHistogram(
const std::string& histogram_name) {
RenderViewImpl *render_view_impl = NULL;
if (!CurrentRenderViewImpl(&render_view_impl)) {
NOTREACHED();
return std::string();
}
std::string histogram_json;
render_view_impl->Send(new ChildProcessHostMsg_GetBrowserHistogram(
histogram_name, &histogram_json));
return histogram_json;
}
std::string StatsCollectionController::GetTabLoadTiming() {
RenderViewImpl *render_view_impl = NULL;
if (!CurrentRenderViewImpl(&render_view_impl)) {
NOTREACHED();
return std::string();
}
StatsCollectionObserver* observer =
render_view_impl->GetStatsCollectionObserver();
if (!observer) {
NOTREACHED();
return std::string();
}
std::string tab_timing_json;
ConvertLoadTimeToJSON(
observer->load_start_time(), observer->load_stop_time(),
&tab_timing_json);
return tab_timing_json;
}
} // namespace content