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/bind.h" 8 #include "base/bind_helpers.h" 9 #include "base/json/json_writer.h" 10 #include "base/metrics/histogram.h" 11 #include "base/metrics/statistics_recorder.h" 12 #include "base/strings/string_util.h" 13 #include "content/common/child_process_messages.h" 14 #include "content/renderer/render_view_impl.h" 15 #include "third_party/WebKit/public/web/WebFrame.h" 16 #include "third_party/WebKit/public/web/WebView.h" 17 18 using webkit_glue::CppArgumentList; 19 using webkit_glue::CppVariant; 20 21 namespace content { 22 23 namespace { 24 25 bool CurrentRenderViewImpl(RenderViewImpl** out) { 26 WebKit::WebFrame* web_frame = WebKit::WebFrame::frameForCurrentContext(); 27 if (!web_frame) 28 return false; 29 30 WebKit::WebView* web_view = web_frame->view(); 31 if (!web_view) 32 return false; 33 34 RenderViewImpl* render_view_impl = 35 RenderViewImpl::FromWebView(web_view); 36 if (!render_view_impl) 37 return false; 38 39 *out = render_view_impl; 40 return true; 41 } 42 43 // Encodes a WebContentsLoadTime as JSON. 44 // Input: 45 // - |load_start_time| - time at which page load started. 46 // - |load_stop_time| - time at which page load stopped. 47 // - |result| - returned JSON. 48 // Example return value: 49 // {'load_start_ms': 1, 'load_duration_ms': 2.5} 50 // either value may be null if a web contents hasn't fully loaded. 51 // load_start_ms is represented as milliseconds since system boot. 52 void ConvertLoadTimeToJSON( 53 const base::TimeTicks& load_start_time, 54 const base::TimeTicks& load_stop_time, 55 std::string *result) { 56 base::DictionaryValue item; 57 58 if (load_start_time.is_null()) { 59 item.Set("load_start_ms", base::Value::CreateNullValue()); 60 } else { 61 // This code relies on an implementation detail of TimeTicks::Now() - that 62 // its return value happens to coincide with the system uptime value in 63 // microseconds, on Win/Mac/iOS/Linux/ChromeOS and Android. See comments 64 // in base::SysInfo::Uptime(). 65 item.SetDouble("load_start_ms", load_start_time.ToInternalValue() / 1000); 66 } 67 if (load_start_time.is_null() || load_stop_time.is_null()) { 68 item.Set("load_duration_ms", base::Value::CreateNullValue()); 69 } else { 70 item.SetDouble("load_duration_ms", 71 (load_stop_time - load_start_time).InMilliseconds()); 72 } 73 base::JSONWriter::Write(&item, result); 74 } 75 76 } // namespace 77 78 StatsCollectionController::StatsCollectionController() 79 : sender_(NULL) { 80 BindCallback("getHistogram", 81 base::Bind(&StatsCollectionController::GetHistogram, 82 base::Unretained(this))); 83 BindCallback("getBrowserHistogram", 84 base::Bind(&StatsCollectionController::GetBrowserHistogram, 85 base::Unretained(this))); 86 BindCallback("tabLoadTiming", 87 base::Bind( 88 &StatsCollectionController::GetTabLoadTiming, 89 base::Unretained(this))); 90 } 91 92 void StatsCollectionController::GetHistogram(const CppArgumentList& args, 93 CppVariant* result) { 94 if (args.size() != 1) { 95 result->SetNull(); 96 return; 97 } 98 base::HistogramBase* histogram = 99 base::StatisticsRecorder::FindHistogram(args[0].ToString()); 100 std::string output; 101 if (!histogram) { 102 output = "{}"; 103 } else { 104 histogram->WriteJSON(&output); 105 } 106 result->Set(output); 107 } 108 109 void StatsCollectionController::GetBrowserHistogram(const CppArgumentList& args, 110 CppVariant* result) { 111 if (args.size() != 1) { 112 result->SetNull(); 113 return; 114 } 115 116 if (!sender_) { 117 NOTREACHED(); 118 result->SetNull(); 119 return; 120 } 121 122 std::string histogram_json; 123 sender_->Send(new ChildProcessHostMsg_GetBrowserHistogram( 124 args[0].ToString(), &histogram_json)); 125 result->Set(histogram_json); 126 } 127 128 void StatsCollectionController::GetTabLoadTiming( 129 const CppArgumentList& args, 130 CppVariant* result) { 131 if (!sender_) { 132 NOTREACHED(); 133 result->SetNull(); 134 return; 135 } 136 137 RenderViewImpl *render_view_impl = NULL; 138 if (!CurrentRenderViewImpl(&render_view_impl)) { 139 NOTREACHED(); 140 result->SetNull(); 141 return; 142 } 143 144 StatsCollectionObserver* observer = 145 render_view_impl->GetStatsCollectionObserver(); 146 if (!observer) { 147 NOTREACHED(); 148 result->SetNull(); 149 return; 150 } 151 152 std::string tab_timing_json; 153 ConvertLoadTimeToJSON( 154 observer->load_start_time(), observer->load_stop_time(), 155 &tab_timing_json); 156 result->Set(tab_timing_json); 157 } 158 159 } // namespace content 160