- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / test / chromedriver / chrome / chrome_desktop_impl.cc
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
3 // found in the LICENSE file.
4
5 #include "chrome/test/chromedriver/chrome/chrome_desktop_impl.h"
6
7 #include "base/files/file_path.h"
8 #include "base/logging.h"
9 #include "base/posix/eintr_wrapper.h"
10 #include "base/process/kill.h"
11 #include "base/sys_info.h"
12 #include "base/threading/platform_thread.h"
13 #include "base/time/time.h"
14 #include "chrome/test/chromedriver/chrome/automation_extension.h"
15 #include "chrome/test/chromedriver/chrome/devtools_client.h"
16 #include "chrome/test/chromedriver/chrome/devtools_http_client.h"
17 #include "chrome/test/chromedriver/chrome/status.h"
18 #include "chrome/test/chromedriver/chrome/web_view_impl.h"
19 #include "chrome/test/chromedriver/net/port_server.h"
20
21 #if defined(OS_POSIX)
22 #include <errno.h>
23 #include <signal.h>
24 #include <sys/wait.h>
25 #include <unistd.h>
26 #endif
27
28 namespace {
29
30 bool KillProcess(base::ProcessHandle process_id) {
31 #if defined(OS_POSIX)
32   kill(process_id, SIGKILL);
33   base::TimeTicks deadline =
34       base::TimeTicks::Now() + base::TimeDelta::FromSeconds(5);
35   while (base::TimeTicks::Now() < deadline) {
36     pid_t pid = HANDLE_EINTR(waitpid(process_id, NULL, WNOHANG));
37     if (pid == process_id)
38       return true;
39     if (pid == -1) {
40       if (errno == ECHILD) {
41         // The wait may fail with ECHILD if another process also waited for
42         // the same pid, causing the process state to get cleaned up.
43         return true;
44       }
45       LOG(WARNING) << "Error waiting for process " << process_id;
46     }
47     base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50));
48   }
49   return false;
50 #endif
51
52 #if defined(OS_WIN)
53   if (!base::KillProcess(process_id, 0, true)) {
54     int exit_code;
55     return base::GetTerminationStatus(process_id, &exit_code) !=
56         base::TERMINATION_STATUS_STILL_RUNNING;
57   }
58   return true;
59 #endif
60 }
61
62 }  // namespace
63
64 ChromeDesktopImpl::ChromeDesktopImpl(
65     scoped_ptr<DevToolsHttpClient> client,
66     ScopedVector<DevToolsEventListener>& devtools_event_listeners,
67     scoped_ptr<PortReservation> port_reservation,
68     base::ProcessHandle process,
69     const CommandLine& command,
70     base::ScopedTempDir* user_data_dir,
71     base::ScopedTempDir* extension_dir)
72     : ChromeImpl(client.Pass(),
73                  devtools_event_listeners,
74                  port_reservation.Pass()),
75       process_(process),
76       command_(command) {
77   if (user_data_dir->IsValid())
78     CHECK(user_data_dir_.Set(user_data_dir->Take()));
79   if (extension_dir->IsValid())
80     CHECK(extension_dir_.Set(extension_dir->Take()));
81 }
82
83 ChromeDesktopImpl::~ChromeDesktopImpl() {
84   if (!quit_) {
85     base::FilePath user_data_dir = user_data_dir_.Take();
86     base::FilePath extension_dir = extension_dir_.Take();
87     LOG(WARNING) << "chrome detaches, user should take care of directory:"
88                  << user_data_dir.value() << " and " << extension_dir.value();
89   }
90   base::CloseProcessHandle(process_);
91 }
92
93 Status ChromeDesktopImpl::WaitForPageToLoad(const std::string& url,
94                                             const base::TimeDelta& timeout,
95                                             scoped_ptr<WebView>* web_view) {
96   base::TimeTicks deadline = base::TimeTicks::Now() + timeout;
97   std::string id;
98   while (base::TimeTicks::Now() < deadline) {
99     WebViewsInfo views_info;
100     Status status = devtools_http_client_->GetWebViewsInfo(&views_info);
101     if (status.IsError())
102       return status;
103
104     for (size_t i = 0; i < views_info.GetSize(); ++i) {
105       if (views_info.Get(i).url.find(url) == 0) {
106         id = views_info.Get(i).id;
107         break;
108       }
109     }
110     if (!id.empty())
111       break;
112     base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
113   }
114   if (id.empty())
115     return Status(kUnknownError, "page could not be found: " + url);
116
117   scoped_ptr<WebView> web_view_tmp(new WebViewImpl(
118       id, GetBuildNo(), devtools_http_client_->CreateClient(id)));
119   Status status = web_view_tmp->ConnectIfNecessary();
120   if (status.IsError())
121     return status;
122
123   status = web_view_tmp->WaitForPendingNavigations(
124       std::string(), deadline - base::TimeTicks::Now(), false);
125   if (status.IsOk())
126     *web_view = web_view_tmp.Pass();
127   return status;
128 }
129
130 Status ChromeDesktopImpl::GetAutomationExtension(
131     AutomationExtension** extension) {
132   if (!automation_extension_) {
133     scoped_ptr<WebView> web_view;
134     Status status = WaitForPageToLoad(
135         "chrome-extension://aapnijgdinlhnhlmodcfapnahmbfebeb/"
136         "_generated_background_page.html",
137         base::TimeDelta::FromSeconds(10),
138         &web_view);
139     if (status.IsError())
140       return Status(kUnknownError, "cannot get automation extension", status);
141
142     automation_extension_.reset(new AutomationExtension(web_view.Pass()));
143   }
144   *extension = automation_extension_.get();
145   return Status(kOk);
146 }
147
148 ChromeDesktopImpl* ChromeDesktopImpl::GetAsDesktop() {
149   return this;
150 }
151
152 std::string ChromeDesktopImpl::GetOperatingSystemName() {
153   return base::SysInfo::OperatingSystemName();
154 }
155
156 Status ChromeDesktopImpl::QuitImpl() {
157   if (!KillProcess(process_))
158     return Status(kUnknownError, "cannot kill Chrome");
159   return Status(kOk);
160 }
161
162 const CommandLine& ChromeDesktopImpl::command() const {
163   return command_;
164 }