blob: ad6488b6aceb29eb622708f68fd0db2a0408a6a8 [file] [log] [blame]
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001// 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/inspect_ui.h"
6
7#include <set>
8
9#include "base/bind.h"
10#include "base/bind_helpers.h"
11#include "base/json/json_writer.h"
12#include "base/memory/ref_counted_memory.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000013#include "base/strings/string_number_conversions.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010014#include "base/strings/string_util.h"
Ben Murdochbb1529c2013-08-08 10:24:53 +010015#include "base/strings/stringprintf.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010016#include "base/strings/utf_string_conversions.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000017#include "base/values.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000018#include "chrome/browser/devtools/devtools_window.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000019#include "chrome/browser/extensions/extension_service.h"
20#include "chrome/browser/profiles/profile.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000021#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
Ben Murdoch32409262013-08-07 11:04:47 +010022#include "chrome/browser/ui/webui/theme_source.h"
Ben Murdoch2385ea32013-08-06 11:01:04 +010023#include "chrome/common/pref_names.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000024#include "chrome/common/url_constants.h"
25#include "content/public/browser/browser_thread.h"
26#include "content/public/browser/child_process_data.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000027#include "content/public/browser/devtools_agent_host.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000028#include "content/public/browser/devtools_client_host.h"
29#include "content/public/browser/devtools_manager.h"
30#include "content/public/browser/favicon_status.h"
31#include "content/public/browser/navigation_entry.h"
32#include "content/public/browser/notification_service.h"
33#include "content/public/browser/notification_source.h"
34#include "content/public/browser/notification_types.h"
35#include "content/public/browser/render_process_host.h"
36#include "content/public/browser/render_view_host.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000037#include "content/public/browser/web_contents.h"
38#include "content/public/browser/web_ui.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000039#include "content/public/browser/web_ui_data_source.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000040#include "content/public/browser/web_ui_message_handler.h"
41#include "content/public/browser/worker_service.h"
42#include "content/public/browser/worker_service_observer.h"
43#include "content/public/common/process_type.h"
44#include "grit/browser_resources.h"
45#include "grit/generated_resources.h"
46#include "net/base/escape.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000047#include "net/base/net_errors.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000048#include "ui/base/resource/resource_bundle.h"
49
50using content::BrowserThread;
51using content::ChildProcessData;
52using content::DevToolsAgentHost;
Torne (Richard Coles)58218062012-11-14 11:43:16 +000053using content::DevToolsClientHost;
54using content::DevToolsManager;
55using content::RenderProcessHost;
56using content::RenderViewHost;
57using content::RenderViewHostDelegate;
58using content::RenderWidgetHost;
59using content::WebContents;
60using content::WebUIMessageHandler;
61using content::WorkerService;
62using content::WorkerServiceObserver;
63
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000064namespace {
65
Torne (Richard Coles)58218062012-11-14 11:43:16 +000066static const char kDataFile[] = "targets-data.json";
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000067static const char kAdbPages[] = "adb-pages";
Torne (Richard Coles)58218062012-11-14 11:43:16 +000068
Ben Murdocha3f7b4e2013-07-24 10:36:34 +010069static const char kAppTargetType[] = "app";
Torne (Richard Coles)58218062012-11-14 11:43:16 +000070static const char kExtensionTargetType[] = "extension";
71static const char kPageTargetType[] = "page";
72static const char kWorkerTargetType[] = "worker";
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000073static const char kAdbTargetType[] = "adb_page";
Torne (Richard Coles)58218062012-11-14 11:43:16 +000074
Ben Murdochbbcdd452013-07-25 10:06:34 +010075static const char kInitUICommand[] = "init-ui";
Torne (Richard Coles)58218062012-11-14 11:43:16 +000076static const char kInspectCommand[] = "inspect";
77static const char kTerminateCommand[] = "terminate";
Ben Murdochbb1529c2013-08-08 10:24:53 +010078static const char kReloadCommand[] = "reload";
79static const char kOpenCommand[] = "open";
80
Ben Murdoch2385ea32013-08-06 11:01:04 +010081static const char kPortForwardingEnabledCommand[] =
82 "set-port-forwarding-enabled";
83static const char kPortForwardingConfigCommand[] = "set-port-forwarding-config";
Torne (Richard Coles)58218062012-11-14 11:43:16 +000084
85static const char kTargetTypeField[] = "type";
86static const char kAttachedField[] = "attached";
87static const char kProcessIdField[] = "processId";
88static const char kRouteIdField[] = "routeId";
89static const char kUrlField[] = "url";
90static const char kNameField[] = "name";
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000091static const char kFaviconUrlField[] = "faviconUrl";
Torne (Richard Coles)58218062012-11-14 11:43:16 +000092static const char kPidField[] = "pid";
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000093static const char kAdbSerialField[] = "adbSerial";
94static const char kAdbModelField[] = "adbModel";
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010095static const char kAdbBrowserNameField[] = "adbBrowserName";
Ben Murdochbb1529c2013-08-08 10:24:53 +010096static const char kAdbGlobalIdField[] = "adbGlobalId";
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010097static const char kAdbBrowsersField[] = "browsers";
98static const char kAdbPagesField[] = "pages";
Torne (Richard Coles)58218062012-11-14 11:43:16 +000099
100DictionaryValue* BuildTargetDescriptor(
101 const std::string& target_type,
102 bool attached,
103 const GURL& url,
104 const std::string& name,
105 const GURL& favicon_url,
106 int process_id,
107 int route_id,
108 base::ProcessHandle handle = base::kNullProcessHandle) {
109 DictionaryValue* target_data = new DictionaryValue();
110 target_data->SetString(kTargetTypeField, target_type);
111 target_data->SetBoolean(kAttachedField, attached);
112 target_data->SetInteger(kProcessIdField, process_id);
113 target_data->SetInteger(kRouteIdField, route_id);
114 target_data->SetString(kUrlField, url.spec());
115 target_data->SetString(kNameField, net::EscapeForHTML(name));
116 target_data->SetInteger(kPidField, base::GetProcId(handle));
117 target_data->SetString(kFaviconUrlField, favicon_url.spec());
118
119 return target_data;
120}
121
122bool HasClientHost(RenderViewHost* rvh) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000123 if (!DevToolsAgentHost::HasFor(rvh))
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000124 return false;
125
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000126 scoped_refptr<DevToolsAgentHost> agent(
127 DevToolsAgentHost::GetOrCreateFor(rvh));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100128 return agent->IsAttached();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000129}
130
131DictionaryValue* BuildTargetDescriptor(RenderViewHost* rvh, bool is_tab) {
132 WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
133 std::string title;
134 std::string target_type = is_tab ? kPageTargetType : "";
135 GURL url;
136 GURL favicon_url;
137 if (web_contents) {
138 url = web_contents->GetURL();
139 title = UTF16ToUTF8(web_contents->GetTitle());
140 content::NavigationController& controller = web_contents->GetController();
141 content::NavigationEntry* entry = controller.GetActiveEntry();
142 if (entry != NULL && entry->GetURL().is_valid())
143 favicon_url = entry->GetFavicon().url;
144
145 Profile* profile = Profile::FromBrowserContext(
146 web_contents->GetBrowserContext());
147 if (profile) {
148 ExtensionService* extension_service = profile->GetExtensionService();
149 const extensions::Extension* extension = extension_service->
150 extensions()->GetByID(url.host());
151 if (extension) {
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100152 if (extension->is_hosted_app()
153 || extension->is_legacy_packaged_app()
154 || extension->is_platform_app())
155 target_type = kAppTargetType;
156 else
157 target_type = kExtensionTargetType;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000158 title = extension->name();
159 }
160 }
161 }
162
163 return BuildTargetDescriptor(target_type,
164 HasClientHost(rvh),
165 url,
166 title,
167 favicon_url,
168 rvh->GetProcess()->GetID(),
169 rvh->GetRoutingID());
170}
171
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000172class InspectMessageHandler : public WebUIMessageHandler {
173 public:
Ben Murdochbbcdd452013-07-25 10:06:34 +0100174 explicit InspectMessageHandler(InspectUI* inspect_ui)
175 : inspect_ui_(inspect_ui) {}
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000176 virtual ~InspectMessageHandler() {}
177
178 private:
179 // WebUIMessageHandler implementation.
180 virtual void RegisterMessages() OVERRIDE;
181
Ben Murdochbbcdd452013-07-25 10:06:34 +0100182 void HandleInitUICommand(const ListValue* args);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000183 void HandleInspectCommand(const ListValue* args);
184 void HandleTerminateCommand(const ListValue* args);
Ben Murdochbb1529c2013-08-08 10:24:53 +0100185 void HandleReloadCommand(const ListValue* args);
186 void HandleOpenCommand(const ListValue* args);
Ben Murdoch2385ea32013-08-06 11:01:04 +0100187 void HandlePortForwardingEnabledCommand(const ListValue* args);
188 void HandlePortForwardingConfigCommand(const ListValue* args);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000189
Ben Murdochbb1529c2013-08-08 10:24:53 +0100190 static bool GetProcessAndRouteId(const ListValue* args,
191 int* process_id,
192 int* route_id);
193
194 static bool GetRemotePageId(const ListValue* args, std::string* page_id);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100195
Ben Murdochbbcdd452013-07-25 10:06:34 +0100196 InspectUI* inspect_ui_;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100197
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000198 DISALLOW_COPY_AND_ASSIGN(InspectMessageHandler);
199};
200
201void InspectMessageHandler::RegisterMessages() {
Ben Murdochbbcdd452013-07-25 10:06:34 +0100202 web_ui()->RegisterMessageCallback(kInitUICommand,
203 base::Bind(&InspectMessageHandler::HandleInitUICommand,
204 base::Unretained(this)));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000205 web_ui()->RegisterMessageCallback(kInspectCommand,
206 base::Bind(&InspectMessageHandler::HandleInspectCommand,
207 base::Unretained(this)));
208 web_ui()->RegisterMessageCallback(kTerminateCommand,
209 base::Bind(&InspectMessageHandler::HandleTerminateCommand,
210 base::Unretained(this)));
Ben Murdoch2385ea32013-08-06 11:01:04 +0100211 web_ui()->RegisterMessageCallback(kPortForwardingEnabledCommand,
212 base::Bind(&InspectMessageHandler::HandlePortForwardingEnabledCommand,
213 base::Unretained(this)));
214 web_ui()->RegisterMessageCallback(kPortForwardingConfigCommand,
215 base::Bind(&InspectMessageHandler::HandlePortForwardingConfigCommand,
216 base::Unretained(this)));
Ben Murdochbb1529c2013-08-08 10:24:53 +0100217 web_ui()->RegisterMessageCallback(kReloadCommand,
218 base::Bind(&InspectMessageHandler::HandleReloadCommand,
219 base::Unretained(this)));
220 web_ui()->RegisterMessageCallback(kOpenCommand,
221 base::Bind(&InspectMessageHandler::HandleOpenCommand,
222 base::Unretained(this)));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000223}
224
Ben Murdochbbcdd452013-07-25 10:06:34 +0100225void InspectMessageHandler::HandleInitUICommand(const ListValue*) {
226 inspect_ui_->InitUI();
227}
228
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000229void InspectMessageHandler::HandleInspectCommand(const ListValue* args) {
Ben Murdochbbcdd452013-07-25 10:06:34 +0100230 Profile* profile = Profile::FromWebUI(web_ui());
231 if (!profile)
232 return;
233
Ben Murdochbb1529c2013-08-08 10:24:53 +0100234 std::string page_id;
235 if (GetRemotePageId(args, &page_id)) {
236 inspect_ui_->InspectRemotePage(page_id);
237 return;
238 }
239
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000240 int process_id;
241 int route_id;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100242 if (!GetProcessAndRouteId(args, &process_id, &route_id) || process_id == 0
243 || route_id == 0) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000244 return;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100245 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000246
247 RenderViewHost* rvh = RenderViewHost::FromID(process_id, route_id);
248 if (rvh) {
249 DevToolsWindow::OpenDevToolsWindow(rvh);
250 return;
251 }
252
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000253 scoped_refptr<DevToolsAgentHost> agent_host(
254 DevToolsAgentHost::GetForWorker(process_id, route_id));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100255 if (!agent_host.get())
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100256 return;
257
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100258 DevToolsWindow::OpenDevToolsWindowForWorker(profile, agent_host.get());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000259}
260
261static void TerminateWorker(int process_id, int route_id) {
262 WorkerService::GetInstance()->TerminateWorker(process_id, route_id);
263}
264
265void InspectMessageHandler::HandleTerminateCommand(const ListValue* args) {
Ben Murdochbb1529c2013-08-08 10:24:53 +0100266 std::string page_id;
267 if (GetRemotePageId(args, &page_id)) {
268 inspect_ui_->CloseRemotePage(page_id);
269 return;
270 }
271
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000272 int process_id;
273 int route_id;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100274 if (!GetProcessAndRouteId(args, &process_id, &route_id))
275 return;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000276
277 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
278 base::Bind(&TerminateWorker, process_id, route_id));
279}
280
Ben Murdochbb1529c2013-08-08 10:24:53 +0100281void InspectMessageHandler::HandleReloadCommand(const ListValue* args) {
282 std::string page_id;
283 if (GetRemotePageId(args, &page_id))
284 inspect_ui_->ReloadRemotePage(page_id);
285}
286
287void InspectMessageHandler::HandleOpenCommand(const ListValue* args) {
288 std::string browser_id;
289 std::string url;
290 if (args->GetSize() == 2 &&
291 args->GetString(0, &browser_id) &&
292 args->GetString(1, &url)) {
293 inspect_ui_->OpenRemotePage(browser_id, url);
294 }
295}
296
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100297bool InspectMessageHandler::GetProcessAndRouteId(const ListValue* args,
298 int* process_id,
299 int* route_id) {
300 const DictionaryValue* data;
301 if (args->GetSize() == 1 && args->GetDictionary(0, &data) &&
302 data->GetInteger(kProcessIdField, process_id) &&
303 data->GetInteger(kRouteIdField, route_id)) {
304 return true;
305 }
306 return false;
307}
308
Ben Murdoch2385ea32013-08-06 11:01:04 +0100309void InspectMessageHandler::HandlePortForwardingEnabledCommand(
310 const ListValue* args) {
311 Profile* profile = Profile::FromWebUI(web_ui());
312 if (!profile)
313 return;
314
315 bool enabled;
316 if (args->GetSize() == 1 && args->GetBoolean(0, &enabled)) {
317 profile->GetPrefs()->SetBoolean(
318 prefs::kDevToolsPortForwardingEnabled, enabled);
319 }
320}
321
322void InspectMessageHandler::HandlePortForwardingConfigCommand(
323 const ListValue* args) {
324 Profile* profile = Profile::FromWebUI(web_ui());
325 if (!profile)
326 return;
327
328 const DictionaryValue* dict_src;
329 if (args->GetSize() == 1 && args->GetDictionary(0, &dict_src))
330 profile->GetPrefs()->Set(prefs::kDevToolsPortForwardingConfig, *dict_src);
331}
332
Ben Murdochbb1529c2013-08-08 10:24:53 +0100333bool InspectMessageHandler::GetRemotePageId(const ListValue* args,
334 std::string* page_id) {
335 const DictionaryValue* data;
336 if (args->GetSize() == 1 && args->GetDictionary(0, &data) &&
337 data->GetString(kAdbGlobalIdField, page_id)) {
338 return true;
339 }
340 return false;
341}
342
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000343} // namespace
344
345class InspectUI::WorkerCreationDestructionListener
346 : public WorkerServiceObserver,
347 public base::RefCountedThreadSafe<WorkerCreationDestructionListener> {
348 public:
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100349 WorkerCreationDestructionListener()
350 : discovery_ui_(NULL) {}
351
352 void Init(InspectUI* workers_ui) {
353 DCHECK(workers_ui);
354 DCHECK(!discovery_ui_);
355 discovery_ui_ = workers_ui;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000356 BrowserThread::PostTask(
357 BrowserThread::IO, FROM_HERE,
358 base::Bind(&WorkerCreationDestructionListener::RegisterObserver,
359 this));
360 }
361
362 void InspectUIDestroyed() {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100363 DCHECK(discovery_ui_);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000364 discovery_ui_ = NULL;
365 BrowserThread::PostTask(
366 BrowserThread::IO, FROM_HERE,
367 base::Bind(&WorkerCreationDestructionListener::UnregisterObserver,
368 this));
369 }
370
Ben Murdochbbcdd452013-07-25 10:06:34 +0100371 void InitUI() {
372 BrowserThread::PostTask(
373 BrowserThread::IO, FROM_HERE,
374 base::Bind(&WorkerCreationDestructionListener::CollectWorkersData,
375 this));
376 }
377
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000378 private:
379 friend class base::RefCountedThreadSafe<WorkerCreationDestructionListener>;
380 virtual ~WorkerCreationDestructionListener() {}
381
382 virtual void WorkerCreated(
383 const GURL& url,
384 const string16& name,
385 int process_id,
386 int route_id) OVERRIDE {
Ben Murdochbbcdd452013-07-25 10:06:34 +0100387 CollectWorkersData();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000388 }
389
390 virtual void WorkerDestroyed(int process_id, int route_id) OVERRIDE {
Ben Murdochbbcdd452013-07-25 10:06:34 +0100391 CollectWorkersData();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000392 }
393
Ben Murdochbbcdd452013-07-25 10:06:34 +0100394 void CollectWorkersData() {
395 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
396 scoped_ptr<ListValue> target_list(new ListValue());
397 std::vector<WorkerService::WorkerInfo> worker_info =
398 WorkerService::GetInstance()->GetWorkers();
399 for (size_t i = 0; i < worker_info.size(); ++i) {
400 target_list->Append(BuildTargetDescriptor(
401 kWorkerTargetType,
402 false,
403 worker_info[i].url,
404 UTF16ToUTF8(worker_info[i].name),
405 GURL(),
406 worker_info[i].process_id,
407 worker_info[i].route_id,
408 worker_info[i].handle));
409 }
410
411 BrowserThread::PostTask(
412 BrowserThread::UI, FROM_HERE,
413 base::Bind(&WorkerCreationDestructionListener::PopulateWorkersList,
414 this, base::Owned(target_list.release())));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000415 }
416
417 void RegisterObserver() {
418 WorkerService::GetInstance()->AddObserver(this);
419 }
420
421 void UnregisterObserver() {
422 WorkerService::GetInstance()->RemoveObserver(this);
423 }
424
Ben Murdochbbcdd452013-07-25 10:06:34 +0100425 void PopulateWorkersList(ListValue* target_list) {
426 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
427 if (discovery_ui_) {
428 discovery_ui_->web_ui()->CallJavascriptFunction(
429 "populateWorkersList", *target_list);
430 }
431 }
432
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000433 InspectUI* discovery_ui_;
434};
435
436InspectUI::InspectUI(content::WebUI* web_ui)
Ben Murdochbbcdd452013-07-25 10:06:34 +0100437 : WebUIController(web_ui) {
438 web_ui->AddMessageHandler(new InspectMessageHandler(this));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000439 Profile* profile = Profile::FromWebUI(web_ui);
Ben Murdochbbcdd452013-07-25 10:06:34 +0100440 content::WebUIDataSource::Add(profile, CreateInspectUIHTMLSource());
Ben Murdoch32409262013-08-07 11:04:47 +0100441
442 // Set up the chrome://theme/ source.
443 ThemeSource* theme = new ThemeSource(profile);
444 content::URLDataSource::Add(profile, theme);
Ben Murdochbbcdd452013-07-25 10:06:34 +0100445}
446
447InspectUI::~InspectUI() {
448 StopListeningNotifications();
449}
450
451void InspectUI::InitUI() {
452 StartListeningNotifications();
453 PopulateLists();
Ben Murdoch2385ea32013-08-06 11:01:04 +0100454 UpdatePortForwardingEnabled();
455 UpdatePortForwardingConfig();
Ben Murdochbbcdd452013-07-25 10:06:34 +0100456 observer_->InitUI();
457}
458
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100459void InspectUI::InspectRemotePage(const std::string& id) {
460 RemotePages::iterator it = remote_pages_.find(id);
461 if (it != remote_pages_.end()) {
462 Profile* profile = Profile::FromWebUI(web_ui());
463 it->second->Inspect(profile);
464 }
465}
466
Ben Murdochbb1529c2013-08-08 10:24:53 +0100467void InspectUI::ReloadRemotePage(const std::string& id) {
468 RemotePages::iterator it = remote_pages_.find(id);
469 if (it != remote_pages_.end())
470 it->second->Reload();
471}
472
473void InspectUI::CloseRemotePage(const std::string& id) {
474 RemotePages::iterator it = remote_pages_.find(id);
475 if (it != remote_pages_.end())
476 it->second->Close();
477}
478
479void InspectUI::OpenRemotePage(const std::string& browser_id,
480 const std::string& url) {
481 GURL gurl(url);
482 if (!gurl.is_valid()) {
483 gurl = GURL("http://" + url);
484 if (!gurl.is_valid())
485 return;
486 }
487 RemoteBrowsers::iterator it = remote_browsers_.find(browser_id);
488 if (it != remote_browsers_.end())
489 it->second->Open(gurl.spec());
490}
491
Ben Murdochbbcdd452013-07-25 10:06:34 +0100492void InspectUI::PopulateLists() {
493 std::set<RenderViewHost*> tab_rvhs;
494 for (TabContentsIterator it; !it.done(); it.Next())
495 tab_rvhs.insert(it->GetRenderViewHost());
496
497 scoped_ptr<ListValue> target_list(new ListValue());
498
499 std::vector<RenderViewHost*> rvh_vector =
500 DevToolsAgentHost::GetValidRenderViewHosts();
501
502 for (std::vector<RenderViewHost*>::iterator it(rvh_vector.begin());
503 it != rvh_vector.end(); it++) {
504 bool is_tab = tab_rvhs.find(*it) != tab_rvhs.end();
505 target_list->Append(BuildTargetDescriptor(*it, is_tab));
506 }
507 web_ui()->CallJavascriptFunction("populateLists", *target_list.get());
508}
509
510void InspectUI::Observe(int type,
511 const content::NotificationSource& source,
512 const content::NotificationDetails& details) {
513 if (source != content::Source<WebContents>(web_ui()->GetWebContents()))
514 PopulateLists();
515 else if (type == content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED)
516 StopListeningNotifications();
517}
518
519void InspectUI::StartListeningNotifications() {
Ben Murdoch558790d2013-07-30 15:19:42 +0100520 if (observer_)
521 return;
522
Ben Murdochbbcdd452013-07-25 10:06:34 +0100523 observer_ = new WorkerCreationDestructionListener();
524 observer_->Init(this);
525
526 Profile* profile = Profile::FromWebUI(web_ui());
Ben Murdoch558790d2013-07-30 15:19:42 +0100527 DevToolsAdbBridge* adb_bridge =
528 DevToolsAdbBridge::Factory::GetForProfile(profile);
529 if (adb_bridge)
530 adb_bridge->AddListener(this);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000531
Ben Murdoch2385ea32013-08-06 11:01:04 +0100532 notification_registrar_.Add(this,
533 content::NOTIFICATION_WEB_CONTENTS_CONNECTED,
534 content::NotificationService::AllSources());
535 notification_registrar_.Add(this,
536 content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
537 content::NotificationService::AllSources());
538 notification_registrar_.Add(this,
539 content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
540 content::NotificationService::AllSources());
541
542 pref_change_registrar_.Init(profile->GetPrefs());
543 pref_change_registrar_.Add(prefs::kDevToolsPortForwardingEnabled,
544 base::Bind(&InspectUI::UpdatePortForwardingEnabled,
545 base::Unretained(this)));
546 pref_change_registrar_.Add(prefs::kDevToolsPortForwardingConfig,
547 base::Bind(&InspectUI::UpdatePortForwardingConfig,
548 base::Unretained(this)));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000549}
550
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000551void InspectUI::StopListeningNotifications()
552{
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100553 if (!observer_.get())
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000554 return;
Ben Murdoch558790d2013-07-30 15:19:42 +0100555 Profile* profile = Profile::FromWebUI(web_ui());
556 DevToolsAdbBridge* adb_bridge =
557 DevToolsAdbBridge::Factory::GetForProfile(profile);
558 if (adb_bridge)
559 adb_bridge->RemoveListener(this);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000560 observer_->InspectUIDestroyed();
561 observer_ = NULL;
Ben Murdoch2385ea32013-08-06 11:01:04 +0100562 notification_registrar_.RemoveAll();
563 pref_change_registrar_.RemoveAll();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000564}
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000565
566content::WebUIDataSource* InspectUI::CreateInspectUIHTMLSource() {
567 content::WebUIDataSource* source =
568 content::WebUIDataSource::Create(chrome::kChromeUIInspectHost);
569 source->AddResourcePath("inspect.css", IDR_INSPECT_CSS);
570 source->AddResourcePath("inspect.js", IDR_INSPECT_JS);
571 source->SetDefaultResource(IDR_INSPECT_HTML);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000572 return source;
573}
574
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100575void InspectUI::RemoteDevicesChanged(
576 DevToolsAdbBridge::RemoteDevices* devices) {
Ben Murdochbb1529c2013-08-08 10:24:53 +0100577 remote_browsers_.clear();
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100578 remote_pages_.clear();
579 ListValue device_list;
580 for (DevToolsAdbBridge::RemoteDevices::iterator dit = devices->begin();
581 dit != devices->end(); ++dit) {
Ben Murdochbb1529c2013-08-08 10:24:53 +0100582 DevToolsAdbBridge::RemoteDevice* device = dit->get();
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100583 DictionaryValue* device_data = new DictionaryValue();
Ben Murdochbb1529c2013-08-08 10:24:53 +0100584 device_data->SetString(kAdbModelField, device->model());
585 device_data->SetString(kAdbSerialField, device->serial());
586 std::string device_id = base::StringPrintf(
587 "device:%s",
588 device->serial().c_str());
589 device_data->SetString(kAdbGlobalIdField, device_id);
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100590 ListValue* browser_list = new ListValue();
591 device_data->Set(kAdbBrowsersField, browser_list);
592
Ben Murdochbb1529c2013-08-08 10:24:53 +0100593 DevToolsAdbBridge::RemoteBrowsers& browsers = device->browsers();
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100594 for (DevToolsAdbBridge::RemoteBrowsers::iterator bit =
595 browsers.begin(); bit != browsers.end(); ++bit) {
Ben Murdochbb1529c2013-08-08 10:24:53 +0100596 DevToolsAdbBridge::RemoteBrowser* browser = bit->get();
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100597 DictionaryValue* browser_data = new DictionaryValue();
Ben Murdochbb1529c2013-08-08 10:24:53 +0100598 browser_data->SetString(kAdbBrowserNameField, browser->name());
599 std::string browser_id = base::StringPrintf(
600 "browser:%s:%s:%s",
601 device->serial().c_str(),
602 browser->socket().c_str(),
603 browser->name().c_str());
604 browser_data->SetString(kAdbGlobalIdField, browser_id);
605 remote_browsers_[browser_id] = browser;
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100606 ListValue* page_list = new ListValue();
607 browser_data->Set(kAdbPagesField, page_list);
608
Ben Murdochbb1529c2013-08-08 10:24:53 +0100609 DevToolsAdbBridge::RemotePages& pages = browser->pages();
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100610 for (DevToolsAdbBridge::RemotePages::iterator it =
611 pages.begin(); it != pages.end(); ++it) {
612 DevToolsAdbBridge::RemotePage* page = it->get();
Ben Murdochbb1529c2013-08-08 10:24:53 +0100613 DictionaryValue* page_data = BuildTargetDescriptor(
614 kAdbTargetType, page->attached(),
615 GURL(page->url()), page->title(), GURL(page->favicon_url()),
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100616 0, 0);
Ben Murdochbb1529c2013-08-08 10:24:53 +0100617 std::string page_id = base::StringPrintf("page:%s:%s:%s",
618 device->serial().c_str(),
619 browser->socket().c_str(),
620 page->id().c_str());
621 page_data->SetString(kAdbGlobalIdField, page_id);
622 remote_pages_[page_id] = page;
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100623 page_list->Append(page_data);
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100624 }
625 browser_list->Append(browser_data);
626 }
627 device_list.Append(device_data);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000628 }
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100629 web_ui()->CallJavascriptFunction("populateDeviceLists", device_list);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000630}
Ben Murdoch2385ea32013-08-06 11:01:04 +0100631
632void InspectUI::UpdatePortForwardingEnabled() {
633 Profile* profile = Profile::FromWebUI(web_ui());
634 const base::Value* value = profile->GetPrefs()->FindPreference(
635 prefs::kDevToolsPortForwardingEnabled)->GetValue();
636 web_ui()->CallJavascriptFunction("updatePortForwardingEnabled", *value);
637
638}
639
640void InspectUI::UpdatePortForwardingConfig() {
641 Profile* profile = Profile::FromWebUI(web_ui());
642 const base::Value* value = profile->GetPrefs()->FindPreference(
643 prefs::kDevToolsPortForwardingConfig)->GetValue();
644 web_ui()->CallJavascriptFunction("updatePortForwardingConfig", *value);
645}