Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(190)

Side by Side Diff: chrome/test/chromedriver/chrome_launcher.cc

Issue 23643005: [chromedriver] Load the automation extension as a component extension. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: . Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 <algorithm> 7 #include <algorithm>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/base64.h" 10 #include "base/base64.h"
(...skipping 25 matching lines...) Expand all
36 #include "chrome/test/chromedriver/chrome/status.h" 36 #include "chrome/test/chromedriver/chrome/status.h"
37 #include "chrome/test/chromedriver/chrome/user_data_dir.h" 37 #include "chrome/test/chromedriver/chrome/user_data_dir.h"
38 #include "chrome/test/chromedriver/chrome/version.h" 38 #include "chrome/test/chromedriver/chrome/version.h"
39 #include "chrome/test/chromedriver/chrome/web_view.h" 39 #include "chrome/test/chromedriver/chrome/web_view.h"
40 #include "chrome/test/chromedriver/chrome/zip.h" 40 #include "chrome/test/chromedriver/chrome/zip.h"
41 #include "chrome/test/chromedriver/net/url_request_context_getter.h" 41 #include "chrome/test/chromedriver/net/url_request_context_getter.h"
42 #include "crypto/sha2.h" 42 #include "crypto/sha2.h"
43 43
44 namespace { 44 namespace {
45 45
46 const char* kCommonSwitches[] = {
47 "ignore-certificate-errors", "metrics-recording-only"};
48
49 Status UnpackAutomationExtension(const base::FilePath& temp_dir, 46 Status UnpackAutomationExtension(const base::FilePath& temp_dir,
50 base::FilePath* automation_extension) { 47 base::FilePath* automation_extension) {
51 std::string decoded_extension; 48 std::string decoded_extension;
52 if (!base::Base64Decode(kAutomationExtension, &decoded_extension)) 49 if (!base::Base64Decode(kAutomationExtension, &decoded_extension))
53 return Status(kUnknownError, "failed to base64decode automation extension"); 50 return Status(kUnknownError, "failed to base64decode automation extension");
54 51
55 base::FilePath extension_zip = temp_dir.AppendASCII("internal.zip"); 52 base::FilePath extension_zip = temp_dir.AppendASCII("internal.zip");
56 int size = static_cast<int>(decoded_extension.length()); 53 int size = static_cast<int>(decoded_extension.length());
57 if (file_util::WriteFile(extension_zip, decoded_extension.c_str(), size) 54 if (file_util::WriteFile(extension_zip, decoded_extension.c_str(), size)
58 != size) { 55 != size) {
59 return Status(kUnknownError, "failed to write automation extension zip"); 56 return Status(kUnknownError, "failed to write automation extension zip");
60 } 57 }
61 58
62 base::FilePath extension_dir = temp_dir.AppendASCII("internal"); 59 base::FilePath extension_dir = temp_dir.AppendASCII("internal");
63 if (!zip::Unzip(extension_zip, extension_dir)) 60 if (!zip::Unzip(extension_zip, extension_dir))
64 return Status(kUnknownError, "failed to unzip automation extension"); 61 return Status(kUnknownError, "failed to unzip automation extension");
65 62
66 *automation_extension = extension_dir; 63 *automation_extension = extension_dir;
67 return Status(kOk); 64 return Status(kOk);
68 } 65 }
69 66
70 void AddSwitches(CommandLine* command,
71 const char* switches[],
72 size_t switch_count,
73 const std::set<std::string>& exclude_switches) {
74 for (size_t i = 0; i < switch_count; ++i) {
75 if (exclude_switches.find(switches[i]) == exclude_switches.end())
76 command->AppendSwitch(switches[i]);
77 }
78 }
79
80 Status PrepareCommandLine(int port, 67 Status PrepareCommandLine(int port,
81 const Capabilities& capabilities, 68 const Capabilities& capabilities,
69 Switches* switches,
82 CommandLine* prepared_command, 70 CommandLine* prepared_command,
83 base::ScopedTempDir* user_data_dir, 71 base::ScopedTempDir* user_data_dir,
84 base::ScopedTempDir* extension_dir, 72 base::ScopedTempDir* extension_dir,
85 std::vector<std::string>* extension_bg_pages) { 73 std::vector<std::string>* extension_bg_pages) {
86 CommandLine command = capabilities.command; 74 base::FilePath program = capabilities.binary;
87 base::FilePath program = command.GetProgram();
88 if (program.empty()) { 75 if (program.empty()) {
89 if (!FindChrome(&program)) 76 if (!FindChrome(&program))
90 return Status(kUnknownError, "cannot find Chrome binary"); 77 return Status(kUnknownError, "cannot find Chrome binary");
91 command.SetProgram(program);
92 } else if (!base::PathExists(program)) { 78 } else if (!base::PathExists(program)) {
93 return Status(kUnknownError, 79 return Status(kUnknownError,
94 base::StringPrintf("no chrome binary at %" PRFilePath, 80 base::StringPrintf("no chrome binary at %" PRFilePath,
95 program.value().c_str())); 81 program.value().c_str()));
96 } 82 }
83 CommandLine command(program);
97 84
98 const char* excludable_switches[] = { 85 // TODO(chrisgao): Add "disable-sync" when chrome 30- is not supported.
99 "disable-hang-monitor", 86 // For chrome 30-, it leads to crash when opening chrome://settings.
100 "disable-prompt-on-repost", 87 switches->SetSwitch("disable-hang-monitor");
101 "full-memory-crash-report", 88 switches->SetSwitch("disable-prompt-on-repost");
102 "no-first-run", 89 switches->SetSwitch("full-memory-crash-report");
103 "disable-background-networking", 90 switches->SetSwitch("no-first-run");
104 // TODO(chrisgao): Add "disable-sync" when chrome 30- is not supported. 91 switches->SetSwitch("disable-background-networking");
105 // For chrome 30-, it leads to crash when opening chrome://settings. 92 switches->SetSwitch("disable-web-resources");
106 "disable-web-resources", 93 switches->SetSwitch("safebrowsing-disable-auto-update");
107 "safebrowsing-disable-auto-update", 94 switches->SetSwitch("safebrowsing-disable-download-protection");
108 "safebrowsing-disable-download-protection", 95 switches->SetSwitch("disable-client-side-phishing-detection");
109 "disable-client-side-phishing-detection", 96 switches->SetSwitch("disable-component-update");
110 "disable-component-update", 97 switches->SetSwitch("disable-default-apps");
111 "disable-default-apps", 98 switches->SetSwitch("enable-logging");
112 }; 99 switches->SetSwitch("logging-level", "1");
100 switches->SetSwitch("password-store", "basic");
101 switches->SetSwitch("use-mock-keychain");
102 switches->SetSwitch("remote-debugging-port", base::IntToString(port));
113 103
114 AddSwitches(&command, excludable_switches, arraysize(excludable_switches), 104 if (!switches->HasSwitch("user-data-dir")) {
115 capabilities.exclude_switches);
116 AddSwitches(&command, kCommonSwitches, arraysize(kCommonSwitches),
117 capabilities.exclude_switches);
118
119 command.AppendSwitch("enable-logging");
120 command.AppendSwitchASCII("logging-level", "1");
121 command.AppendSwitchASCII("password-store", "basic");
122 command.AppendSwitch("use-mock-keychain");
123 command.AppendSwitchASCII("remote-debugging-port", base::IntToString(port));
124
125 if (!command.HasSwitch("user-data-dir")) {
126 command.AppendArg("about:blank"); 105 command.AppendArg("about:blank");
127 if (!user_data_dir->CreateUniqueTempDir()) 106 if (!user_data_dir->CreateUniqueTempDir())
128 return Status(kUnknownError, "cannot create temp dir for user data dir"); 107 return Status(kUnknownError, "cannot create temp dir for user data dir");
129 command.AppendSwitchPath("user-data-dir", user_data_dir->path()); 108 command.AppendSwitchPath("user-data-dir", user_data_dir->path());
130 Status status = internal::PrepareUserDataDir( 109 Status status = internal::PrepareUserDataDir(
131 user_data_dir->path(), capabilities.prefs.get(), 110 user_data_dir->path(), capabilities.prefs.get(),
132 capabilities.local_state.get()); 111 capabilities.local_state.get());
133 if (status.IsError()) 112 if (status.IsError())
134 return status; 113 return status;
135 } 114 }
136 115
137 if (!extension_dir->CreateUniqueTempDir()) { 116 if (!extension_dir->CreateUniqueTempDir()) {
138 return Status(kUnknownError, 117 return Status(kUnknownError,
139 "cannot create temp dir for unpacking extensions"); 118 "cannot create temp dir for unpacking extensions");
140 } 119 }
141 Status status = internal::ProcessExtensions(capabilities.extensions, 120 Status status = internal::ProcessExtensions(capabilities.extensions,
142 extension_dir->path(), 121 extension_dir->path(),
143 true, 122 true,
144 &command, 123 switches,
145 extension_bg_pages); 124 extension_bg_pages);
146 if (status.IsError()) 125 if (status.IsError())
147 return status; 126 return status;
148 127
128 switches->AppendToCommandLine(&command);
149 *prepared_command = command; 129 *prepared_command = command;
150 return Status(kOk); 130 return Status(kOk);
151 } 131 }
152 132
153 Status WaitForDevToolsAndCheckVersion( 133 Status WaitForDevToolsAndCheckVersion(
154 int port, 134 int port,
155 URLRequestContextGetter* context_getter, 135 URLRequestContextGetter* context_getter,
156 const SyncWebSocketFactory& socket_factory, 136 const SyncWebSocketFactory& socket_factory,
157 Log* log, 137 Log* log,
158 scoped_ptr<DevToolsHttpClient>* user_client) { 138 scoped_ptr<DevToolsHttpClient>* user_client) {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
199 log)); 179 log));
200 return Status(kOk); 180 return Status(kOk);
201 } 181 }
202 182
203 Status LaunchDesktopChrome( 183 Status LaunchDesktopChrome(
204 URLRequestContextGetter* context_getter, 184 URLRequestContextGetter* context_getter,
205 int port, 185 int port,
206 const SyncWebSocketFactory& socket_factory, 186 const SyncWebSocketFactory& socket_factory,
207 Log* log, 187 Log* log,
208 const Capabilities& capabilities, 188 const Capabilities& capabilities,
189 Switches* switches,
209 ScopedVector<DevToolsEventListener>& devtools_event_listeners, 190 ScopedVector<DevToolsEventListener>& devtools_event_listeners,
210 scoped_ptr<Chrome>* chrome) { 191 scoped_ptr<Chrome>* chrome) {
211 CommandLine command(CommandLine::NO_PROGRAM); 192 CommandLine command(CommandLine::NO_PROGRAM);
212 base::ScopedTempDir user_data_dir; 193 base::ScopedTempDir user_data_dir;
213 base::ScopedTempDir extension_dir; 194 base::ScopedTempDir extension_dir;
214 std::vector<std::string> extension_bg_pages; 195 std::vector<std::string> extension_bg_pages;
215 Status status = PrepareCommandLine(port, 196 Status status = PrepareCommandLine(port,
216 capabilities, 197 capabilities,
198 switches,
217 &command, 199 &command,
218 &user_data_dir, 200 &user_data_dir,
219 &extension_dir, 201 &extension_dir,
220 &extension_bg_pages); 202 &extension_bg_pages);
221 if (status.IsError()) 203 if (status.IsError())
222 return status; 204 return status;
223 205
224 base::LaunchOptions options; 206 base::LaunchOptions options;
225 207
226 #if !defined(OS_WIN) 208 #if !defined(OS_WIN)
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
304 *chrome = chrome_desktop.Pass(); 286 *chrome = chrome_desktop.Pass();
305 return Status(kOk); 287 return Status(kOk);
306 } 288 }
307 289
308 Status LaunchAndroidChrome( 290 Status LaunchAndroidChrome(
309 URLRequestContextGetter* context_getter, 291 URLRequestContextGetter* context_getter,
310 int port, 292 int port,
311 const SyncWebSocketFactory& socket_factory, 293 const SyncWebSocketFactory& socket_factory,
312 Log* log, 294 Log* log,
313 const Capabilities& capabilities, 295 const Capabilities& capabilities,
296 Switches* switches,
314 ScopedVector<DevToolsEventListener>& devtools_event_listeners, 297 ScopedVector<DevToolsEventListener>& devtools_event_listeners,
315 DeviceManager* device_manager, 298 DeviceManager* device_manager,
316 scoped_ptr<Chrome>* chrome) { 299 scoped_ptr<Chrome>* chrome) {
317 Status status(kOk); 300 Status status(kOk);
318 scoped_ptr<Device> device; 301 scoped_ptr<Device> device;
319 if (capabilities.android_device_serial.empty()) { 302 if (capabilities.android_device_serial.empty()) {
320 status = device_manager->AcquireDevice(&device); 303 status = device_manager->AcquireDevice(&device);
321 } else { 304 } else {
322 status = device_manager->AcquireSpecificDevice( 305 status = device_manager->AcquireSpecificDevice(
323 capabilities.android_device_serial, &device); 306 capabilities.android_device_serial, &device);
324 } 307 }
325 if (!status.IsOk()) 308 if (!status.IsOk())
326 return status; 309 return status;
327 310
328 std::string args(capabilities.android_args); 311 switches->SetSwitch("disable-fre");
329 for (size_t i = 0; i < arraysize(kCommonSwitches); i++) 312 switches->SetSwitch("enable-remote-debugging");
330 args += "--" + std::string(kCommonSwitches[i]) + " ";
331 args += "--disable-fre --enable-remote-debugging";
332
333 status = device->StartApp(capabilities.android_package, 313 status = device->StartApp(capabilities.android_package,
334 capabilities.android_activity, 314 capabilities.android_activity,
335 capabilities.android_process, 315 capabilities.android_process,
336 args, port); 316 switches->ToString(), port);
337 if (!status.IsOk()) { 317 if (!status.IsOk()) {
338 device->StopApp(); 318 device->StopApp();
339 return status; 319 return status;
340 } 320 }
341 321
342 scoped_ptr<DevToolsHttpClient> devtools_client; 322 scoped_ptr<DevToolsHttpClient> devtools_client;
343 status = WaitForDevToolsAndCheckVersion(port, 323 status = WaitForDevToolsAndCheckVersion(port,
344 context_getter, 324 context_getter,
345 socket_factory, 325 socket_factory,
346 log, 326 log,
(...skipping 15 matching lines...) Expand all
362 Log* log, 342 Log* log,
363 DeviceManager* device_manager, 343 DeviceManager* device_manager,
364 const Capabilities& capabilities, 344 const Capabilities& capabilities,
365 ScopedVector<DevToolsEventListener>& devtools_event_listeners, 345 ScopedVector<DevToolsEventListener>& devtools_event_listeners,
366 scoped_ptr<Chrome>* chrome) { 346 scoped_ptr<Chrome>* chrome) {
367 347
368 if (capabilities.IsExistingBrowser()) { 348 if (capabilities.IsExistingBrowser()) {
369 return LaunchExistingChromeSession( 349 return LaunchExistingChromeSession(
370 context_getter, capabilities.existing_browser_port, socket_factory, 350 context_getter, capabilities.existing_browser_port, socket_factory,
371 log, capabilities, devtools_event_listeners, chrome); 351 log, capabilities, devtools_event_listeners, chrome);
372 } else if (capabilities.IsAndroid()) { 352 }
353
354
355 Switches switches = capabilities.switches;
356 const char* kCommonSwitches[] = {
357 "ignore-certificate-errors", "metrics-recording-only"};
358 for (size_t i = 0; i < arraysize(kCommonSwitches); i++)
359 switches.SetSwitch(kCommonSwitches[i]);
360
361 if (capabilities.IsAndroid()) {
373 return LaunchAndroidChrome( 362 return LaunchAndroidChrome(
374 context_getter, port, socket_factory, log, capabilities, 363 context_getter, port, socket_factory, log, capabilities,
375 devtools_event_listeners, device_manager, chrome); 364 &switches, devtools_event_listeners, device_manager, chrome);
376 } else { 365 } else {
377 return LaunchDesktopChrome( 366 return LaunchDesktopChrome(
378 context_getter, port, socket_factory, log, capabilities, 367 context_getter, port, socket_factory, log, capabilities,
379 devtools_event_listeners, chrome); 368 &switches, devtools_event_listeners, chrome);
380 } 369 }
381 } 370 }
382 371
383 namespace internal { 372 namespace internal {
384 373
385 void ConvertHexadecimalToIDAlphabet(std::string* id) { 374 void ConvertHexadecimalToIDAlphabet(std::string* id) {
386 for (size_t i = 0; i < id->size(); ++i) { 375 for (size_t i = 0; i < id->size(); ++i) {
387 int val; 376 int val;
388 if (base::HexStringToInt(base::StringPiece(id->begin() + i, 377 if (base::HexStringToInt(base::StringPiece(id->begin() + i,
389 id->begin() + i + 1), 378 id->begin() + i + 1),
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
486 Status status = GetExtensionBackgroundPage(manifest, id, &bg_page_tmp); 475 Status status = GetExtensionBackgroundPage(manifest, id, &bg_page_tmp);
487 if (status.IsError()) 476 if (status.IsError())
488 return status; 477 return status;
489 478
490 *path = extension_dir; 479 *path = extension_dir;
491 if (bg_page_tmp.size()) 480 if (bg_page_tmp.size())
492 *bg_page = bg_page_tmp; 481 *bg_page = bg_page_tmp;
493 return Status(kOk); 482 return Status(kOk);
494 } 483 }
495 484
485 void UpdateExtensionSwitch(Switches* switches,
486 const char name[],
487 const base::FilePath::StringType& extension) {
488 base::FilePath::StringType value = switches->GetSwitchValueNative(name);
489 if (value.length())
490 value += FILE_PATH_LITERAL(",");
491 value += extension;
492 switches->SetSwitch(name, value);
493 }
494
496 Status ProcessExtensions(const std::vector<std::string>& extensions, 495 Status ProcessExtensions(const std::vector<std::string>& extensions,
497 const base::FilePath& temp_dir, 496 const base::FilePath& temp_dir,
498 bool include_automation_extension, 497 bool include_automation_extension,
499 CommandLine* command, 498 Switches* switches,
500 std::vector<std::string>* bg_pages) { 499 std::vector<std::string>* bg_pages) {
501 std::vector<std::string> bg_pages_tmp; 500 std::vector<std::string> bg_pages_tmp;
502 std::vector<base::FilePath::StringType> extension_paths; 501 std::vector<base::FilePath::StringType> extension_paths;
503 for (size_t i = 0; i < extensions.size(); ++i) { 502 for (size_t i = 0; i < extensions.size(); ++i) {
504 base::FilePath path; 503 base::FilePath path;
505 std::string bg_page; 504 std::string bg_page;
506 Status status = ProcessExtension(extensions[i], temp_dir, &path, &bg_page); 505 Status status = ProcessExtension(extensions[i], temp_dir, &path, &bg_page);
507 if (status.IsError()) { 506 if (status.IsError()) {
508 return Status( 507 return Status(
509 kUnknownError, 508 kUnknownError,
510 base::StringPrintf("cannot process extension #%" PRIuS, i + 1), 509 base::StringPrintf("cannot process extension #%" PRIuS, i + 1),
511 status); 510 status);
512 } 511 }
513 extension_paths.push_back(path.value()); 512 extension_paths.push_back(path.value());
514 if (bg_page.length()) 513 if (bg_page.length())
515 bg_pages_tmp.push_back(bg_page); 514 bg_pages_tmp.push_back(bg_page);
516 } 515 }
517 516
518 if (include_automation_extension) { 517 if (include_automation_extension) {
519 base::FilePath automation_extension; 518 base::FilePath automation_extension;
520 Status status = UnpackAutomationExtension(temp_dir, &automation_extension); 519 Status status = UnpackAutomationExtension(temp_dir, &automation_extension);
521 if (status.IsError()) 520 if (status.IsError())
522 return status; 521 return status;
523 if (command->HasSwitch("disable-extensions")) { 522 if (switches->HasSwitch("disable-extensions")) {
524 command->AppendSwitchNative("load-component-extension", 523 UpdateExtensionSwitch(switches, "load-component-extension",
525 automation_extension.value()); 524 automation_extension.value());
526 } else { 525 } else {
527 extension_paths.push_back(automation_extension.value()); 526 extension_paths.push_back(automation_extension.value());
528 } 527 }
529 } 528 }
530 529
531 if (extension_paths.size()) { 530 if (extension_paths.size()) {
532 base::FilePath::StringType extension_paths_value = JoinString( 531 base::FilePath::StringType extension_paths_value = JoinString(
533 extension_paths, FILE_PATH_LITERAL(',')); 532 extension_paths, FILE_PATH_LITERAL(','));
534 command->AppendSwitchNative("load-extension", extension_paths_value); 533 UpdateExtensionSwitch(switches, "load-extension", extension_paths_value);
535 } 534 }
536 bg_pages->swap(bg_pages_tmp); 535 bg_pages->swap(bg_pages_tmp);
537 return Status(kOk); 536 return Status(kOk);
538 } 537 }
539 538
540 Status WritePrefsFile( 539 Status WritePrefsFile(
541 const std::string& template_string, 540 const std::string& template_string,
542 const base::DictionaryValue* custom_prefs, 541 const base::DictionaryValue* custom_prefs,
543 const base::FilePath& path) { 542 const base::FilePath& path) {
544 int code; 543 int code;
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
592 // Write empty "First Run" file, otherwise Chrome will wipe the default 591 // Write empty "First Run" file, otherwise Chrome will wipe the default
593 // profile that was written. 592 // profile that was written.
594 if (file_util::WriteFile( 593 if (file_util::WriteFile(
595 user_data_dir.AppendASCII("First Run"), "", 0) != 0) { 594 user_data_dir.AppendASCII("First Run"), "", 0) != 0) {
596 return Status(kUnknownError, "failed to write first run file"); 595 return Status(kUnknownError, "failed to write first run file");
597 } 596 }
598 return Status(kOk); 597 return Status(kOk);
599 } 598 }
600 599
601 } // namespace internal 600 } // namespace internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698