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