1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/renderer/stats_collection_controller.h" 6 7 #include "base/json/json_writer.h" 8 #include "base/metrics/histogram.h" 9 #include "base/metrics/statistics_recorder.h" 10 #include "base/strings/string_util.h" 11 #include "content/common/child_process_messages.h" 12 #include "content/renderer/render_view_impl.h" 13 #include "gin/handle.h" 14 #include "gin/object_template_builder.h" 15 #include "gin/per_isolate_data.h" 16 #include "third_party/WebKit/public/web/WebFrame.h" 17 #include "third_party/WebKit/public/web/WebKit.h" 18 #include "third_party/WebKit/public/web/WebView.h" 19 20 namespace content { 21 22 namespace { 23 24 bool CurrentRenderViewImpl(RenderViewImpl** out) { 25 blink::WebFrame* web_frame = blink::WebFrame::frameForCurrentContext(); 26 if (!web_frame) 27 return false; 28 29 blink::WebView* web_view = web_frame->view(); 30 if (!web_view) 31 return false; 32 33 RenderViewImpl* render_view_impl = 34 RenderViewImpl::FromWebView(web_view); 35 if (!render_view_impl) 36 return false; 37 38 *out = render_view_impl; 39 return true; 40 } 41 42 // Encodes a WebContentsLoadTime as JSON. 43 // Input: 44 // - |load_start_time| - time at which page load started. 45 // - |load_stop_time| - time at which page load stopped. 46 // - |result| - returned JSON. 47 // Example return value: 48 // {'load_start_ms': 1, 'load_duration_ms': 2.5} 49 // either value may be null if a web contents hasn't fully loaded. 50 // load_start_ms is represented as milliseconds since system boot. 51 void ConvertLoadTimeToJSON( 52 const base::Time& load_start_time, 53 const base::Time& load_stop_time, 54 std::string *result) { 55 base::DictionaryValue item; 56 57 if (load_start_time.is_null()) { 58 item.Set("load_start_ms", base::Value::CreateNullValue()); 59 } else { 60 item.SetDouble("load_start_ms", load_start_time.ToInternalValue() / 1000); 61 } 62 if (load_start_time.is_null() || load_stop_time.is_null()) { 63 item.Set("load_duration_ms", base::Value::CreateNullValue()); 64 } else { 65 item.SetDouble("load_duration_ms", 66 (load_stop_time - load_start_time).InMillisecondsF()); 67 } 68 base::JSONWriter::Write(&item, result); 69 } 70 71 } // namespace 72 73 // static 74 gin::WrapperInfo StatsCollectionController::kWrapperInfo = { 75 gin::kEmbedderNativeGin 76 }; 77 78 // static 79 void StatsCollectionController::Install(blink::WebFrame* frame) { 80 v8::Isolate* isolate = blink::mainThreadIsolate(); 81 v8::HandleScope handle_scope(isolate); 82 v8::Handle<v8::Context> context = frame->mainWorldScriptContext(); 83 if (context.IsEmpty()) 84 return; 85 86 v8::Context::Scope context_scope(context); 87 88 gin::PerIsolateData* data = gin::PerIsolateData::From(isolate); 89 if (data->GetObjectTemplate(&StatsCollectionController::kWrapperInfo) 90 .IsEmpty()) { 91 v8::Handle<v8::ObjectTemplate> templ = 92 gin::ObjectTemplateBuilder(isolate) 93 .SetMethod("getHistogram", &StatsCollectionController::GetHistogram) 94 .SetMethod("getBrowserHistogram", 95 &StatsCollectionController::GetBrowserHistogram) 96 .SetMethod("tabLoadTiming", 97 &StatsCollectionController::GetTabLoadTiming) 98 .Build(); 99 templ->SetInternalFieldCount(gin::kNumberOfInternalFields); 100 data->SetObjectTemplate(&StatsCollectionController::kWrapperInfo, templ); 101 } 102 103 gin::Handle<StatsCollectionController> controller = 104 gin::CreateHandle(isolate, new StatsCollectionController()); 105 v8::Handle<v8::Object> global = context->Global(); 106 global->Set(gin::StringToV8(isolate, "statsCollectionController"), 107 controller.ToV8()); 108 } 109 110 StatsCollectionController::StatsCollectionController() {} 111 112 StatsCollectionController::~StatsCollectionController() {} 113 114 std::string StatsCollectionController::GetHistogram( 115 const std::string& histogram_name) { 116 base::HistogramBase* histogram = 117 base::StatisticsRecorder::FindHistogram(histogram_name); 118 std::string output; 119 if (!histogram) { 120 output = "{}"; 121 } else { 122 histogram->WriteJSON(&output); 123 } 124 return output; 125 } 126 127 std::string StatsCollectionController::GetBrowserHistogram( 128 const std::string& histogram_name) { 129 RenderViewImpl *render_view_impl = NULL; 130 if (!CurrentRenderViewImpl(&render_view_impl)) { 131 NOTREACHED(); 132 return std::string(); 133 } 134 135 std::string histogram_json; 136 render_view_impl->Send(new ChildProcessHostMsg_GetBrowserHistogram( 137 histogram_name, &histogram_json)); 138 return histogram_json; 139 } 140 141 std::string StatsCollectionController::GetTabLoadTiming() { 142 RenderViewImpl *render_view_impl = NULL; 143 if (!CurrentRenderViewImpl(&render_view_impl)) { 144 NOTREACHED(); 145 return std::string(); 146 } 147 148 StatsCollectionObserver* observer = 149 render_view_impl->GetStatsCollectionObserver(); 150 if (!observer) { 151 NOTREACHED(); 152 return std::string(); 153 } 154 155 std::string tab_timing_json; 156 ConvertLoadTimeToJSON( 157 observer->load_start_time(), observer->load_stop_time(), 158 &tab_timing_json); 159 return tab_timing_json; 160 } 161 162 } // namespace content 163