1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// found in the LICENSE file.
4868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/renderer/stats_collection_controller.h"
6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/json/json_writer.h"
8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/metrics/histogram.h"
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/metrics/statistics_recorder.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/common/child_process_messages.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/renderer/render_view_impl.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "gin/handle.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "gin/object_template_builder.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "third_party/WebKit/public/web/WebKit.h"
16a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "third_party/WebKit/public/web/WebLocalFrame.h"
177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebView.h"
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace content {
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace {
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool CurrentRenderViewImpl(RenderViewImpl** out) {
24a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  blink::WebLocalFrame* web_frame =
25a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      blink::WebLocalFrame::frameForCurrentContext();
26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!web_frame)
27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return false;
28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
29f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  blink::WebView* web_view = web_frame->view();
30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!web_view)
31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return false;
32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  RenderViewImpl* render_view_impl =
34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      RenderViewImpl::FromWebView(web_view);
35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!render_view_impl)
36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return false;
37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  *out = render_view_impl;
39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return true;
40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Encodes a WebContentsLoadTime as JSON.
43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Input:
44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// - |load_start_time| - time at which page load started.
45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// - |load_stop_time| - time at which page load stopped.
46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// - |result| - returned JSON.
47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Example return value:
48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// {'load_start_ms': 1, 'load_duration_ms': 2.5}
49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// either value may be null if a web contents hasn't fully loaded.
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// load_start_ms is represented as milliseconds since the unix epoch.
51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void ConvertLoadTimeToJSON(
52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const base::Time& load_start_time,
53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const base::Time& load_stop_time,
54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    std::string *result) {
557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  base::DictionaryValue item;
56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (load_start_time.is_null()) {
58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    item.Set("load_start_ms", base::Value::CreateNullValue());
59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else {
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    item.SetDouble("load_start_ms", (load_start_time - base::Time::UnixEpoch())
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                   .InMillisecondsF());
62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
632385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  if (load_start_time.is_null() || load_stop_time.is_null()) {
647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    item.Set("load_duration_ms", base::Value::CreateNullValue());
65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else {
66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    item.SetDouble("load_duration_ms",
67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        (load_stop_time - load_start_time).InMillisecondsF());
68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::JSONWriter::Write(&item, result);
70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace
73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)gin::WrapperInfo StatsCollectionController::kWrapperInfo = {
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gin::kEmbedderNativeGin
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void StatsCollectionController::Install(blink::WebFrame* frame) {
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::Isolate* isolate = blink::mainThreadIsolate();
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::HandleScope handle_scope(isolate);
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (context.IsEmpty())
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::Context::Scope context_scope(context);
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gin::Handle<StatsCollectionController> controller =
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      gin::CreateHandle(isolate, new StatsCollectionController());
915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (controller.IsEmpty())
925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return;
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::Handle<v8::Object> global = context->Global();
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  global->Set(gin::StringToV8(isolate, "statsCollectionController"),
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              controller.ToV8());
96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
97868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)StatsCollectionController::StatsCollectionController() {}
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)StatsCollectionController::~StatsCollectionController() {}
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)gin::ObjectTemplateBuilder StatsCollectionController::GetObjectTemplateBuilder(
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    v8::Isolate* isolate) {
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return gin::Wrappable<StatsCollectionController>::GetObjectTemplateBuilder(
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      isolate)
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .SetMethod("getHistogram", &StatsCollectionController::GetHistogram)
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .SetMethod("getBrowserHistogram",
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 &StatsCollectionController::GetBrowserHistogram)
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .SetMethod("tabLoadTiming", &StatsCollectionController::GetTabLoadTiming);
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string StatsCollectionController::GetHistogram(
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& histogram_name) {
114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::HistogramBase* histogram =
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::StatisticsRecorder::FindHistogram(histogram_name);
116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::string output;
117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!histogram) {
118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    output = "{}";
119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else {
120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    histogram->WriteJSON(&output);
121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return output;
123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string StatsCollectionController::GetBrowserHistogram(
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& histogram_name) {
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RenderViewImpl *render_view_impl = NULL;
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!CurrentRenderViewImpl(&render_view_impl)) {
129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    NOTREACHED();
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return std::string();
131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::string histogram_json;
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  render_view_impl->Send(new ChildProcessHostMsg_GetBrowserHistogram(
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      histogram_name, &histogram_json));
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return histogram_json;
137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string StatsCollectionController::GetTabLoadTiming() {
140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  RenderViewImpl *render_view_impl = NULL;
141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!CurrentRenderViewImpl(&render_view_impl)) {
142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    NOTREACHED();
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return std::string();
144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  StatsCollectionObserver* observer =
147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      render_view_impl->GetStatsCollectionObserver();
148868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!observer) {
149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    NOTREACHED();
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return std::string();
151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::string tab_timing_json;
154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ConvertLoadTimeToJSON(
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      observer->load_start_time(), observer->load_stop_time(),
156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      &tab_timing_json);
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return tab_timing_json;
158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
160868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace content
161