Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

Side by Side Diff: chrome/browser/chrome_select_file_dialog_factory_win.cc

Issue 419523006: Experimentally isolate GetOpenFileName in a utility process. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase. Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/chrome_select_file_dialog_factory_win.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2014 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/browser/chrome_select_file_dialog_factory_win.h"
6
7 #include <Windows.h>
8 #include <commdlg.h>
9
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/callback.h"
13 #include "base/location.h"
14 #include "base/logging.h"
15 #include "base/metrics/field_trial.h"
16 #include "base/strings/string16.h"
17 #include "base/synchronization/waitable_event.h"
18 #include "base/win/metro.h"
19 #include "chrome/common/chrome_utility_messages.h"
20 #include "content/public/browser/utility_process_host.h"
21 #include "content/public/browser/utility_process_host_client.h"
22 #include "ipc/ipc_message_macros.h"
23 #include "ui/base/win/open_file_name_win.h"
24 #include "ui/shell_dialogs/select_file_dialog_win.h"
25
26 namespace {
27
28 // Receives the GetOpenFileName result from the utility process.
29 class GetOpenFileNameClient : public content::UtilityProcessHostClient {
30 public:
31 GetOpenFileNameClient();
32
33 // Blocks until the GetOpenFileName result is received (including failure to
34 // launch or a crash of the utility process).
35 void WaitForCompletion();
36
37 // Returns the selected directory.
38 const base::FilePath& directory() const { return directory_; }
39
40 // Returns the list of selected filenames. Each should be interpreted as a
41 // child of directory().
42 const std::vector<base::FilePath>& filenames() const { return filenames_; }
43
44 // UtilityProcessHostClient implementation
45 virtual void OnProcessCrashed(int exit_code) OVERRIDE;
46 virtual void OnProcessLaunchFailed() OVERRIDE;
47 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
48
49 protected:
50 virtual ~GetOpenFileNameClient();
51
52 private:
53 void OnResult(const base::FilePath& directory,
54 const std::vector<base::FilePath>& filenames);
55 void OnFailure();
56
57 base::FilePath directory_;
58 std::vector<base::FilePath> filenames_;
59 base::WaitableEvent event_;
60
61 DISALLOW_COPY_AND_ASSIGN(GetOpenFileNameClient);
62 };
63
64 GetOpenFileNameClient::GetOpenFileNameClient() : event_(true, false) {
65 }
66
67 void GetOpenFileNameClient::WaitForCompletion() {
68 event_.Wait();
69 }
70
71 void GetOpenFileNameClient::OnProcessCrashed(int exit_code) {
72 event_.Signal();
73 }
74
75 void GetOpenFileNameClient::OnProcessLaunchFailed() {
76 event_.Signal();
77 }
78
79 bool GetOpenFileNameClient::OnMessageReceived(const IPC::Message& message) {
80 bool handled = true;
81 IPC_BEGIN_MESSAGE_MAP(GetOpenFileNameClient, message)
82 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetOpenFileName_Failed,
83 OnFailure)
84 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetOpenFileName_Result,
85 OnResult)
86 IPC_MESSAGE_UNHANDLED(handled = false)
87 IPC_END_MESSAGE_MAP()
88 return handled;
89 }
90
91 GetOpenFileNameClient::~GetOpenFileNameClient() {}
92
93 void GetOpenFileNameClient::OnResult(
94 const base::FilePath& directory,
95 const std::vector<base::FilePath>& filenames) {
96 directory_ = directory;
97 filenames_ = filenames;
98 event_.Signal();
99 }
100
101 void GetOpenFileNameClient::OnFailure() {
102 event_.Signal();
103 }
104
105 // Initiates IPC with a new utility process using |client|. Instructs the
106 // utility process to call GetOpenFileName with |ofn|. |current_task_runner|
107 // must be the currently executing task runner.
108 void DoInvokeGetOpenFileName(
109 OPENFILENAME* ofn,
110 scoped_refptr<GetOpenFileNameClient> client,
111 const scoped_refptr<base::SequencedTaskRunner>& current_task_runner) {
112 DCHECK(current_task_runner->RunsTasksOnCurrentThread());
113
114 base::WeakPtr<content::UtilityProcessHost> utility_process_host(
115 content::UtilityProcessHost::Create(client, current_task_runner)
116 ->AsWeakPtr());
117 utility_process_host->DisableSandbox();
118 utility_process_host->Send(new ChromeUtilityMsg_GetOpenFileName(
119 ofn->hwndOwner,
120 ofn->Flags,
121 ui::win::OpenFileName::GetFilters(ofn),
122 base::FilePath(ofn->lpstrInitialDir ? ofn->lpstrInitialDir
123 : base::string16()),
124 base::FilePath(ofn->lpstrFile)));
125 }
126
127 // Invokes GetOpenFileName in a utility process. Blocks until the result is
128 // received. Uses |blocking_task_runner| for IPC.
129 bool GetOpenFileNameInUtilityProcess(
130 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
131 OPENFILENAME* ofn) {
132 scoped_refptr<GetOpenFileNameClient> client(new GetOpenFileNameClient);
133 blocking_task_runner->PostTask(
134 FROM_HERE,
135 base::Bind(&DoInvokeGetOpenFileName,
136 base::Unretained(ofn), client, blocking_task_runner));
137 client->WaitForCompletion();
138
139 if (!client->filenames().size())
140 return false;
141
142 ui::win::OpenFileName::SetResult(
143 client->directory(), client->filenames(), ofn);
144 return true;
145 }
146
147 // Implements GetOpenFileName for CreateWinSelectFileDialog by delegating either
148 // to Metro or a utility process.
149 bool GetOpenFileNameImpl(
150 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
151 OPENFILENAME* ofn) {
152 HMODULE metro_module = base::win::GetMetroModule();
153 if (metro_module != NULL) {
154 typedef BOOL (*MetroGetOpenFileName)(OPENFILENAME*);
155 MetroGetOpenFileName metro_get_open_file_name =
156 reinterpret_cast<MetroGetOpenFileName>(
157 ::GetProcAddress(metro_module, "MetroGetOpenFileName"));
158 if (metro_get_open_file_name == NULL) {
159 NOTREACHED();
160 return false;
161 }
162
163 return metro_get_open_file_name(ofn) == TRUE;
164 }
165
166 if (base::FieldTrialList::FindFullName("IsolateShellOperations") ==
167 "Enabled") {
168 return GetOpenFileNameInUtilityProcess(blocking_task_runner, ofn);
169 }
170
171 return ::GetOpenFileName(ofn) == TRUE;
172 }
173
174 } // namespace
175
176 ChromeSelectFileDialogFactory::ChromeSelectFileDialogFactory(
177 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner)
178 : blocking_task_runner_(blocking_task_runner) {
179 }
180
181 ChromeSelectFileDialogFactory::~ChromeSelectFileDialogFactory() {}
182
183 ui::SelectFileDialog* ChromeSelectFileDialogFactory::Create(
184 ui::SelectFileDialog::Listener* listener,
185 ui::SelectFilePolicy* policy) {
186 return ui::CreateWinSelectFileDialog(
187 listener,
188 policy,
189 base::Bind(GetOpenFileNameImpl, blocking_task_runner_));
190 }
OLDNEW
« no previous file with comments | « chrome/browser/chrome_select_file_dialog_factory_win.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698