Home | History | Annotate | Download | only in webui
      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