inspect_ui.cc revision 58537e28ecd584eab876aee8be7156509866d23a
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/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" 13#include "base/strings/string_number_conversions.h" 14#include "base/strings/string_util.h" 15#include "base/strings/stringprintf.h" 16#include "base/strings/utf_string_conversions.h" 17#include "base/values.h" 18#include "chrome/browser/devtools/devtools_window.h" 19#include "chrome/browser/extensions/extension_service.h" 20#include "chrome/browser/profiles/profile.h" 21#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h" 22#include "chrome/browser/ui/webui/theme_source.h" 23#include "chrome/common/pref_names.h" 24#include "chrome/common/url_constants.h" 25#include "content/public/browser/browser_child_process_observer.h" 26#include "content/public/browser/browser_thread.h" 27#include "content/public/browser/child_process_data.h" 28#include "content/public/browser/devtools_agent_host.h" 29#include "content/public/browser/devtools_client_host.h" 30#include "content/public/browser/devtools_manager.h" 31#include "content/public/browser/favicon_status.h" 32#include "content/public/browser/navigation_entry.h" 33#include "content/public/browser/notification_service.h" 34#include "content/public/browser/notification_source.h" 35#include "content/public/browser/notification_types.h" 36#include "content/public/browser/render_process_host.h" 37#include "content/public/browser/render_view_host.h" 38#include "content/public/browser/web_contents.h" 39#include "content/public/browser/web_ui.h" 40#include "content/public/browser/web_ui_data_source.h" 41#include "content/public/browser/web_ui_message_handler.h" 42#include "content/public/browser/worker_service.h" 43#include "content/public/browser/worker_service_observer.h" 44#include "content/public/common/process_type.h" 45#include "grit/browser_resources.h" 46#include "grit/generated_resources.h" 47#include "net/base/escape.h" 48#include "net/base/net_errors.h" 49#include "ui/base/resource/resource_bundle.h" 50 51using content::BrowserThread; 52using content::ChildProcessData; 53using content::DevToolsAgentHost; 54using content::DevToolsClientHost; 55using content::DevToolsManager; 56using content::RenderProcessHost; 57using content::RenderViewHost; 58using content::RenderViewHostDelegate; 59using content::RenderWidgetHost; 60using content::WebContents; 61using content::WebUIMessageHandler; 62using content::WorkerService; 63using content::WorkerServiceObserver; 64 65namespace { 66 67static const char kDataFile[] = "targets-data.json"; 68static const char kAdbPages[] = "adb-pages"; 69 70static const char kAppTargetType[] = "app"; 71static const char kExtensionTargetType[] = "extension"; 72static const char kPageTargetType[] = "page"; 73static const char kWorkerTargetType[] = "worker"; 74static const char kAdbTargetType[] = "adb_page"; 75 76static const char kInitUICommand[] = "init-ui"; 77static const char kInspectCommand[] = "inspect"; 78static const char kActivateCommand[] = "activate"; 79static const char kTerminateCommand[] = "terminate"; 80static const char kReloadCommand[] = "reload"; 81static const char kOpenCommand[] = "open"; 82 83static const char kPortForwardingEnabledCommand[] = 84 "set-port-forwarding-enabled"; 85static const char kPortForwardingConfigCommand[] = "set-port-forwarding-config"; 86 87static const char kPortForwardingDefaultPort[] = "8080"; 88static const char kPortForwardingDefaultLocation[] = "localhost:8080"; 89 90static const char kTargetTypeField[] = "type"; 91static const char kAttachedField[] = "attached"; 92static const char kProcessIdField[] = "processId"; 93static const char kRouteIdField[] = "routeId"; 94static const char kUrlField[] = "url"; 95static const char kNameField[] = "name"; 96static const char kFaviconUrlField[] = "faviconUrl"; 97static const char kDescription[] = "description"; 98static const char kPidField[] = "pid"; 99static const char kAdbSerialField[] = "adbSerial"; 100static const char kAdbModelField[] = "adbModel"; 101static const char kAdbBrowserProductField[] = "adbBrowserProduct"; 102static const char kAdbBrowserPackageField[] = "adbBrowserPackage"; 103static const char kAdbBrowserVersionField[] = "adbBrowserVersion"; 104static const char kAdbGlobalIdField[] = "adbGlobalId"; 105static const char kAdbBrowsersField[] = "browsers"; 106static const char kAdbPagesField[] = "pages"; 107static const char kAdbPortStatus[] = "adbPortStatus"; 108static const char kGuestList[] = "guests"; 109 110DictionaryValue* BuildTargetDescriptor( 111 const std::string& target_type, 112 bool attached, 113 const GURL& url, 114 const std::string& name, 115 const GURL& favicon_url, 116 const std::string& description, 117 int process_id, 118 int route_id, 119 base::ProcessHandle handle = base::kNullProcessHandle) { 120 DictionaryValue* target_data = new DictionaryValue(); 121 target_data->SetString(kTargetTypeField, target_type); 122 target_data->SetBoolean(kAttachedField, attached); 123 target_data->SetInteger(kProcessIdField, process_id); 124 target_data->SetInteger(kRouteIdField, route_id); 125 target_data->SetString(kUrlField, url.spec()); 126 target_data->SetString(kNameField, net::EscapeForHTML(name)); 127 target_data->SetInteger(kPidField, base::GetProcId(handle)); 128 target_data->SetString(kFaviconUrlField, favicon_url.spec()); 129 target_data->SetString(kDescription, description); 130 131 return target_data; 132} 133 134bool HasClientHost(RenderViewHost* rvh) { 135 if (!DevToolsAgentHost::HasFor(rvh)) 136 return false; 137 138 scoped_refptr<DevToolsAgentHost> agent( 139 DevToolsAgentHost::GetOrCreateFor(rvh)); 140 return agent->IsAttached(); 141} 142 143bool HasClientHost(int process_id, int route_id) { 144 if (!DevToolsAgentHost::HasForWorker(process_id, route_id)) 145 return false; 146 147 scoped_refptr<DevToolsAgentHost> agent( 148 DevToolsAgentHost::GetForWorker(process_id, route_id)); 149 return agent->IsAttached(); 150} 151 152DictionaryValue* BuildTargetDescriptor(RenderViewHost* rvh, bool is_tab) { 153 WebContents* web_contents = WebContents::FromRenderViewHost(rvh); 154 std::string title; 155 std::string target_type = is_tab ? kPageTargetType : ""; 156 GURL url; 157 GURL favicon_url; 158 if (web_contents) { 159 url = web_contents->GetURL(); 160 title = UTF16ToUTF8(web_contents->GetTitle()); 161 content::NavigationController& controller = web_contents->GetController(); 162 content::NavigationEntry* entry = controller.GetActiveEntry(); 163 if (entry != NULL && entry->GetURL().is_valid()) 164 favicon_url = entry->GetFavicon().url; 165 166 Profile* profile = Profile::FromBrowserContext( 167 web_contents->GetBrowserContext()); 168 if (profile) { 169 ExtensionService* extension_service = profile->GetExtensionService(); 170 const extensions::Extension* extension = extension_service-> 171 extensions()->GetByID(url.host()); 172 if (extension) { 173 if (extension->is_hosted_app() 174 || extension->is_legacy_packaged_app() 175 || extension->is_platform_app()) 176 target_type = kAppTargetType; 177 else 178 target_type = kExtensionTargetType; 179 title = extension->name(); 180 } 181 } 182 } 183 184 return BuildTargetDescriptor(target_type, 185 HasClientHost(rvh), 186 url, 187 title, 188 favicon_url, 189 "", 190 rvh->GetProcess()->GetID(), 191 rvh->GetRoutingID()); 192} 193 194class InspectMessageHandler : public WebUIMessageHandler { 195 public: 196 explicit InspectMessageHandler(InspectUI* inspect_ui) 197 : inspect_ui_(inspect_ui) {} 198 virtual ~InspectMessageHandler() {} 199 200 private: 201 // WebUIMessageHandler implementation. 202 virtual void RegisterMessages() OVERRIDE; 203 204 void HandleInitUICommand(const ListValue* args); 205 void HandleInspectCommand(const ListValue* args); 206 void HandleActivateCommand(const ListValue* args); 207 void HandleTerminateCommand(const ListValue* args); 208 void HandleReloadCommand(const ListValue* args); 209 void HandleOpenCommand(const ListValue* args); 210 void HandlePortForwardingEnabledCommand(const ListValue* args); 211 void HandlePortForwardingConfigCommand(const ListValue* args); 212 213 static bool GetProcessAndRouteId(const ListValue* args, 214 int* process_id, 215 int* route_id); 216 217 static bool GetRemotePageId(const ListValue* args, std::string* page_id); 218 219 InspectUI* inspect_ui_; 220 221 DISALLOW_COPY_AND_ASSIGN(InspectMessageHandler); 222}; 223 224void InspectMessageHandler::RegisterMessages() { 225 web_ui()->RegisterMessageCallback(kInitUICommand, 226 base::Bind(&InspectMessageHandler::HandleInitUICommand, 227 base::Unretained(this))); 228 web_ui()->RegisterMessageCallback(kInspectCommand, 229 base::Bind(&InspectMessageHandler::HandleInspectCommand, 230 base::Unretained(this))); 231 web_ui()->RegisterMessageCallback(kActivateCommand, 232 base::Bind(&InspectMessageHandler::HandleActivateCommand, 233 base::Unretained(this))); 234 web_ui()->RegisterMessageCallback(kTerminateCommand, 235 base::Bind(&InspectMessageHandler::HandleTerminateCommand, 236 base::Unretained(this))); 237 web_ui()->RegisterMessageCallback(kPortForwardingEnabledCommand, 238 base::Bind(&InspectMessageHandler::HandlePortForwardingEnabledCommand, 239 base::Unretained(this))); 240 web_ui()->RegisterMessageCallback(kPortForwardingConfigCommand, 241 base::Bind(&InspectMessageHandler::HandlePortForwardingConfigCommand, 242 base::Unretained(this))); 243 web_ui()->RegisterMessageCallback(kReloadCommand, 244 base::Bind(&InspectMessageHandler::HandleReloadCommand, 245 base::Unretained(this))); 246 web_ui()->RegisterMessageCallback(kOpenCommand, 247 base::Bind(&InspectMessageHandler::HandleOpenCommand, 248 base::Unretained(this))); 249} 250 251void InspectMessageHandler::HandleInitUICommand(const ListValue*) { 252 inspect_ui_->InitUI(); 253} 254 255void InspectMessageHandler::HandleInspectCommand(const ListValue* args) { 256 Profile* profile = Profile::FromWebUI(web_ui()); 257 if (!profile) 258 return; 259 260 std::string page_id; 261 if (GetRemotePageId(args, &page_id)) { 262 inspect_ui_->InspectRemotePage(page_id); 263 return; 264 } 265 266 int process_id; 267 int route_id; 268 if (!GetProcessAndRouteId(args, &process_id, &route_id) || process_id == 0 269 || route_id == 0) { 270 return; 271 } 272 273 RenderViewHost* rvh = RenderViewHost::FromID(process_id, route_id); 274 if (rvh) { 275 DevToolsWindow::OpenDevToolsWindow(rvh); 276 return; 277 } 278 279 scoped_refptr<DevToolsAgentHost> agent_host( 280 DevToolsAgentHost::GetForWorker(process_id, route_id)); 281 if (!agent_host.get()) 282 return; 283 284 DevToolsWindow::OpenDevToolsWindowForWorker(profile, agent_host.get()); 285} 286 287void InspectMessageHandler::HandleActivateCommand(const ListValue* args) { 288 std::string page_id; 289 if (GetRemotePageId(args, &page_id)) 290 inspect_ui_->ActivateRemotePage(page_id); 291} 292 293static void TerminateWorker(int process_id, int route_id) { 294 WorkerService::GetInstance()->TerminateWorker(process_id, route_id); 295} 296 297void InspectMessageHandler::HandleTerminateCommand(const ListValue* args) { 298 std::string page_id; 299 if (GetRemotePageId(args, &page_id)) { 300 inspect_ui_->CloseRemotePage(page_id); 301 return; 302 } 303 304 int process_id; 305 int route_id; 306 if (!GetProcessAndRouteId(args, &process_id, &route_id)) 307 return; 308 309 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 310 base::Bind(&TerminateWorker, process_id, route_id)); 311} 312 313void InspectMessageHandler::HandleReloadCommand(const ListValue* args) { 314 std::string page_id; 315 if (GetRemotePageId(args, &page_id)) 316 inspect_ui_->ReloadRemotePage(page_id); 317} 318 319void InspectMessageHandler::HandleOpenCommand(const ListValue* args) { 320 std::string browser_id; 321 std::string url; 322 if (args->GetSize() == 2 && 323 args->GetString(0, &browser_id) && 324 args->GetString(1, &url)) { 325 inspect_ui_->OpenRemotePage(browser_id, url); 326 } 327} 328 329bool InspectMessageHandler::GetProcessAndRouteId(const ListValue* args, 330 int* process_id, 331 int* route_id) { 332 const DictionaryValue* data; 333 if (args->GetSize() == 1 && args->GetDictionary(0, &data) && 334 data->GetInteger(kProcessIdField, process_id) && 335 data->GetInteger(kRouteIdField, route_id)) { 336 return true; 337 } 338 return false; 339} 340 341void InspectMessageHandler::HandlePortForwardingEnabledCommand( 342 const ListValue* args) { 343 Profile* profile = Profile::FromWebUI(web_ui()); 344 if (!profile) 345 return; 346 347 bool enabled; 348 if (args->GetSize() == 1 && args->GetBoolean(0, &enabled)) { 349 profile->GetPrefs()->SetBoolean( 350 prefs::kDevToolsPortForwardingEnabled, enabled); 351 } 352} 353 354void InspectMessageHandler::HandlePortForwardingConfigCommand( 355 const ListValue* args) { 356 Profile* profile = Profile::FromWebUI(web_ui()); 357 if (!profile) 358 return; 359 360 const DictionaryValue* dict_src; 361 if (args->GetSize() == 1 && args->GetDictionary(0, &dict_src)) 362 profile->GetPrefs()->Set(prefs::kDevToolsPortForwardingConfig, *dict_src); 363} 364 365bool InspectMessageHandler::GetRemotePageId(const ListValue* args, 366 std::string* page_id) { 367 const DictionaryValue* data; 368 if (args->GetSize() == 1 && args->GetDictionary(0, &data) && 369 data->GetString(kAdbGlobalIdField, page_id)) { 370 return true; 371 } 372 return false; 373} 374 375} // namespace 376 377class InspectUI::WorkerCreationDestructionListener 378 : public WorkerServiceObserver, 379 public content::BrowserChildProcessObserver, 380 public base::RefCountedThreadSafe<WorkerCreationDestructionListener> { 381 public: 382 WorkerCreationDestructionListener() 383 : discovery_ui_(NULL) {} 384 385 void Init(InspectUI* workers_ui) { 386 DCHECK(workers_ui); 387 DCHECK(!discovery_ui_); 388 discovery_ui_ = workers_ui; 389 BrowserChildProcessObserver::Add(this); 390 BrowserThread::PostTask( 391 BrowserThread::IO, FROM_HERE, 392 base::Bind(&WorkerCreationDestructionListener::RegisterObserver, 393 this)); 394 } 395 396 void InspectUIDestroyed() { 397 DCHECK(discovery_ui_); 398 discovery_ui_ = NULL; 399 BrowserChildProcessObserver::Remove(this); 400 BrowserThread::PostTask( 401 BrowserThread::IO, FROM_HERE, 402 base::Bind(&WorkerCreationDestructionListener::UnregisterObserver, 403 this)); 404 } 405 406 void UpdateUI() { 407 BrowserThread::PostTask( 408 BrowserThread::IO, FROM_HERE, 409 base::Bind(&WorkerCreationDestructionListener::CollectWorkersData, 410 this)); 411 } 412 413 private: 414 friend class base::RefCountedThreadSafe<WorkerCreationDestructionListener>; 415 virtual ~WorkerCreationDestructionListener() {} 416 417 virtual void WorkerCreated( 418 const GURL& url, 419 const string16& name, 420 int process_id, 421 int route_id) OVERRIDE { 422 CollectWorkersData(); 423 } 424 425 virtual void WorkerDestroyed(int process_id, int route_id) OVERRIDE { 426 CollectWorkersData(); 427 } 428 429 virtual void BrowserChildProcessHostConnected( 430 const content::ChildProcessData& data) OVERRIDE { 431 if (data.process_type == content::PROCESS_TYPE_WORKER) 432 UpdateUI(); 433 } 434 435 virtual void BrowserChildProcessHostDisconnected( 436 const content::ChildProcessData& data) OVERRIDE { 437 if (data.process_type == content::PROCESS_TYPE_WORKER) 438 UpdateUI(); 439 } 440 441 void CollectWorkersData() { 442 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 443 BrowserThread::PostTask( 444 BrowserThread::UI, FROM_HERE, 445 base::Bind(&WorkerCreationDestructionListener::PopulateWorkersList, 446 this, WorkerService::GetInstance()->GetWorkers())); 447 } 448 449 void RegisterObserver() { 450 WorkerService::GetInstance()->AddObserver(this); 451 } 452 453 void UnregisterObserver() { 454 WorkerService::GetInstance()->RemoveObserver(this); 455 } 456 457 void PopulateWorkersList( 458 const std::vector<WorkerService::WorkerInfo>& worker_info) { 459 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 460 if (!discovery_ui_) 461 return; 462 463 ListValue target_list; 464 for (size_t i = 0; i < worker_info.size(); ++i) { 465 if (!worker_info[i].handle) 466 continue; // Process is still being created. 467 target_list.Append(BuildTargetDescriptor( 468 kWorkerTargetType, 469 HasClientHost(worker_info[i].process_id, worker_info[i].route_id), 470 worker_info[i].url, 471 UTF16ToUTF8(worker_info[i].name), 472 GURL(), 473 "", 474 worker_info[i].process_id, 475 worker_info[i].route_id, 476 worker_info[i].handle)); 477 } 478 discovery_ui_->web_ui()->CallJavascriptFunction( 479 "populateWorkersList", target_list); 480 } 481 482 InspectUI* discovery_ui_; 483}; 484 485InspectUI::InspectUI(content::WebUI* web_ui) 486 : WebUIController(web_ui) { 487 web_ui->AddMessageHandler(new InspectMessageHandler(this)); 488 Profile* profile = Profile::FromWebUI(web_ui); 489 content::WebUIDataSource::Add(profile, CreateInspectUIHTMLSource()); 490 491 // Set up the chrome://theme/ source. 492 ThemeSource* theme = new ThemeSource(profile); 493 content::URLDataSource::Add(profile, theme); 494} 495 496InspectUI::~InspectUI() { 497 StopListeningNotifications(); 498} 499 500void InspectUI::InitUI() { 501 SetPortForwardingDefaults(); 502 StartListeningNotifications(); 503 PopulateLists(); 504 UpdatePortForwardingEnabled(); 505 UpdatePortForwardingConfig(); 506 observer_->UpdateUI(); 507} 508 509void InspectUI::InspectRemotePage(const std::string& id) { 510 RemotePages::iterator it = remote_pages_.find(id); 511 if (it != remote_pages_.end()) { 512 Profile* profile = Profile::FromWebUI(web_ui()); 513 it->second->Inspect(profile); 514 } 515} 516 517void InspectUI::ActivateRemotePage(const std::string& id) { 518 RemotePages::iterator it = remote_pages_.find(id); 519 if (it != remote_pages_.end()) 520 it->second->Activate(); 521} 522 523void InspectUI::ReloadRemotePage(const std::string& id) { 524 RemotePages::iterator it = remote_pages_.find(id); 525 if (it != remote_pages_.end()) 526 it->second->Reload(); 527} 528 529void InspectUI::CloseRemotePage(const std::string& id) { 530 RemotePages::iterator it = remote_pages_.find(id); 531 if (it != remote_pages_.end()) 532 it->second->Close(); 533} 534 535void InspectUI::OpenRemotePage(const std::string& browser_id, 536 const std::string& url) { 537 GURL gurl(url); 538 if (!gurl.is_valid()) { 539 gurl = GURL("http://" + url); 540 if (!gurl.is_valid()) 541 return; 542 } 543 RemoteBrowsers::iterator it = remote_browsers_.find(browser_id); 544 if (it != remote_browsers_.end()) 545 it->second->Open(gurl.spec()); 546} 547 548void InspectUI::PopulateLists() { 549 std::set<RenderViewHost*> tab_rvhs; 550 for (TabContentsIterator it; !it.done(); it.Next()) 551 tab_rvhs.insert(it->GetRenderViewHost()); 552 553 scoped_ptr<ListValue> target_list(new ListValue()); 554 555 std::vector<RenderViewHost*> rvh_vector = 556 DevToolsAgentHost::GetValidRenderViewHosts(); 557 558 std::map<WebContents*, DictionaryValue*> description_map; 559 std::vector<WebContents*> guest_contents; 560 561 for (std::vector<RenderViewHost*>::iterator it(rvh_vector.begin()); 562 it != rvh_vector.end(); it++) { 563 bool is_tab = tab_rvhs.find(*it) != tab_rvhs.end(); 564 RenderViewHost* rvh = (*it); 565 WebContents* web_contents = WebContents::FromRenderViewHost(rvh); 566 if (rvh->GetProcess()->IsGuest()) { 567 if (web_contents) 568 guest_contents.push_back(web_contents); 569 } else { 570 DictionaryValue* dictionary = BuildTargetDescriptor(rvh, is_tab); 571 if (web_contents) 572 description_map[web_contents] = dictionary; 573 target_list->Append(dictionary); 574 } 575 } 576 577 // Add the list of guest-views to each of its embedders. 578 for (std::vector<WebContents*>::iterator it(guest_contents.begin()); 579 it != guest_contents.end(); ++it) { 580 WebContents* guest = (*it); 581 WebContents* embedder = guest->GetEmbedderWebContents(); 582 if (embedder && description_map.count(embedder) > 0) { 583 DictionaryValue* description = description_map[embedder]; 584 ListValue* guests = NULL; 585 if (!description->GetList(kGuestList, &guests)) { 586 guests = new ListValue(); 587 description->Set(kGuestList, guests); 588 } 589 RenderViewHost* rvh = guest->GetRenderViewHost(); 590 if (rvh) 591 guests->Append(BuildTargetDescriptor(rvh, false)); 592 } 593 } 594 595 web_ui()->CallJavascriptFunction("populateLists", *target_list.get()); 596} 597 598void InspectUI::Observe(int type, 599 const content::NotificationSource& source, 600 const content::NotificationDetails& details) { 601 if (source != content::Source<WebContents>(web_ui()->GetWebContents())) 602 PopulateLists(); 603 else if (type == content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED) 604 StopListeningNotifications(); 605} 606 607void InspectUI::StartListeningNotifications() { 608 if (observer_) 609 return; 610 611 observer_ = new WorkerCreationDestructionListener(); 612 observer_->Init(this); 613 614 Profile* profile = Profile::FromWebUI(web_ui()); 615 DevToolsAdbBridge* adb_bridge = 616 DevToolsAdbBridge::Factory::GetForProfile(profile); 617 if (adb_bridge) 618 adb_bridge->AddListener(this); 619 620 notification_registrar_.Add(this, 621 content::NOTIFICATION_WEB_CONTENTS_CONNECTED, 622 content::NotificationService::AllSources()); 623 notification_registrar_.Add(this, 624 content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, 625 content::NotificationService::AllSources()); 626 notification_registrar_.Add(this, 627 content::NOTIFICATION_WEB_CONTENTS_DESTROYED, 628 content::NotificationService::AllSources()); 629 630 pref_change_registrar_.Init(profile->GetPrefs()); 631 pref_change_registrar_.Add(prefs::kDevToolsPortForwardingEnabled, 632 base::Bind(&InspectUI::UpdatePortForwardingEnabled, 633 base::Unretained(this))); 634 pref_change_registrar_.Add(prefs::kDevToolsPortForwardingConfig, 635 base::Bind(&InspectUI::UpdatePortForwardingConfig, 636 base::Unretained(this))); 637} 638 639void InspectUI::StopListeningNotifications() 640{ 641 if (!observer_.get()) 642 return; 643 Profile* profile = Profile::FromWebUI(web_ui()); 644 DevToolsAdbBridge* adb_bridge = 645 DevToolsAdbBridge::Factory::GetForProfile(profile); 646 if (adb_bridge) 647 adb_bridge->RemoveListener(this); 648 observer_->InspectUIDestroyed(); 649 observer_ = NULL; 650 notification_registrar_.RemoveAll(); 651 pref_change_registrar_.RemoveAll(); 652} 653 654content::WebUIDataSource* InspectUI::CreateInspectUIHTMLSource() { 655 content::WebUIDataSource* source = 656 content::WebUIDataSource::Create(chrome::kChromeUIInspectHost); 657 source->AddResourcePath("inspect.css", IDR_INSPECT_CSS); 658 source->AddResourcePath("inspect.js", IDR_INSPECT_JS); 659 source->SetDefaultResource(IDR_INSPECT_HTML); 660 return source; 661} 662 663void InspectUI::RemoteDevicesChanged( 664 DevToolsAdbBridge::RemoteDevices* devices) { 665 remote_browsers_.clear(); 666 remote_pages_.clear(); 667 ListValue device_list; 668 for (DevToolsAdbBridge::RemoteDevices::iterator dit = devices->begin(); 669 dit != devices->end(); ++dit) { 670 DevToolsAdbBridge::RemoteDevice* device = dit->get(); 671 DictionaryValue* device_data = new DictionaryValue(); 672 device_data->SetString(kAdbModelField, device->model()); 673 device_data->SetString(kAdbSerialField, device->serial()); 674 std::string device_id = base::StringPrintf( 675 "device:%s", 676 device->serial().c_str()); 677 device_data->SetString(kAdbGlobalIdField, device_id); 678 ListValue* browser_list = new ListValue(); 679 device_data->Set(kAdbBrowsersField, browser_list); 680 681 DevToolsAdbBridge::RemoteBrowsers& browsers = device->browsers(); 682 for (DevToolsAdbBridge::RemoteBrowsers::iterator bit = 683 browsers.begin(); bit != browsers.end(); ++bit) { 684 DevToolsAdbBridge::RemoteBrowser* browser = bit->get(); 685 DictionaryValue* browser_data = new DictionaryValue(); 686 browser_data->SetString(kAdbBrowserProductField, browser->product()); 687 browser_data->SetString(kAdbBrowserPackageField, browser->package()); 688 browser_data->SetString(kAdbBrowserVersionField, browser->version()); 689 std::string browser_id = base::StringPrintf( 690 "browser:%s:%s:%s", 691 device->serial().c_str(), 692 browser->product().c_str(), // Force sorting by product name. 693 browser->socket().c_str()); 694 browser_data->SetString(kAdbGlobalIdField, browser_id); 695 remote_browsers_[browser_id] = browser; 696 ListValue* page_list = new ListValue(); 697 browser_data->Set(kAdbPagesField, page_list); 698 699 DevToolsAdbBridge::RemotePages& pages = browser->pages(); 700 for (DevToolsAdbBridge::RemotePages::iterator it = 701 pages.begin(); it != pages.end(); ++it) { 702 DevToolsAdbBridge::RemotePage* page = it->get(); 703 DictionaryValue* page_data = BuildTargetDescriptor( 704 kAdbTargetType, page->attached(), 705 GURL(page->url()), page->title(), GURL(page->favicon_url()), 706 page->description(), 0, 0); 707 std::string page_id = base::StringPrintf("page:%s:%s:%s", 708 device->serial().c_str(), 709 browser->socket().c_str(), 710 page->id().c_str()); 711 page_data->SetString(kAdbGlobalIdField, page_id); 712 remote_pages_[page_id] = page; 713 page_list->Append(page_data); 714 } 715 browser_list->Append(browser_data); 716 } 717 718 DictionaryValue* port_status_dict = new DictionaryValue(); 719 typedef DevToolsAdbBridge::RemoteDevice::PortStatusMap StatusMap; 720 const StatusMap& port_status = device->port_status(); 721 for (StatusMap::const_iterator it = port_status.begin(); 722 it != port_status.end(); ++it) { 723 port_status_dict->SetInteger( 724 base::StringPrintf("%d", it->first), it->second); 725 } 726 device_data->Set(kAdbPortStatus, port_status_dict); 727 728 device_list.Append(device_data); 729 } 730 web_ui()->CallJavascriptFunction("populateDeviceLists", device_list); 731} 732 733void InspectUI::UpdatePortForwardingEnabled() { 734 web_ui()->CallJavascriptFunction("updatePortForwardingEnabled", 735 *GetPrefValue(prefs::kDevToolsPortForwardingEnabled)); 736 737} 738 739void InspectUI::UpdatePortForwardingConfig() { 740 web_ui()->CallJavascriptFunction("updatePortForwardingConfig", 741 *GetPrefValue(prefs::kDevToolsPortForwardingConfig)); 742} 743 744void InspectUI::SetPortForwardingDefaults() { 745 Profile* profile = Profile::FromWebUI(web_ui()); 746 PrefService* prefs = profile->GetPrefs(); 747 748 bool default_set; 749 if (!GetPrefValue(prefs::kDevToolsPortForwardingDefaultSet)-> 750 GetAsBoolean(&default_set) || default_set) { 751 return; 752 } 753 754 // This is the first chrome://inspect invocation on a fresh profile or after 755 // upgrade from a version that did not have kDevToolsPortForwardingDefaultSet. 756 prefs->SetBoolean(prefs::kDevToolsPortForwardingDefaultSet, true); 757 758 bool enabled; 759 const base::DictionaryValue* config; 760 if (!GetPrefValue(prefs::kDevToolsPortForwardingEnabled)-> 761 GetAsBoolean(&enabled) || 762 !GetPrefValue(prefs::kDevToolsPortForwardingConfig)-> 763 GetAsDictionary(&config)) { 764 return; 765 } 766 767 // Do nothing if user already took explicit action. 768 if (enabled || config->size() != 0) 769 return; 770 771 base::DictionaryValue default_config; 772 default_config.SetString( 773 kPortForwardingDefaultPort, kPortForwardingDefaultLocation); 774 prefs->Set(prefs::kDevToolsPortForwardingConfig, default_config); 775} 776 777const base::Value* InspectUI::GetPrefValue(const char* name) { 778 Profile* profile = Profile::FromWebUI(web_ui()); 779 return profile->GetPrefs()->FindPreference(name)->GetValue(); 780} 781