Home | History | Annotate | Download | only in viewer
      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/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/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 
     39 MetroViewerProcessHost::InternalMessageFilter::InternalMessageFilter(
     40     MetroViewerProcessHost* owner)
     41     : owner_(owner) {
     42 }
     43 
     44 void MetroViewerProcessHost::InternalMessageFilter::OnChannelConnected(
     45     int32 peer_pid) {
     46   owner_->NotifyChannelConnected();
     47 }
     48 
     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 
     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 
     86 base::ProcessId MetroViewerProcessHost::GetViewerProcessId() {
     87   if (channel_)
     88     return channel_->GetPeerPID();
     89   return base::kNullProcessId;
     90 }
     91 
     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 
    131 bool MetroViewerProcessHost::Send(IPC::Message* msg) {
    132   return channel_->Send(msg);
    133 }
    134 
    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
    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
    170 void MetroViewerProcessHost::HandleMetroExit() {
    171   if (instance_)
    172     instance_->Send(new MetroViewerHostMsg_MetroExit());
    173 }
    174 
    175 // static
    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
    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
    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
    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 
    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 
    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 
    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 
    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 
    295 void MetroViewerProcessHost::NotifyChannelConnected() {
    296   if (channel_connected_event_)
    297     channel_connected_event_->Signal();
    298 }
    299 
    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 
    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 
    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 
    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