Upstream version 7.36.149.0
[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(30);
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(
118       new WebViewImpl(id,
119                       devtools_http_client_->browser_info(),
120                       devtools_http_client_->CreateClient(id)));
121   Status status = web_view_tmp->ConnectIfNecessary();
122   if (status.IsError())
123     return status;
124
125   status = web_view_tmp->WaitForPendingNavigations(
126       std::string(), deadline - base::TimeTicks::Now(), false);
127   if (status.IsOk())
128     *web_view = web_view_tmp.Pass();
129   return status;
130 }
131
132 Status ChromeDesktopImpl::GetAutomationExtension(
133     AutomationExtension** extension) {
134   if (!automation_extension_) {
135     scoped_ptr<WebView> web_view;
136     Status status = WaitForPageToLoad(
137         "chrome-extension://aapnijgdinlhnhlmodcfapnahmbfebeb/"
138         "_generated_background_page.html",
139         base::TimeDelta::FromSeconds(10),
140         &web_view);
141     if (status.IsError())
142       return Status(kUnknownError, "cannot get automation extension", status);
143
144     automation_extension_.reset(new AutomationExtension(web_view.Pass()));
145   }
146   *extension = automation_extension_.get();
147   return Status(kOk);
148 }
149
150 ChromeDesktopImpl* ChromeDesktopImpl::GetAsDesktop() {
151   return this;
152 }
153
154 std::string ChromeDesktopImpl::GetOperatingSystemName() {
155   return base::SysInfo::OperatingSystemName();
156 }
157
158 Status ChromeDesktopImpl::QuitImpl() {
159   if (!KillProcess(process_))
160     return Status(kUnknownError, "cannot kill Chrome");
161   return Status(kOk);
162 }
163
164 const CommandLine& ChromeDesktopImpl::command() const {
165   return command_;
166 }