Add elapsed time and timeout value to feedback data.
[chromium-blink-merge.git] / win8 / viewer / metro_viewer_process_host.cc
blob348dfda678bbceb276a0ec1e160d5c2f7d1937d4
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.
5 #include "win8/viewer/metro_viewer_process_host.h"
7 #include <shlobj.h>
9 #include "base/command_line.h"
10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/path_service.h"
14 #include "base/process/process.h"
15 #include "base/strings/string16.h"
16 #include "base/synchronization/waitable_event.h"
17 #include "base/time/time.h"
18 #include "base/win/scoped_comptr.h"
19 #include "base/win/windows_version.h"
20 #include "ipc/ipc_channel_proxy.h"
21 #include "ipc/ipc_message.h"
22 #include "ipc/ipc_message_macros.h"
23 #include "ui/aura/remote_window_tree_host_win.h"
24 #include "ui/metro_viewer/metro_viewer_messages.h"
25 #include "win8/viewer/metro_viewer_constants.h"
27 namespace {
29 const int kViewerProcessConnectionTimeoutSecs = 60;
31 } // namespace
33 namespace win8 {
35 // static
36 MetroViewerProcessHost* MetroViewerProcessHost::instance_ = NULL;
38 MetroViewerProcessHost::InternalMessageFilter::InternalMessageFilter(
39 MetroViewerProcessHost* owner)
40 : owner_(owner) {
43 void MetroViewerProcessHost::InternalMessageFilter::OnChannelConnected(
44 int32 peer_pid) {
45 owner_->NotifyChannelConnected();
48 MetroViewerProcessHost::InternalMessageFilter::~InternalMessageFilter() {
51 MetroViewerProcessHost::MetroViewerProcessHost(
52 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner) {
53 DCHECK(!instance_);
54 instance_ = this;
56 channel_ = IPC::ChannelProxy::Create(kMetroViewerIPCChannelName,
57 IPC::Channel::MODE_NAMED_SERVER,
58 this,
59 ipc_task_runner);
62 MetroViewerProcessHost::~MetroViewerProcessHost() {
63 if (!channel_) {
64 instance_ = NULL;
65 return;
68 base::ProcessId viewer_process_id = GetViewerProcessId();
69 channel_->Close();
70 if (message_filter_.get()) {
71 // Wait for the viewer process to go away.
72 if (viewer_process_id != base::kNullProcessId) {
73 base::Process viewer_process =
74 base::Process::OpenWithAccess(
75 viewer_process_id,
76 PROCESS_QUERY_INFORMATION | SYNCHRONIZE);
77 if (viewer_process.IsValid()) {
78 int exit_code;
79 viewer_process.WaitForExit(&exit_code);
82 channel_->RemoveFilter(message_filter_.get());
84 instance_ = NULL;
87 base::ProcessId MetroViewerProcessHost::GetViewerProcessId() {
88 if (channel_)
89 return channel_->GetPeerPID();
90 return base::kNullProcessId;
93 bool MetroViewerProcessHost::LaunchViewerAndWaitForConnection(
94 const base::string16& app_user_model_id) {
95 DCHECK_EQ(base::kNullProcessId, channel_->GetPeerPID());
97 channel_connected_event_.reset(new base::WaitableEvent(false, false));
99 message_filter_ = new InternalMessageFilter(this);
100 channel_->AddFilter(message_filter_.get());
102 if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
103 base::win::ScopedComPtr<IApplicationActivationManager> activator;
104 HRESULT hr = activator.CreateInstance(CLSID_ApplicationActivationManager);
105 if (SUCCEEDED(hr)) {
106 DWORD pid = 0;
107 // Use the "connect" verb to
108 hr = activator->ActivateApplication(
109 app_user_model_id.c_str(), kMetroViewerConnectVerb, AO_NONE, &pid);
112 LOG_IF(ERROR, FAILED(hr)) << "Tried and failed to launch Metro Chrome. "
113 << "hr=" << std::hex << hr;
114 } else {
115 // For Windows 7 we need to launch the viewer ourselves.
116 base::FilePath chrome_path;
117 if (!PathService::Get(base::DIR_EXE, &chrome_path))
118 return false;
119 // TODO(cpu): launch with "-ServerName:DefaultBrowserServer"
120 // note that the viewer might try to launch chrome again.
121 CHECK(false);
124 // Having launched the viewer process, now we wait for it to connect.
125 bool success =
126 channel_connected_event_->TimedWait(base::TimeDelta::FromSeconds(
127 kViewerProcessConnectionTimeoutSecs));
128 channel_connected_event_.reset();
129 return success;
132 bool MetroViewerProcessHost::Send(IPC::Message* msg) {
133 return channel_->Send(msg);
136 bool MetroViewerProcessHost::OnMessageReceived(
137 const IPC::Message& message) {
138 DCHECK(CalledOnValidThread());
139 bool handled = true;
140 IPC_BEGIN_MESSAGE_MAP(MetroViewerProcessHost, message)
141 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_FileSaveAsDone,
142 OnFileSaveAsDone)
143 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_FileOpenDone,
144 OnFileOpenDone)
145 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MultiFileOpenDone,
146 OnMultiFileOpenDone)
147 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_OpenURL, OnOpenURL)
148 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SearchRequest, OnHandleSearchRequest)
149 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SelectFolderDone,
150 OnSelectFolderDone)
151 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetTargetSurface, OnSetTargetSurface)
152 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_WindowSizeChanged,
153 OnWindowSizeChanged)
154 IPC_MESSAGE_UNHANDLED(handled = false)
155 IPC_END_MESSAGE_MAP()
156 return handled ? true :
157 aura::RemoteWindowTreeHostWin::Instance()->OnMessageReceived(message);
160 // static
161 void MetroViewerProcessHost::HandleActivateDesktop(
162 const base::FilePath& path,
163 bool ash_exit) {
164 if (instance_) {
165 instance_->Send(
166 new MetroViewerHostMsg_ActivateDesktop(path, ash_exit));
170 // static
171 void MetroViewerProcessHost::HandleMetroExit() {
172 if (instance_)
173 instance_->Send(new MetroViewerHostMsg_MetroExit());
176 // static
177 void MetroViewerProcessHost::HandleOpenFile(
178 const base::string16& title,
179 const base::FilePath& default_path,
180 const base::string16& filter,
181 const OpenFileCompletion& on_success,
182 const FileSelectionCanceled& on_failure) {
183 if (instance_) {
184 instance_->HandleOpenFileImpl(title, default_path, filter, on_success,
185 on_failure);
189 // static
190 void MetroViewerProcessHost::HandleOpenMultipleFiles(
191 const base::string16& title,
192 const base::FilePath& default_path,
193 const base::string16& filter,
194 const OpenMultipleFilesCompletion& on_success,
195 const FileSelectionCanceled& on_failure) {
196 if (instance_) {
197 instance_->HandleOpenMultipleFilesImpl(title, default_path, filter,
198 on_success, on_failure);
202 // static
203 void MetroViewerProcessHost::HandleSaveFile(
204 const base::string16& title,
205 const base::FilePath& default_path,
206 const base::string16& filter,
207 int filter_index,
208 const base::string16& default_extension,
209 const SaveFileCompletion& on_success,
210 const FileSelectionCanceled& on_failure) {
211 if (instance_) {
212 instance_->HandleSaveFileImpl(title, default_path, filter, filter_index,
213 default_extension, on_success, on_failure);
217 // static
218 void MetroViewerProcessHost::HandleSelectFolder(
219 const base::string16& title,
220 const SelectFolderCompletion& on_success,
221 const FileSelectionCanceled& on_failure) {
222 if (instance_)
223 instance_->HandleSelectFolderImpl(title, on_success, on_failure);
226 void MetroViewerProcessHost::HandleOpenFileImpl(
227 const base::string16& title,
228 const base::FilePath& default_path,
229 const base::string16& filter,
230 const OpenFileCompletion& on_success,
231 const FileSelectionCanceled& on_failure) {
232 // Can only have one of these operations in flight.
233 DCHECK(file_open_completion_callback_.is_null());
234 DCHECK(failure_callback_.is_null());
236 file_open_completion_callback_ = on_success;
237 failure_callback_ = on_failure;
239 Send(new MetroViewerHostMsg_DisplayFileOpen(title, filter, default_path,
240 false));
243 void MetroViewerProcessHost::HandleOpenMultipleFilesImpl(
244 const base::string16& title,
245 const base::FilePath& default_path,
246 const base::string16& filter,
247 const OpenMultipleFilesCompletion& on_success,
248 const FileSelectionCanceled& on_failure) {
249 // Can only have one of these operations in flight.
250 DCHECK(multi_file_open_completion_callback_.is_null());
251 DCHECK(failure_callback_.is_null());
252 multi_file_open_completion_callback_ = on_success;
253 failure_callback_ = on_failure;
255 Send(new MetroViewerHostMsg_DisplayFileOpen(title, filter, default_path,
256 true));
259 void MetroViewerProcessHost::HandleSaveFileImpl(
260 const base::string16& title,
261 const base::FilePath& default_path,
262 const base::string16& filter,
263 int filter_index,
264 const base::string16& default_extension,
265 const SaveFileCompletion& on_success,
266 const FileSelectionCanceled& on_failure) {
267 MetroViewerHostMsg_SaveAsDialogParams params;
268 params.title = title;
269 params.default_extension = default_extension;
270 params.filter = filter;
271 params.filter_index = filter_index;
272 params.suggested_name = default_path;
274 // Can only have one of these operations in flight.
275 DCHECK(file_saveas_completion_callback_.is_null());
276 DCHECK(failure_callback_.is_null());
277 file_saveas_completion_callback_ = on_success;
278 failure_callback_ = on_failure;
280 Send(new MetroViewerHostMsg_DisplayFileSaveAs(params));
283 void MetroViewerProcessHost::HandleSelectFolderImpl(
284 const base::string16& title,
285 const SelectFolderCompletion& on_success,
286 const FileSelectionCanceled& on_failure) {
287 // Can only have one of these operations in flight.
288 DCHECK(select_folder_completion_callback_.is_null());
289 DCHECK(failure_callback_.is_null());
290 select_folder_completion_callback_ = on_success;
291 failure_callback_ = on_failure;
293 Send(new MetroViewerHostMsg_DisplaySelectFolder(title));
296 void MetroViewerProcessHost::NotifyChannelConnected() {
297 if (channel_connected_event_)
298 channel_connected_event_->Signal();
301 void MetroViewerProcessHost::OnFileSaveAsDone(bool success,
302 const base::FilePath& filename,
303 int filter_index) {
304 if (success)
305 file_saveas_completion_callback_.Run(filename, filter_index, NULL);
306 else
307 failure_callback_.Run(NULL);
308 file_saveas_completion_callback_.Reset();
309 failure_callback_.Reset();
313 void MetroViewerProcessHost::OnFileOpenDone(bool success,
314 const base::FilePath& filename) {
315 if (success)
316 file_open_completion_callback_.Run(base::FilePath(filename), 0, NULL);
317 else
318 failure_callback_.Run(NULL);
319 file_open_completion_callback_.Reset();
320 failure_callback_.Reset();
323 void MetroViewerProcessHost::OnMultiFileOpenDone(
324 bool success,
325 const std::vector<base::FilePath>& files) {
326 if (success)
327 multi_file_open_completion_callback_.Run(files, NULL);
328 else
329 failure_callback_.Run(NULL);
330 multi_file_open_completion_callback_.Reset();
331 failure_callback_.Reset();
334 void MetroViewerProcessHost::OnSelectFolderDone(
335 bool success,
336 const base::FilePath& folder) {
337 if (success)
338 select_folder_completion_callback_.Run(base::FilePath(folder), 0, NULL);
339 else
340 failure_callback_.Run(NULL);
341 select_folder_completion_callback_.Reset();
342 failure_callback_.Reset();
345 } // namespace win8