| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/test/chromedriver/chrome_launcher.h" | 5 #include "chrome/test/chromedriver/chrome_launcher.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <memory> |
| 10 #include <utility> | 11 #include <utility> |
| 11 #include <vector> | 12 #include <vector> |
| 12 | 13 |
| 13 #include "base/base64.h" | 14 #include "base/base64.h" |
| 14 #include "base/bind.h" | 15 #include "base/bind.h" |
| 15 #include "base/command_line.h" | 16 #include "base/command_line.h" |
| 16 #include "base/files/file_path.h" | 17 #include "base/files/file_path.h" |
| 17 #include "base/files/file_util.h" | 18 #include "base/files/file_util.h" |
| 18 #include "base/files/scoped_file.h" | 19 #include "base/files/scoped_file.h" |
| 19 #include "base/format_macros.h" | 20 #include "base/format_macros.h" |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 237 } | 238 } |
| 238 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50)); | 239 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50)); |
| 239 } | 240 } |
| 240 return Status(kUnknownError, "unable to discover open pages"); | 241 return Status(kUnknownError, "unable to discover open pages"); |
| 241 } | 242 } |
| 242 | 243 |
| 243 Status CreateBrowserwideDevToolsClientAndConnect( | 244 Status CreateBrowserwideDevToolsClientAndConnect( |
| 244 const NetAddress& address, | 245 const NetAddress& address, |
| 245 const PerfLoggingPrefs& perf_logging_prefs, | 246 const PerfLoggingPrefs& perf_logging_prefs, |
| 246 const SyncWebSocketFactory& socket_factory, | 247 const SyncWebSocketFactory& socket_factory, |
| 247 const ScopedVector<DevToolsEventListener>& devtools_event_listeners, | 248 const std::vector<std::unique_ptr<DevToolsEventListener>>& |
| 249 devtools_event_listeners, |
| 248 std::unique_ptr<DevToolsClient>* browser_client) { | 250 std::unique_ptr<DevToolsClient>* browser_client) { |
| 249 std::unique_ptr<DevToolsClient> client(new DevToolsClientImpl( | 251 std::unique_ptr<DevToolsClient> client(new DevToolsClientImpl( |
| 250 socket_factory, base::StringPrintf("ws://%s/devtools/browser/", | 252 socket_factory, base::StringPrintf("ws://%s/devtools/browser/", |
| 251 address.ToString().c_str()), | 253 address.ToString().c_str()), |
| 252 DevToolsClientImpl::kBrowserwideDevToolsClientId)); | 254 DevToolsClientImpl::kBrowserwideDevToolsClientId)); |
| 253 for (ScopedVector<DevToolsEventListener>::const_iterator it = | 255 for (const auto& listener : devtools_event_listeners) { |
| 254 devtools_event_listeners.begin(); | |
| 255 it != devtools_event_listeners.end(); | |
| 256 ++it) { | |
| 257 // Only add listeners that subscribe to the browser-wide |DevToolsClient|. | 256 // Only add listeners that subscribe to the browser-wide |DevToolsClient|. |
| 258 // Otherwise, listeners will think this client is associated with a webview, | 257 // Otherwise, listeners will think this client is associated with a webview, |
| 259 // and will send unrecognized commands to it. | 258 // and will send unrecognized commands to it. |
| 260 if ((*it)->subscribes_to_browser()) | 259 if (listener->subscribes_to_browser()) |
| 261 client->AddListener(*it); | 260 client->AddListener(listener.get()); |
| 262 } | 261 } |
| 263 // Provide the client regardless of whether it connects, so that Chrome always | 262 // Provide the client regardless of whether it connects, so that Chrome always |
| 264 // has a valid |devtools_websocket_client_|. If not connected, no listeners | 263 // has a valid |devtools_websocket_client_|. If not connected, no listeners |
| 265 // will be notified, and client will just return kDisconnected errors if used. | 264 // will be notified, and client will just return kDisconnected errors if used. |
| 266 *browser_client = std::move(client); | 265 *browser_client = std::move(client); |
| 267 // To avoid unnecessary overhead, only connect if tracing is enabled, since | 266 // To avoid unnecessary overhead, only connect if tracing is enabled, since |
| 268 // the browser-wide client is currently only used for tracing. | 267 // the browser-wide client is currently only used for tracing. |
| 269 if (!perf_logging_prefs.trace_categories.empty()) { | 268 if (!perf_logging_prefs.trace_categories.empty()) { |
| 270 Status status = (*browser_client)->ConnectIfNecessary(); | 269 Status status = (*browser_client)->ConnectIfNecessary(); |
| 271 if (status.IsError()) | 270 if (status.IsError()) |
| 272 return status; | 271 return status; |
| 273 } | 272 } |
| 274 return Status(kOk); | 273 return Status(kOk); |
| 275 } | 274 } |
| 276 | 275 |
| 277 Status LaunchRemoteChromeSession( | 276 Status LaunchRemoteChromeSession( |
| 278 URLRequestContextGetter* context_getter, | 277 URLRequestContextGetter* context_getter, |
| 279 const SyncWebSocketFactory& socket_factory, | 278 const SyncWebSocketFactory& socket_factory, |
| 280 const Capabilities& capabilities, | 279 const Capabilities& capabilities, |
| 281 ScopedVector<DevToolsEventListener>* devtools_event_listeners, | 280 std::vector<std::unique_ptr<DevToolsEventListener>> |
| 281 devtools_event_listeners, |
| 282 std::unique_ptr<Chrome>* chrome) { | 282 std::unique_ptr<Chrome>* chrome) { |
| 283 Status status(kOk); | 283 Status status(kOk); |
| 284 std::unique_ptr<DevToolsHttpClient> devtools_http_client; | 284 std::unique_ptr<DevToolsHttpClient> devtools_http_client; |
| 285 status = WaitForDevToolsAndCheckVersion( | 285 status = WaitForDevToolsAndCheckVersion( |
| 286 capabilities.debugger_address, context_getter, socket_factory, | 286 capabilities.debugger_address, context_getter, socket_factory, |
| 287 &capabilities, &devtools_http_client); | 287 &capabilities, &devtools_http_client); |
| 288 if (status.IsError()) { | 288 if (status.IsError()) { |
| 289 return Status(kUnknownError, "cannot connect to chrome at " + | 289 return Status(kUnknownError, "cannot connect to chrome at " + |
| 290 capabilities.debugger_address.ToString(), | 290 capabilities.debugger_address.ToString(), |
| 291 status); | 291 status); |
| 292 } | 292 } |
| 293 | 293 |
| 294 std::unique_ptr<DevToolsClient> devtools_websocket_client; | 294 std::unique_ptr<DevToolsClient> devtools_websocket_client; |
| 295 status = CreateBrowserwideDevToolsClientAndConnect( | 295 status = CreateBrowserwideDevToolsClientAndConnect( |
| 296 capabilities.debugger_address, capabilities.perf_logging_prefs, | 296 capabilities.debugger_address, capabilities.perf_logging_prefs, |
| 297 socket_factory, *devtools_event_listeners, &devtools_websocket_client); | 297 socket_factory, devtools_event_listeners, &devtools_websocket_client); |
| 298 if (status.IsError()) { | 298 if (status.IsError()) { |
| 299 LOG(WARNING) << "Browser-wide DevTools client failed to connect: " | 299 LOG(WARNING) << "Browser-wide DevTools client failed to connect: " |
| 300 << status.message(); | 300 << status.message(); |
| 301 } | 301 } |
| 302 | 302 |
| 303 chrome->reset(new ChromeRemoteImpl(std::move(devtools_http_client), | 303 chrome->reset(new ChromeRemoteImpl( |
| 304 std::move(devtools_websocket_client), | 304 std::move(devtools_http_client), std::move(devtools_websocket_client), |
| 305 *devtools_event_listeners, | 305 std::move(devtools_event_listeners), capabilities.page_load_strategy)); |
| 306 capabilities.page_load_strategy)); | |
| 307 return Status(kOk); | 306 return Status(kOk); |
| 308 } | 307 } |
| 309 | 308 |
| 310 Status LaunchDesktopChrome( | 309 Status LaunchDesktopChrome(URLRequestContextGetter* context_getter, |
| 311 URLRequestContextGetter* context_getter, | 310 uint16_t port, |
| 312 uint16_t port, | 311 std::unique_ptr<PortReservation> port_reservation, |
| 313 std::unique_ptr<PortReservation> port_reservation, | 312 const SyncWebSocketFactory& socket_factory, |
| 314 const SyncWebSocketFactory& socket_factory, | 313 const Capabilities& capabilities, |
| 315 const Capabilities& capabilities, | 314 std::vector<std::unique_ptr<DevToolsEventListener>> |
| 316 ScopedVector<DevToolsEventListener>* devtools_event_listeners, | 315 devtools_event_listeners, |
| 317 std::unique_ptr<Chrome>* chrome, | 316 std::unique_ptr<Chrome>* chrome, |
| 318 bool w3c_compliant) { | 317 bool w3c_compliant) { |
| 319 base::CommandLine command(base::CommandLine::NO_PROGRAM); | 318 base::CommandLine command(base::CommandLine::NO_PROGRAM); |
| 320 base::ScopedTempDir user_data_dir; | 319 base::ScopedTempDir user_data_dir; |
| 321 base::ScopedTempDir extension_dir; | 320 base::ScopedTempDir extension_dir; |
| 322 std::vector<std::string> extension_bg_pages; | 321 std::vector<std::string> extension_bg_pages; |
| 323 Status status = PrepareCommandLine(port, | 322 Status status = PrepareCommandLine(port, |
| 324 capabilities, | 323 capabilities, |
| 325 &command, | 324 &command, |
| 326 &user_data_dir, | 325 &user_data_dir, |
| 327 &extension_dir, | 326 &extension_dir, |
| 328 &extension_bg_pages); | 327 &extension_bg_pages); |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 425 if (base::GetTerminationStatus(process.Handle(), &exit_code) == | 424 if (base::GetTerminationStatus(process.Handle(), &exit_code) == |
| 426 base::TERMINATION_STATUS_STILL_RUNNING) | 425 base::TERMINATION_STATUS_STILL_RUNNING) |
| 427 return Status(kUnknownError, "cannot kill Chrome", status); | 426 return Status(kUnknownError, "cannot kill Chrome", status); |
| 428 } | 427 } |
| 429 return status; | 428 return status; |
| 430 } | 429 } |
| 431 | 430 |
| 432 std::unique_ptr<DevToolsClient> devtools_websocket_client; | 431 std::unique_ptr<DevToolsClient> devtools_websocket_client; |
| 433 status = CreateBrowserwideDevToolsClientAndConnect( | 432 status = CreateBrowserwideDevToolsClientAndConnect( |
| 434 NetAddress(port), capabilities.perf_logging_prefs, socket_factory, | 433 NetAddress(port), capabilities.perf_logging_prefs, socket_factory, |
| 435 *devtools_event_listeners, &devtools_websocket_client); | 434 devtools_event_listeners, &devtools_websocket_client); |
| 436 if (status.IsError()) { | 435 if (status.IsError()) { |
| 437 LOG(WARNING) << "Browser-wide DevTools client failed to connect: " | 436 LOG(WARNING) << "Browser-wide DevTools client failed to connect: " |
| 438 << status.message(); | 437 << status.message(); |
| 439 } | 438 } |
| 440 | 439 |
| 441 std::unique_ptr<ChromeDesktopImpl> chrome_desktop( | 440 std::unique_ptr<ChromeDesktopImpl> chrome_desktop(new ChromeDesktopImpl( |
| 442 new ChromeDesktopImpl(std::move(devtools_http_client), | 441 std::move(devtools_http_client), std::move(devtools_websocket_client), |
| 443 std::move(devtools_websocket_client), | 442 std::move(devtools_event_listeners), std::move(port_reservation), |
| 444 *devtools_event_listeners, | 443 capabilities.page_load_strategy, std::move(process), command, |
| 445 std::move(port_reservation), | 444 &user_data_dir, &extension_dir, capabilities.network_emulation_enabled)); |
| 446 capabilities.page_load_strategy, | |
| 447 std::move(process), | |
| 448 command, | |
| 449 &user_data_dir, | |
| 450 &extension_dir, | |
| 451 capabilities.network_emulation_enabled)); | |
| 452 for (size_t i = 0; i < extension_bg_pages.size(); ++i) { | 445 for (size_t i = 0; i < extension_bg_pages.size(); ++i) { |
| 453 VLOG(0) << "Waiting for extension bg page load: " << extension_bg_pages[i]; | 446 VLOG(0) << "Waiting for extension bg page load: " << extension_bg_pages[i]; |
| 454 std::unique_ptr<WebView> web_view; | 447 std::unique_ptr<WebView> web_view; |
| 455 Status status = chrome_desktop->WaitForPageToLoad( | 448 Status status = chrome_desktop->WaitForPageToLoad( |
| 456 extension_bg_pages[i], base::TimeDelta::FromSeconds(10), | 449 extension_bg_pages[i], base::TimeDelta::FromSeconds(10), |
| 457 &web_view, w3c_compliant); | 450 &web_view, w3c_compliant); |
| 458 if (status.IsError()) { | 451 if (status.IsError()) { |
| 459 return Status(kUnknownError, | 452 return Status(kUnknownError, |
| 460 "failed to wait for extension background page to load: " + | 453 "failed to wait for extension background page to load: " + |
| 461 extension_bg_pages[i], | 454 extension_bg_pages[i], |
| 462 status); | 455 status); |
| 463 } | 456 } |
| 464 } | 457 } |
| 465 *chrome = std::move(chrome_desktop); | 458 *chrome = std::move(chrome_desktop); |
| 466 return Status(kOk); | 459 return Status(kOk); |
| 467 } | 460 } |
| 468 | 461 |
| 469 Status LaunchAndroidChrome( | 462 Status LaunchAndroidChrome(URLRequestContextGetter* context_getter, |
| 470 URLRequestContextGetter* context_getter, | 463 uint16_t port, |
| 471 uint16_t port, | 464 std::unique_ptr<PortReservation> port_reservation, |
| 472 std::unique_ptr<PortReservation> port_reservation, | 465 const SyncWebSocketFactory& socket_factory, |
| 473 const SyncWebSocketFactory& socket_factory, | 466 const Capabilities& capabilities, |
| 474 const Capabilities& capabilities, | 467 std::vector<std::unique_ptr<DevToolsEventListener>> |
| 475 ScopedVector<DevToolsEventListener>* devtools_event_listeners, | 468 devtools_event_listeners, |
| 476 DeviceManager* device_manager, | 469 DeviceManager* device_manager, |
| 477 std::unique_ptr<Chrome>* chrome) { | 470 std::unique_ptr<Chrome>* chrome) { |
| 478 Status status(kOk); | 471 Status status(kOk); |
| 479 std::unique_ptr<Device> device; | 472 std::unique_ptr<Device> device; |
| 480 if (capabilities.android_device_serial.empty()) { | 473 if (capabilities.android_device_serial.empty()) { |
| 481 status = device_manager->AcquireDevice(&device); | 474 status = device_manager->AcquireDevice(&device); |
| 482 } else { | 475 } else { |
| 483 status = device_manager->AcquireSpecificDevice( | 476 status = device_manager->AcquireSpecificDevice( |
| 484 capabilities.android_device_serial, &device); | 477 capabilities.android_device_serial, &device); |
| 485 } | 478 } |
| 486 if (status.IsError()) | 479 if (status.IsError()) |
| 487 return status; | 480 return status; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 511 &capabilities, | 504 &capabilities, |
| 512 &devtools_http_client); | 505 &devtools_http_client); |
| 513 if (status.IsError()) { | 506 if (status.IsError()) { |
| 514 device->TearDown(); | 507 device->TearDown(); |
| 515 return status; | 508 return status; |
| 516 } | 509 } |
| 517 | 510 |
| 518 std::unique_ptr<DevToolsClient> devtools_websocket_client; | 511 std::unique_ptr<DevToolsClient> devtools_websocket_client; |
| 519 status = CreateBrowserwideDevToolsClientAndConnect( | 512 status = CreateBrowserwideDevToolsClientAndConnect( |
| 520 NetAddress(port), capabilities.perf_logging_prefs, socket_factory, | 513 NetAddress(port), capabilities.perf_logging_prefs, socket_factory, |
| 521 *devtools_event_listeners, &devtools_websocket_client); | 514 devtools_event_listeners, &devtools_websocket_client); |
| 522 if (status.IsError()) { | 515 if (status.IsError()) { |
| 523 LOG(WARNING) << "Browser-wide DevTools client failed to connect: " | 516 LOG(WARNING) << "Browser-wide DevTools client failed to connect: " |
| 524 << status.message(); | 517 << status.message(); |
| 525 } | 518 } |
| 526 | 519 |
| 527 chrome->reset(new ChromeAndroidImpl(std::move(devtools_http_client), | 520 chrome->reset(new ChromeAndroidImpl( |
| 528 std::move(devtools_websocket_client), | 521 std::move(devtools_http_client), std::move(devtools_websocket_client), |
| 529 *devtools_event_listeners, | 522 std::move(devtools_event_listeners), std::move(port_reservation), |
| 530 std::move(port_reservation), | 523 capabilities.page_load_strategy, std::move(device))); |
| 531 capabilities.page_load_strategy, | |
| 532 std::move(device))); | |
| 533 return Status(kOk); | 524 return Status(kOk); |
| 534 } | 525 } |
| 535 | 526 |
| 536 } // namespace | 527 } // namespace |
| 537 | 528 |
| 538 Status LaunchChrome( | 529 Status LaunchChrome(URLRequestContextGetter* context_getter, |
| 539 URLRequestContextGetter* context_getter, | 530 const SyncWebSocketFactory& socket_factory, |
| 540 const SyncWebSocketFactory& socket_factory, | 531 DeviceManager* device_manager, |
| 541 DeviceManager* device_manager, | 532 PortServer* port_server, |
| 542 PortServer* port_server, | 533 PortManager* port_manager, |
| 543 PortManager* port_manager, | 534 const Capabilities& capabilities, |
| 544 const Capabilities& capabilities, | 535 std::vector<std::unique_ptr<DevToolsEventListener>> |
| 545 ScopedVector<DevToolsEventListener>* devtools_event_listeners, | 536 devtools_event_listeners, |
| 546 std::unique_ptr<Chrome>* chrome, | 537 std::unique_ptr<Chrome>* chrome, |
| 547 bool w3c_compliant) { | 538 bool w3c_compliant) { |
| 548 if (capabilities.IsRemoteBrowser()) { | 539 if (capabilities.IsRemoteBrowser()) { |
| 549 return LaunchRemoteChromeSession( | 540 return LaunchRemoteChromeSession( |
| 550 context_getter, socket_factory, | 541 context_getter, socket_factory, capabilities, |
| 551 capabilities, devtools_event_listeners, chrome); | 542 std::move(devtools_event_listeners), chrome); |
| 552 } | 543 } |
| 553 | 544 |
| 554 uint16_t port = 0; | 545 uint16_t port = 0; |
| 555 std::unique_ptr<PortReservation> port_reservation; | 546 std::unique_ptr<PortReservation> port_reservation; |
| 556 Status port_status(kOk); | 547 Status port_status(kOk); |
| 557 | 548 |
| 558 if (capabilities.IsAndroid()) { | 549 if (capabilities.IsAndroid()) { |
| 559 if (port_server) | 550 if (port_server) |
| 560 port_status = port_server->ReservePort(&port, &port_reservation); | 551 port_status = port_server->ReservePort(&port, &port_reservation); |
| 561 else | 552 else |
| 562 port_status = port_manager->ReservePortFromPool(&port, &port_reservation); | 553 port_status = port_manager->ReservePortFromPool(&port, &port_reservation); |
| 563 if (port_status.IsError()) | 554 if (port_status.IsError()) |
| 564 return Status(kUnknownError, "cannot reserve port for Chrome", | 555 return Status(kUnknownError, "cannot reserve port for Chrome", |
| 565 port_status); | 556 port_status); |
| 566 return LaunchAndroidChrome( | 557 return LaunchAndroidChrome( |
| 567 context_getter, port, std::move(port_reservation), socket_factory, | 558 context_getter, port, std::move(port_reservation), socket_factory, |
| 568 capabilities, devtools_event_listeners, device_manager, chrome); | 559 capabilities, std::move(devtools_event_listeners), device_manager, |
| 560 chrome); |
| 569 } else { | 561 } else { |
| 570 if (port_server) | 562 if (port_server) |
| 571 port_status = port_server->ReservePort(&port, &port_reservation); | 563 port_status = port_server->ReservePort(&port, &port_reservation); |
| 572 else | 564 else |
| 573 port_status = port_manager->ReservePort(&port, &port_reservation); | 565 port_status = port_manager->ReservePort(&port, &port_reservation); |
| 574 if (port_status.IsError()) | 566 if (port_status.IsError()) |
| 575 return Status(kUnknownError, "cannot reserve port for Chrome", | 567 return Status(kUnknownError, "cannot reserve port for Chrome", |
| 576 port_status); | 568 port_status); |
| 577 return LaunchDesktopChrome(context_getter, port, | 569 return LaunchDesktopChrome( |
| 578 std::move(port_reservation), socket_factory, | 570 context_getter, port, std::move(port_reservation), socket_factory, |
| 579 capabilities, devtools_event_listeners, chrome, | 571 capabilities, std::move(devtools_event_listeners), chrome, |
| 580 w3c_compliant); | 572 w3c_compliant); |
| 581 } | 573 } |
| 582 } | 574 } |
| 583 | 575 |
| 584 namespace internal { | 576 namespace internal { |
| 585 | 577 |
| 586 void ConvertHexadecimalToIDAlphabet(std::string* id) { | 578 void ConvertHexadecimalToIDAlphabet(std::string* id) { |
| 587 for (size_t i = 0; i < id->size(); ++i) { | 579 for (size_t i = 0; i < id->size(); ++i) { |
| 588 int val; | 580 int val; |
| 589 if (base::HexStringToInt(base::StringPiece(id->begin() + i, | 581 if (base::HexStringToInt(base::StringPiece(id->begin() + i, |
| 590 id->begin() + i + 1), | 582 id->begin() + i + 1), |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 881 // Write empty "First Run" file, otherwise Chrome will wipe the default | 873 // Write empty "First Run" file, otherwise Chrome will wipe the default |
| 882 // profile that was written. | 874 // profile that was written. |
| 883 if (base::WriteFile( | 875 if (base::WriteFile( |
| 884 user_data_dir.Append(chrome::kFirstRunSentinel), "", 0) != 0) { | 876 user_data_dir.Append(chrome::kFirstRunSentinel), "", 0) != 0) { |
| 885 return Status(kUnknownError, "failed to write first run file"); | 877 return Status(kUnknownError, "failed to write first run file"); |
| 886 } | 878 } |
| 887 return Status(kOk); | 879 return Status(kOk); |
| 888 } | 880 } |
| 889 | 881 |
| 890 } // namespace internal | 882 } // namespace internal |
| OLD | NEW |