inspect_ui.cc revision 424c4d7b64af9d0d8fd9624f381f469654d5e3d2
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 kTargetTypeField[] = "type"; 88static const char kAttachedField[] = "attached"; 89static const char kProcessIdField[] = "processId"; 90static const char kRouteIdField[] = "routeId"; 91static const char kUrlField[] = "url"; 92static const char kNameField[] = "name"; 93static const char kFaviconUrlField[] = "faviconUrl"; 94static const char kDescription[] = "description"; 95static const char kPidField[] = "pid"; 96static const char kAdbSerialField[] = "adbSerial"; 97static const char kAdbModelField[] = "adbModel"; 98static const char kAdbBrowserProductField[] = "adbBrowserProduct"; 99static const char kAdbBrowserPackageField[] = "adbBrowserPackage"; 100static const char kAdbBrowserVersionField[] = "adbBrowserVersion"; 101static const char kAdbGlobalIdField[] = "adbGlobalId"; 102static const char kAdbBrowsersField[] = "browsers"; 103static const char kAdbPagesField[] = "pages"; 104static const char kAdbPortStatus[] = "adbPortStatus"; 105 106DictionaryValue* BuildTargetDescriptor( 107 const std::string& target_type, 108 bool attached, 109 const GURL& url, 110 const std::string& name, 111 const GURL& favicon_url, 112 const std::string& description, 113 int process_id, 114 int route_id, 115 base::ProcessHandle handle = base::kNullProcessHandle) { 116 DictionaryValue* target_data = new DictionaryValue(); 117 target_data->SetString(kTargetTypeField, target_type); 118 target_data->SetBoolean(kAttachedField, attached); 119 target_data->SetInteger(kProcessIdField, process_id); 120 target_data->SetInteger(kRouteIdField, route_id); 121 target_data->SetString(kUrlField, url.spec()); 122 target_data->SetString(kNameField, net::EscapeForHTML(name)); 123 target_data->SetInteger(kPidField, base::GetProcId(handle)); 124 target_data->SetString(kFaviconUrlField, favicon_url.spec()); 125 target_data->SetString(kDescription, description); 126 127 return target_data; 128} 129 130bool HasClientHost(RenderViewHost* rvh) { 131 if (!DevToolsAgentHost::HasFor(rvh)) 132 return false; 133 134 scoped_refptr<DevToolsAgentHost> agent( 135 DevToolsAgentHost::GetOrCreateFor(rvh)); 136 return agent->IsAttached(); 137} 138 139bool HasClientHost(int process_id, int route_id) { 140 if (!DevToolsAgentHost::HasForWorker(process_id, route_id)) 141 return false; 142 143 scoped_refptr<DevToolsAgentHost> agent( 144 DevToolsAgentHost::GetForWorker(process_id, route_id)); 145 return agent->IsAttached(); 146} 147 148DictionaryValue* BuildTargetDescriptor(RenderViewHost* rvh, bool is_tab) { 149 WebContents* web_contents = WebContents::FromRenderViewHost(rvh); 150 std::string title; 151 std::string target_type = is_tab ? kPageTargetType : ""; 152 GURL url; 153 GURL favicon_url; 154 if (web_contents) { 155 url = web_contents->GetURL(); 156 title = UTF16ToUTF8(web_contents->GetTitle()); 157 content::NavigationController& controller = web_contents->GetController(); 158 content::NavigationEntry* entry = controller.GetActiveEntry(); 159 if (entry != NULL && entry->GetURL().is_valid()) 160 favicon_url = entry->GetFavicon().url; 161 162 Profile* profile = Profile::FromBrowserContext( 163 web_contents->GetBrowserContext()); 164 if (profile) { 165 ExtensionService* extension_service = profile->GetExtensionService(); 166 const extensions::Extension* extension = extension_service-> 167 extensions()->GetByID(url.host()); 168 if (extension) { 169 if (extension->is_hosted_app() 170 || extension->is_legacy_packaged_app() 171 || extension->is_platform_app()) 172 target_type = kAppTargetType; 173 else 174 target_type = kExtensionTargetType; 175 title = extension->name(); 176 } 177 } 178 } 179 180 return BuildTargetDescriptor(target_type, 181 HasClientHost(rvh), 182 url, 183 title, 184 favicon_url, 185 "", 186 rvh->GetProcess()->GetID(), 187 rvh->GetRoutingID()); 188} 189 190class InspectMessageHandler : public WebUIMessageHandler { 191 public: 192 explicit InspectMessageHandler(InspectUI* inspect_ui) 193 : inspect_ui_(inspect_ui) {} 194 virtual ~InspectMessageHandler() {} 195 196 private: 197 // WebUIMessageHandler implementation. 198 virtual void RegisterMessages() OVERRIDE; 199 200 void HandleInitUICommand(const ListValue* args); 201 void HandleInspectCommand(const ListValue* args); 202 void HandleActivateCommand(const ListValue* args); 203 void HandleTerminateCommand(const ListValue* args); 204 void HandleReloadCommand(const ListValue* args); 205 void HandleOpenCommand(const ListValue* args); 206 void HandlePortForwardingEnabledCommand(const ListValue* args); 207 void HandlePortForwardingConfigCommand(const ListValue* args); 208 209 static bool GetProcessAndRouteId(const ListValue* args, 210 int* process_id, 211 int* route_id); 212 213 static bool GetRemotePageId(const ListValue* args, std::string* page_id); 214 215 InspectUI* inspect_ui_; 216 217 DISALLOW_COPY_AND_ASSIGN(InspectMessageHandler); 218}; 219 220void InspectMessageHandler::RegisterMessages() { 221 web_ui()->RegisterMessageCallback(kInitUICommand, 222 base::Bind(&InspectMessageHandler::HandleInitUICommand, 223 base::Unretained(this))); 224 web_ui()->RegisterMessageCallback(kInspectCommand, 225 base::Bind(&InspectMessageHandler::HandleInspectCommand, 226 base::Unretained(this))); 227 web_ui()->RegisterMessageCallback(kActivateCommand, 228 base::Bind(&InspectMessageHandler::HandleActivateCommand, 229 base::Unretained(this))); 230 web_ui()->RegisterMessageCallback(kTerminateCommand, 231 base::Bind(&InspectMessageHandler::HandleTerminateCommand, 232 base::Unretained(this))); 233 web_ui()->RegisterMessageCallback(kPortForwardingEnabledCommand, 234 base::Bind(&InspectMessageHandler::HandlePortForwardingEnabledCommand, 235 base::Unretained(this))); 236 web_ui()->RegisterMessageCallback(kPortForwardingConfigCommand, 237 base::Bind(&InspectMessageHandler::HandlePortForwardingConfigCommand, 238 base::Unretained(this))); 239 web_ui()->RegisterMessageCallback(kReloadCommand, 240 base::Bind(&InspectMessageHandler::HandleReloadCommand, 241 base::Unretained(this))); 242 web_ui()->RegisterMessageCallback(kOpenCommand, 243 base::Bind(&InspectMessageHandler::HandleOpenCommand, 244 base::Unretained(this))); 245} 246 247void InspectMessageHandler::HandleInitUICommand(const ListValue*) { 248 inspect_ui_->InitUI(); 249} 250 251void InspectMessageHandler::HandleInspectCommand(const ListValue* args) { 252 Profile* profile = Profile::FromWebUI(web_ui()); 253 if (!profile) 254 return; 255 256 std::string page_id; 257 if (GetRemotePageId(args, &page_id)) { 258 inspect_ui_->InspectRemotePage(page_id); 259 return; 260 } 261 262 int process_id; 263 int route_id; 264 if (!GetProcessAndRouteId(args, &process_id, &route_id) || process_id == 0 265 || route_id == 0) { 266 return; 267 } 268 269 RenderViewHost* rvh = RenderViewHost::FromID(process_id, route_id); 270 if (rvh) { 271 DevToolsWindow::OpenDevToolsWindow(rvh); 272 return; 273 } 274 275 scoped_refptr<DevToolsAgentHost> agent_host( 276 DevToolsAgentHost::GetForWorker(process_id, route_id)); 277 if (!agent_host.get()) 278 return; 279 280 DevToolsWindow::OpenDevToolsWindowForWorker(profile, agent_host.get()); 281} 282 283void InspectMessageHandler::HandleActivateCommand(const ListValue* args) { 284 std::string page_id; 285 if (GetRemotePageId(args, &page_id)) 286 inspect_ui_->ActivateRemotePage(page_id); 287} 288 289static void TerminateWorker(int process_id, int route_id) { 290 WorkerService::GetInstance()->TerminateWorker(process_id, route_id); 291} 292 293void InspectMessageHandler::HandleTerminateCommand(const ListValue* args) { 294 std::string page_id; 295 if (GetRemotePageId(args, &page_id)) { 296 inspect_ui_->CloseRemotePage(page_id); 297 return; 298 } 299 300 int process_id; 301 int route_id; 302 if (!GetProcessAndRouteId(args, &process_id, &route_id)) 303 return; 304 305 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 306 base::Bind(&TerminateWorker, process_id, route_id)); 307} 308 309void InspectMessageHandler::HandleReloadCommand(const ListValue* args) { 310 std::string page_id; 311 if (GetRemotePageId(args, &page_id)) 312 inspect_ui_->ReloadRemotePage(page_id); 313} 314 315void InspectMessageHandler::HandleOpenCommand(const ListValue* args) { 316 std::string browser_id; 317 std::string url; 318 if (args->GetSize() == 2 && 319 args->GetString(0, &browser_id) && 320 args->GetString(1, &url)) { 321 inspect_ui_->OpenRemotePage(browser_id, url); 322 } 323} 324 325bool InspectMessageHandler::GetProcessAndRouteId(const ListValue* args, 326 int* process_id, 327 int* route_id) { 328 const DictionaryValue* data; 329 if (args->GetSize() == 1 && args->GetDictionary(0, &data) && 330 data->GetInteger(kProcessIdField, process_id) && 331 data->GetInteger(kRouteIdField, route_id)) { 332 return true; 333 } 334 return false; 335} 336 337void InspectMessageHandler::HandlePortForwardingEnabledCommand( 338 const ListValue* args) { 339 Profile* profile = Profile::FromWebUI(web_ui()); 340 if (!profile) 341 return; 342 343 bool enabled; 344 if (args->GetSize() == 1 && args->GetBoolean(0, &enabled)) { 345 profile->GetPrefs()->SetBoolean( 346 prefs::kDevToolsPortForwardingEnabled, enabled); 347 } 348} 349 350void InspectMessageHandler::HandlePortForwardingConfigCommand( 351 const ListValue* args) { 352 Profile* profile = Profile::FromWebUI(web_ui()); 353 if (!profile) 354 return; 355 356 const DictionaryValue* dict_src; 357 if (args->GetSize() == 1 && args->GetDictionary(0, &dict_src)) 358 profile->GetPrefs()->Set(prefs::kDevToolsPortForwardingConfig, *dict_src); 359} 360 361bool InspectMessageHandler::GetRemotePageId(const ListValue* args, 362 std::string* page_id) { 363 const DictionaryValue* data; 364 if (args->GetSize() == 1 && args->GetDictionary(0, &data) && 365 data->GetString(kAdbGlobalIdField, page_id)) { 366 return true; 367 } 368 return false; 369} 370 371} // namespace 372 373class InspectUI::WorkerCreationDestructionListener 374 : public WorkerServiceObserver, 375 public content::BrowserChildProcessObserver, 376 public base::RefCountedThreadSafe<WorkerCreationDestructionListener> { 377 public: 378 WorkerCreationDestructionListener() 379 : discovery_ui_(NULL) {} 380 381 void Init(InspectUI* workers_ui) { 382 DCHECK(workers_ui); 383 DCHECK(!discovery_ui_); 384 discovery_ui_ = workers_ui; 385 BrowserChildProcessObserver::Add(this); 386 BrowserThread::PostTask( 387 BrowserThread::IO, FROM_HERE, 388 base::Bind(&WorkerCreationDestructionListener::RegisterObserver, 389 this)); 390 } 391 392 void InspectUIDestroyed() { 393 DCHECK(discovery_ui_); 394 discovery_ui_ = NULL; 395 BrowserChildProcessObserver::Remove(this); 396 BrowserThread::PostTask( 397 BrowserThread::IO, FROM_HERE, 398 base::Bind(&WorkerCreationDestructionListener::UnregisterObserver, 399 this)); 400 } 401 402 void UpdateUI() { 403 BrowserThread::PostTask( 404 BrowserThread::IO, FROM_HERE, 405 base::Bind(&WorkerCreationDestructionListener::CollectWorkersData, 406 this)); 407 } 408 409 private: 410 friend class base::RefCountedThreadSafe<WorkerCreationDestructionListener>; 411 virtual ~WorkerCreationDestructionListener() {} 412 413 virtual void WorkerCreated( 414 const GURL& url, 415 const string16& name, 416 int process_id, 417 int route_id) OVERRIDE { 418 CollectWorkersData(); 419 } 420 421 virtual void WorkerDestroyed(int process_id, int route_id) OVERRIDE { 422 CollectWorkersData(); 423 } 424 425 virtual void BrowserChildProcessHostConnected( 426 const content::ChildProcessData& data) OVERRIDE { 427 if (data.process_type == content::PROCESS_TYPE_WORKER) 428 UpdateUI(); 429 } 430 431 virtual void BrowserChildProcessHostDisconnected( 432 const content::ChildProcessData& data) OVERRIDE { 433 if (data.process_type == content::PROCESS_TYPE_WORKER) 434 UpdateUI(); 435 } 436 437 void CollectWorkersData() { 438 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 439 BrowserThread::PostTask( 440 BrowserThread::UI, FROM_HERE, 441 base::Bind(&WorkerCreationDestructionListener::PopulateWorkersList, 442 this, WorkerService::GetInstance()->GetWorkers())); 443 } 444 445 void RegisterObserver() { 446 WorkerService::GetInstance()->AddObserver(this); 447 } 448 449 void UnregisterObserver() { 450 WorkerService::GetInstance()->RemoveObserver(this); 451 } 452 453 void PopulateWorkersList( 454 const std::vector<WorkerService::WorkerInfo>& worker_info) { 455 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 456 if (!discovery_ui_) 457 return; 458 459 ListValue target_list; 460 for (size_t i = 0; i < worker_info.size(); ++i) { 461 if (!worker_info[i].handle) 462 continue; // Process is still being created. 463 target_list.Append(BuildTargetDescriptor( 464 kWorkerTargetType, 465 HasClientHost(worker_info[i].process_id, worker_info[i].route_id), 466 worker_info[i].url, 467 UTF16ToUTF8(worker_info[i].name), 468 GURL(), 469 "", 470 worker_info[i].process_id, 471 worker_info[i].route_id, 472 worker_info[i].handle)); 473 } 474 discovery_ui_->web_ui()->CallJavascriptFunction( 475 "populateWorkersList", target_list); 476 } 477 478 InspectUI* discovery_ui_; 479}; 480 481InspectUI::InspectUI(content::WebUI* web_ui) 482 : WebUIController(web_ui) { 483 web_ui->AddMessageHandler(new InspectMessageHandler(this)); 484 Profile* profile = Profile::FromWebUI(web_ui); 485 content::WebUIDataSource::Add(profile, CreateInspectUIHTMLSource()); 486 487 // Set up the chrome://theme/ source. 488 ThemeSource* theme = new ThemeSource(profile); 489 content::URLDataSource::Add(profile, theme); 490} 491 492InspectUI::~InspectUI() { 493 StopListeningNotifications(); 494} 495 496void InspectUI::InitUI() { 497 StartListeningNotifications(); 498 PopulateLists(); 499 UpdatePortForwardingEnabled(); 500 UpdatePortForwardingConfig(); 501 observer_->UpdateUI(); 502} 503 504void InspectUI::InspectRemotePage(const std::string& id) { 505 RemotePages::iterator it = remote_pages_.find(id); 506 if (it != remote_pages_.end()) { 507 Profile* profile = Profile::FromWebUI(web_ui()); 508 it->second->Inspect(profile); 509 } 510} 511 512void InspectUI::ActivateRemotePage(const std::string& id) { 513 RemotePages::iterator it = remote_pages_.find(id); 514 if (it != remote_pages_.end()) 515 it->second->Activate(); 516} 517 518void InspectUI::ReloadRemotePage(const std::string& id) { 519 RemotePages::iterator it = remote_pages_.find(id); 520 if (it != remote_pages_.end()) 521 it->second->Reload(); 522} 523 524void InspectUI::CloseRemotePage(const std::string& id) { 525 RemotePages::iterator it = remote_pages_.find(id); 526 if (it != remote_pages_.end()) 527 it->second->Close(); 528} 529 530void InspectUI::OpenRemotePage(const std::string& browser_id, 531 const std::string& url) { 532 GURL gurl(url); 533 if (!gurl.is_valid()) { 534 gurl = GURL("http://" + url); 535 if (!gurl.is_valid()) 536 return; 537 } 538 RemoteBrowsers::iterator it = remote_browsers_.find(browser_id); 539 if (it != remote_browsers_.end()) 540 it->second->Open(gurl.spec()); 541} 542 543void InspectUI::PopulateLists() { 544 std::set<RenderViewHost*> tab_rvhs; 545 for (TabContentsIterator it; !it.done(); it.Next()) 546 tab_rvhs.insert(it->GetRenderViewHost()); 547 548 scoped_ptr<ListValue> target_list(new ListValue()); 549 550 std::vector<RenderViewHost*> rvh_vector = 551 DevToolsAgentHost::GetValidRenderViewHosts(); 552 553 for (std::vector<RenderViewHost*>::iterator it(rvh_vector.begin()); 554 it != rvh_vector.end(); it++) { 555 bool is_tab = tab_rvhs.find(*it) != tab_rvhs.end(); 556 target_list->Append(BuildTargetDescriptor(*it, is_tab)); 557 } 558 web_ui()->CallJavascriptFunction("populateLists", *target_list.get()); 559} 560 561void InspectUI::Observe(int type, 562 const content::NotificationSource& source, 563 const content::NotificationDetails& details) { 564 if (source != content::Source<WebContents>(web_ui()->GetWebContents())) 565 PopulateLists(); 566 else if (type == content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED) 567 StopListeningNotifications(); 568} 569 570void InspectUI::StartListeningNotifications() { 571 if (observer_) 572 return; 573 574 observer_ = new WorkerCreationDestructionListener(); 575 observer_->Init(this); 576 577 Profile* profile = Profile::FromWebUI(web_ui()); 578 DevToolsAdbBridge* adb_bridge = 579 DevToolsAdbBridge::Factory::GetForProfile(profile); 580 if (adb_bridge) 581 adb_bridge->AddListener(this); 582 583 notification_registrar_.Add(this, 584 content::NOTIFICATION_WEB_CONTENTS_CONNECTED, 585 content::NotificationService::AllSources()); 586 notification_registrar_.Add(this, 587 content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, 588 content::NotificationService::AllSources()); 589 notification_registrar_.Add(this, 590 content::NOTIFICATION_WEB_CONTENTS_DESTROYED, 591 content::NotificationService::AllSources()); 592 593 pref_change_registrar_.Init(profile->GetPrefs()); 594 pref_change_registrar_.Add(prefs::kDevToolsPortForwardingEnabled, 595 base::Bind(&InspectUI::UpdatePortForwardingEnabled, 596 base::Unretained(this))); 597 pref_change_registrar_.Add(prefs::kDevToolsPortForwardingConfig, 598 base::Bind(&InspectUI::UpdatePortForwardingConfig, 599 base::Unretained(this))); 600} 601 602void InspectUI::StopListeningNotifications() 603{ 604 if (!observer_.get()) 605 return; 606 Profile* profile = Profile::FromWebUI(web_ui()); 607 DevToolsAdbBridge* adb_bridge = 608 DevToolsAdbBridge::Factory::GetForProfile(profile); 609 if (adb_bridge) 610 adb_bridge->RemoveListener(this); 611 observer_->InspectUIDestroyed(); 612 observer_ = NULL; 613 notification_registrar_.RemoveAll(); 614 pref_change_registrar_.RemoveAll(); 615} 616 617content::WebUIDataSource* InspectUI::CreateInspectUIHTMLSource() { 618 content::WebUIDataSource* source = 619 content::WebUIDataSource::Create(chrome::kChromeUIInspectHost); 620 source->AddResourcePath("inspect.css", IDR_INSPECT_CSS); 621 source->AddResourcePath("inspect.js", IDR_INSPECT_JS); 622 source->SetDefaultResource(IDR_INSPECT_HTML); 623 return source; 624} 625 626void InspectUI::RemoteDevicesChanged( 627 DevToolsAdbBridge::RemoteDevices* devices) { 628 remote_browsers_.clear(); 629 remote_pages_.clear(); 630 ListValue device_list; 631 for (DevToolsAdbBridge::RemoteDevices::iterator dit = devices->begin(); 632 dit != devices->end(); ++dit) { 633 DevToolsAdbBridge::RemoteDevice* device = dit->get(); 634 DictionaryValue* device_data = new DictionaryValue(); 635 device_data->SetString(kAdbModelField, device->model()); 636 device_data->SetString(kAdbSerialField, device->serial()); 637 std::string device_id = base::StringPrintf( 638 "device:%s", 639 device->serial().c_str()); 640 device_data->SetString(kAdbGlobalIdField, device_id); 641 ListValue* browser_list = new ListValue(); 642 device_data->Set(kAdbBrowsersField, browser_list); 643 644 DevToolsAdbBridge::RemoteBrowsers& browsers = device->browsers(); 645 for (DevToolsAdbBridge::RemoteBrowsers::iterator bit = 646 browsers.begin(); bit != browsers.end(); ++bit) { 647 DevToolsAdbBridge::RemoteBrowser* browser = bit->get(); 648 DictionaryValue* browser_data = new DictionaryValue(); 649 browser_data->SetString(kAdbBrowserProductField, browser->product()); 650 browser_data->SetString(kAdbBrowserPackageField, browser->package()); 651 browser_data->SetString(kAdbBrowserVersionField, browser->version()); 652 std::string browser_id = base::StringPrintf( 653 "browser:%s:%s:%s", 654 device->serial().c_str(), 655 browser->product().c_str(), // Force sorting by product name. 656 browser->socket().c_str()); 657 browser_data->SetString(kAdbGlobalIdField, browser_id); 658 remote_browsers_[browser_id] = browser; 659 ListValue* page_list = new ListValue(); 660 browser_data->Set(kAdbPagesField, page_list); 661 662 DevToolsAdbBridge::RemotePages& pages = browser->pages(); 663 for (DevToolsAdbBridge::RemotePages::iterator it = 664 pages.begin(); it != pages.end(); ++it) { 665 DevToolsAdbBridge::RemotePage* page = it->get(); 666 DictionaryValue* page_data = BuildTargetDescriptor( 667 kAdbTargetType, page->attached(), 668 GURL(page->url()), page->title(), GURL(page->favicon_url()), 669 page->description(), 0, 0); 670 std::string page_id = base::StringPrintf("page:%s:%s:%s", 671 device->serial().c_str(), 672 browser->socket().c_str(), 673 page->id().c_str()); 674 page_data->SetString(kAdbGlobalIdField, page_id); 675 remote_pages_[page_id] = page; 676 page_list->Append(page_data); 677 } 678 browser_list->Append(browser_data); 679 } 680 681 DictionaryValue* port_status_dict = new DictionaryValue(); 682 typedef DevToolsAdbBridge::RemoteDevice::PortStatusMap StatusMap; 683 const StatusMap& port_status = device->port_status(); 684 for (StatusMap::const_iterator it = port_status.begin(); 685 it != port_status.end(); ++it) { 686 port_status_dict->SetInteger( 687 base::StringPrintf("%d", it->first), it->second); 688 } 689 device_data->Set(kAdbPortStatus, port_status_dict); 690 691 device_list.Append(device_data); 692 } 693 web_ui()->CallJavascriptFunction("populateDeviceLists", device_list); 694} 695 696void InspectUI::UpdatePortForwardingEnabled() { 697 Profile* profile = Profile::FromWebUI(web_ui()); 698 const base::Value* value = profile->GetPrefs()->FindPreference( 699 prefs::kDevToolsPortForwardingEnabled)->GetValue(); 700 web_ui()->CallJavascriptFunction("updatePortForwardingEnabled", *value); 701 702} 703 704void InspectUI::UpdatePortForwardingConfig() { 705 Profile* profile = Profile::FromWebUI(web_ui()); 706 const base::Value* value = profile->GetPrefs()->FindPreference( 707 prefs::kDevToolsPortForwardingConfig)->GetValue(); 708 web_ui()->CallJavascriptFunction("updatePortForwardingConfig", *value); 709} 710