1// Copyright (c) 2012 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 "chrome/browser/ui/webui/profiler_ui.h" 6 7#include <string> 8 9// When testing the javacript code, it is cumbersome to have to keep 10// re-building the resouces package and reloading the browser. To solve 11// this, enable the following flag to read the webapp's source files 12// directly off disk, so all you have to do is refresh the page to 13// test the modifications. 14// #define USE_SOURCE_FILES_DIRECTLY 15 16#include "base/bind.h" 17#include "base/memory/scoped_ptr.h" 18#include "base/strings/string_util.h" 19#include "base/tracked_objects.h" 20#include "base/values.h" 21#include "chrome/browser/profiles/profile.h" 22#include "chrome/browser/task_profiler/task_profiler_data_serializer.h" 23#include "chrome/common/url_constants.h" 24#include "components/metrics/profiler/tracking_synchronizer.h" 25#include "content/public/browser/browser_thread.h" 26#include "content/public/browser/url_data_source.h" 27#include "content/public/browser/web_contents.h" 28#include "content/public/browser/web_ui.h" 29#include "content/public/browser/web_ui_data_source.h" 30#include "content/public/browser/web_ui_message_handler.h" 31#include "grit/browser_resources.h" 32 33#ifdef USE_SOURCE_FILES_DIRECTLY 34#include "base/base_paths.h" 35#include "base/files/file_util.h" 36#include "base/memory/ref_counted_memory.h" 37#include "base/path_service.h" 38#endif // USE_SOURCE_FILES_DIRECTLY 39 40using content::BrowserThread; 41using content::WebContents; 42using content::WebUIMessageHandler; 43using metrics::TrackingSynchronizer; 44 45namespace { 46 47#ifdef USE_SOURCE_FILES_DIRECTLY 48 49class ProfilerWebUIDataSource : public content::URLDataSource { 50 public: 51 ProfilerWebUIDataSource() { 52 } 53 54 protected: 55 // content::URLDataSource implementation. 56 virtual std::string GetSource() OVERRIDE { 57 return chrome::kChromeUIProfilerHost; 58 } 59 60 virtual std::string GetMimeType(const std::string& path) const OVERRIDE { 61 if (EndsWith(path, ".js", false)) 62 return "application/javascript"; 63 return "text/html"; 64 } 65 66 virtual void StartDataRequest( 67 const std::string& path, 68 bool is_incognito, 69 const content::URLDataSource::GotDataCallback& callback) OVERRIDE { 70 base::FilePath base_path; 71 PathService::Get(base::DIR_SOURCE_ROOT, &base_path); 72 base_path = base_path.AppendASCII("chrome"); 73 base_path = base_path.AppendASCII("browser"); 74 base_path = base_path.AppendASCII("resources"); 75 base_path = base_path.AppendASCII("profiler"); 76 77 // If no resource was specified, default to profiler.html. 78 std::string filename = path.empty() ? "profiler.html" : path; 79 80 base::FilePath file_path; 81 file_path = base_path.AppendASCII(filename); 82 83 // Read the file synchronously and send it as the response. 84 base::ThreadRestrictions::ScopedAllowIO allow; 85 std::string file_contents; 86 if (!base::ReadFileToString(file_path, &file_contents)) 87 LOG(ERROR) << "Couldn't read file: " << file_path.value(); 88 scoped_refptr<base::RefCountedString> response = 89 new base::RefCountedString(); 90 response->data() = file_contents; 91 callback.Run(response); 92 } 93 94 private: 95 DISALLOW_COPY_AND_ASSIGN(ProfilerWebUIDataSource); 96}; 97 98#else // USE_SOURCE_FILES_DIRECTLY 99 100content::WebUIDataSource* CreateProfilerHTMLSource() { 101 content::WebUIDataSource* source = 102 content::WebUIDataSource::Create(chrome::kChromeUIProfilerHost); 103 104 source->SetJsonPath("strings.js"); 105 source->AddResourcePath("profiler.js", IDR_PROFILER_JS); 106 source->SetDefaultResource(IDR_PROFILER_HTML); 107 return source; 108} 109 110#endif 111 112// This class receives javascript messages from the renderer. 113// Note that the WebUI infrastructure runs on the UI thread, therefore all of 114// this class's methods are expected to run on the UI thread. 115class ProfilerMessageHandler : public WebUIMessageHandler { 116 public: 117 ProfilerMessageHandler() {} 118 119 // WebUIMessageHandler implementation. 120 virtual void RegisterMessages() OVERRIDE; 121 122 // Messages. 123 void OnGetData(const base::ListValue* list); 124 void OnResetData(const base::ListValue* list); 125 126 private: 127 DISALLOW_COPY_AND_ASSIGN(ProfilerMessageHandler); 128}; 129 130void ProfilerMessageHandler::RegisterMessages() { 131 DCHECK_CURRENTLY_ON(BrowserThread::UI); 132 133 web_ui()->RegisterMessageCallback("getData", 134 base::Bind(&ProfilerMessageHandler::OnGetData, base::Unretained(this))); 135 web_ui()->RegisterMessageCallback("resetData", 136 base::Bind(&ProfilerMessageHandler::OnResetData, 137 base::Unretained(this))); 138} 139 140void ProfilerMessageHandler::OnGetData(const base::ListValue* list) { 141 ProfilerUI* profiler_ui = static_cast<ProfilerUI*>(web_ui()->GetController()); 142 profiler_ui->GetData(); 143} 144 145void ProfilerMessageHandler::OnResetData(const base::ListValue* list) { 146 tracked_objects::ThreadData::ResetAllThreadData(); 147} 148 149} // namespace 150 151ProfilerUI::ProfilerUI(content::WebUI* web_ui) 152 : WebUIController(web_ui), 153 weak_ptr_factory_(this) { 154 web_ui->AddMessageHandler(new ProfilerMessageHandler()); 155 156 // Set up the chrome://profiler/ source. 157 Profile* profile = Profile::FromWebUI(web_ui); 158#if defined(USE_SOURCE_FILES_DIRECTLY) 159 content::URLDataSource::Add(profile, new ProfilerWebUIDataSource); 160#else 161 content::WebUIDataSource::Add(profile, CreateProfilerHTMLSource()); 162#endif 163} 164 165ProfilerUI::~ProfilerUI() { 166} 167 168void ProfilerUI::GetData() { 169 TrackingSynchronizer::FetchProfilerDataAsynchronously( 170 weak_ptr_factory_.GetWeakPtr()); 171} 172 173void ProfilerUI::ReceivedProfilerData( 174 const tracked_objects::ProcessDataSnapshot& profiler_data, 175 int process_type) { 176 // Serialize the data to JSON. 177 base::DictionaryValue json_data; 178 task_profiler::TaskProfilerDataSerializer::ToValue(profiler_data, 179 process_type, 180 &json_data); 181 182 // Send the data to the renderer. 183 web_ui()->CallJavascriptFunction("g_browserBridge.receivedData", json_data); 184} 185