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