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