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