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

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

Issue 487453002: Experimentally isolate GetSaveFileName in a utility process. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Small cleanups. 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
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/chrome_select_file_dialog_factory_win.h" 5 #include "chrome/browser/chrome_select_file_dialog_factory_win.h"
6 6
7 #include <Windows.h> 7 #include <Windows.h>
8 #include <commdlg.h> 8 #include <commdlg.h>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/bind_helpers.h" 11 #include "base/bind_helpers.h"
12 #include "base/callback.h" 12 #include "base/callback.h"
13 #include "base/location.h" 13 #include "base/location.h"
14 #include "base/logging.h" 14 #include "base/logging.h"
15 #include "base/metrics/field_trial.h" 15 #include "base/metrics/field_trial.h"
16 #include "base/strings/string16.h" 16 #include "base/strings/string16.h"
17 #include "base/synchronization/waitable_event.h" 17 #include "base/synchronization/waitable_event.h"
18 #include "base/win/metro.h" 18 #include "base/win/metro.h"
19 #include "chrome/common/chrome_utility_messages.h" 19 #include "chrome/common/chrome_utility_messages.h"
20 #include "content/public/browser/utility_process_host.h" 20 #include "content/public/browser/utility_process_host.h"
21 #include "content/public/browser/utility_process_host_client.h" 21 #include "content/public/browser/utility_process_host_client.h"
22 #include "ipc/ipc_message_macros.h" 22 #include "ipc/ipc_message_macros.h"
23 #include "ui/base/win/open_file_name_win.h" 23 #include "ui/base/win/open_file_name_win.h"
24 #include "ui/shell_dialogs/select_file_dialog_win.h" 24 #include "ui/shell_dialogs/select_file_dialog_win.h"
25 25
26 namespace { 26 namespace {
27 27
28 bool CallMetroOPENFILENAMEMethod(const char* method_name, OPENFILENAME* ofn) {
29 typedef BOOL (*MetroOPENFILENAMEMethod)(OPENFILENAME*);
30 MetroOPENFILENAMEMethod metro_method = NULL;
31 HMODULE metro_module = base::win::GetMetroModule();
32
33 if (metro_module != NULL) {
34 metro_method = reinterpret_cast<MetroOPENFILENAMEMethod>(
35 ::GetProcAddress(metro_module, method_name));
36 }
37
38 if (metro_method != NULL)
39 return metro_method(ofn) == TRUE;
40
41 NOTREACHED();
42
43 return false;
44 }
45
46 bool ShouldIsolateShellOperations() {
47 return base::FieldTrialList::FindFullName("IsolateShellOperations") ==
48 "Enabled";
49 }
50
28 // Receives the GetOpenFileName result from the utility process. 51 // Receives the GetOpenFileName result from the utility process.
29 class GetOpenFileNameClient : public content::UtilityProcessHostClient { 52 class GetOpenFileNameClient : public content::UtilityProcessHostClient {
30 public: 53 public:
31 GetOpenFileNameClient(); 54 GetOpenFileNameClient();
32 55
33 // Blocks until the GetOpenFileName result is received (including failure to 56 // Blocks until the GetOpenFileName result is received (including failure to
34 // launch or a crash of the utility process). 57 // launch or a crash of the utility process).
35 void WaitForCompletion(); 58 void WaitForCompletion();
36 59
37 // Returns the selected directory. 60 // Returns the selected directory.
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 scoped_refptr<GetOpenFileNameClient> client, 133 scoped_refptr<GetOpenFileNameClient> client,
111 const scoped_refptr<base::SequencedTaskRunner>& current_task_runner) { 134 const scoped_refptr<base::SequencedTaskRunner>& current_task_runner) {
112 DCHECK(current_task_runner->RunsTasksOnCurrentThread()); 135 DCHECK(current_task_runner->RunsTasksOnCurrentThread());
113 136
114 base::WeakPtr<content::UtilityProcessHost> utility_process_host( 137 base::WeakPtr<content::UtilityProcessHost> utility_process_host(
115 content::UtilityProcessHost::Create(client, current_task_runner) 138 content::UtilityProcessHost::Create(client, current_task_runner)
116 ->AsWeakPtr()); 139 ->AsWeakPtr());
117 utility_process_host->DisableSandbox(); 140 utility_process_host->DisableSandbox();
118 utility_process_host->Send(new ChromeUtilityMsg_GetOpenFileName( 141 utility_process_host->Send(new ChromeUtilityMsg_GetOpenFileName(
119 ofn->hwndOwner, 142 ofn->hwndOwner,
120 ofn->Flags, 143 ofn->Flags & ~OFN_ENABLEHOOK, // We can't send a hook function over IPC.
121 ui::win::OpenFileName::GetFilters(ofn), 144 ui::win::OpenFileName::GetFilters(ofn),
122 base::FilePath(ofn->lpstrInitialDir ? ofn->lpstrInitialDir 145 base::FilePath(ofn->lpstrInitialDir ? ofn->lpstrInitialDir
123 : base::string16()), 146 : base::string16()),
124 base::FilePath(ofn->lpstrFile))); 147 base::FilePath(ofn->lpstrFile)));
125 } 148 }
126 149
127 // Invokes GetOpenFileName in a utility process. Blocks until the result is 150 // Invokes GetOpenFileName in a utility process. Blocks until the result is
128 // received. Uses |blocking_task_runner| for IPC. 151 // received. Uses |blocking_task_runner| for IPC.
129 bool GetOpenFileNameInUtilityProcess( 152 bool GetOpenFileNameInUtilityProcess(
130 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner, 153 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
(...skipping 11 matching lines...) Expand all
142 ui::win::OpenFileName::SetResult( 165 ui::win::OpenFileName::SetResult(
143 client->directory(), client->filenames(), ofn); 166 client->directory(), client->filenames(), ofn);
144 return true; 167 return true;
145 } 168 }
146 169
147 // Implements GetOpenFileName for CreateWinSelectFileDialog by delegating either 170 // Implements GetOpenFileName for CreateWinSelectFileDialog by delegating either
148 // to Metro or a utility process. 171 // to Metro or a utility process.
149 bool GetOpenFileNameImpl( 172 bool GetOpenFileNameImpl(
150 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner, 173 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
151 OPENFILENAME* ofn) { 174 OPENFILENAME* ofn) {
152 HMODULE metro_module = base::win::GetMetroModule(); 175 if (base::win::IsMetroProcess())
153 if (metro_module != NULL) { 176 return CallMetroOPENFILENAMEMethod("MetroGetOpenFileName", ofn);
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 177
163 return metro_get_open_file_name(ofn) == TRUE; 178 if (ShouldIsolateShellOperations())
164 }
165
166 if (base::FieldTrialList::FindFullName("IsolateShellOperations") ==
167 "Enabled") {
168 return GetOpenFileNameInUtilityProcess(blocking_task_runner, ofn); 179 return GetOpenFileNameInUtilityProcess(blocking_task_runner, ofn);
169 }
170 180
171 return ::GetOpenFileName(ofn) == TRUE; 181 return ::GetOpenFileName(ofn) == TRUE;
172 } 182 }
173 183
184 class GetSaveFileNameClient : public content::UtilityProcessHostClient {
185 public:
186 GetSaveFileNameClient();
187
188 // Blocks until the GetSaveFileName result is received (including failure to
189 // launch or a crash of the utility process).
190 void WaitForCompletion();
191
192 // Returns the selected path.
193 const base::FilePath& path() const { return path_; }
194
195 // Returns the index of the user-selected filter.
196 int one_based_filter_index() const { return one_based_filter_index_; }
197
198 // UtilityProcessHostClient implementation
199 virtual void OnProcessCrashed(int exit_code) OVERRIDE;
200 virtual void OnProcessLaunchFailed() OVERRIDE;
201 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
202
203 protected:
204 virtual ~GetSaveFileNameClient();
205
206 private:
207 void OnResult(const base::FilePath& path, int one_based_filter_index);
208 void OnFailure();
209
210 base::FilePath path_;
211 int one_based_filter_index_;
212 base::WaitableEvent event_;
213
214 DISALLOW_COPY_AND_ASSIGN(GetSaveFileNameClient);
215 };
216
217 GetSaveFileNameClient::GetSaveFileNameClient()
218 : event_(true, false), one_based_filter_index_(0) {
219 }
220
221 void GetSaveFileNameClient::WaitForCompletion() {
222 event_.Wait();
223 }
224
225 void GetSaveFileNameClient::OnProcessCrashed(int exit_code) {
226 event_.Signal();
227 }
228
229 void GetSaveFileNameClient::OnProcessLaunchFailed() {
230 event_.Signal();
231 }
232
233 bool GetSaveFileNameClient::OnMessageReceived(const IPC::Message& message) {
234 bool handled = true;
235 IPC_BEGIN_MESSAGE_MAP(GetSaveFileNameClient, message)
236 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetSaveFileName_Failed,
237 OnFailure)
238 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetSaveFileName_Result,
239 OnResult)
240 IPC_MESSAGE_UNHANDLED(handled = false)
241 IPC_END_MESSAGE_MAP()
242 return handled;
243 }
244
245 GetSaveFileNameClient::~GetSaveFileNameClient() {}
246
247 void GetSaveFileNameClient::OnResult(const base::FilePath& path,
248 int one_based_filter_index) {
249 path_ = path;
250 one_based_filter_index_ = one_based_filter_index;
251 event_.Signal();
252 }
253
254 void GetSaveFileNameClient::OnFailure() {
255 event_.Signal();
256 }
257
258 // Initiates IPC with a new utility process using |client|. Instructs the
259 // utility process to call GetSaveFileName with |ofn|. |current_task_runner|
260 // must be the currently executing task runner.
261 void DoInvokeGetSaveFileName(
262 OPENFILENAME* ofn,
263 scoped_refptr<GetSaveFileNameClient> client,
264 const scoped_refptr<base::SequencedTaskRunner>& current_task_runner) {
265 DCHECK(current_task_runner->RunsTasksOnCurrentThread());
266
267 base::WeakPtr<content::UtilityProcessHost> utility_process_host(
268 content::UtilityProcessHost::Create(client, current_task_runner)
269 ->AsWeakPtr());
270 utility_process_host->DisableSandbox();
271 ChromeUtilityMsg_GetSaveFileName_Params params;
272 params.owner = ofn->hwndOwner;
273 // We can't pass the hook function over IPC.
274 params.flags = ofn->Flags & ~OFN_ENABLEHOOK;
275 params.filters = ui::win::OpenFileName::GetFilters(ofn);
276 params.one_based_filter_index = ofn->nFilterIndex;
277 params.suggested_filename = base::FilePath(ofn->lpstrFile);
278 params.initial_directory = base::FilePath(
279 ofn->lpstrInitialDir ? ofn->lpstrInitialDir : base::string16());
280 params.default_extension =
281 ofn->lpstrDefExt ? base::string16(ofn->lpstrDefExt) : base::string16();
282
283 utility_process_host->Send(new ChromeUtilityMsg_GetSaveFileName(params));
284 }
285
286 // Invokes GetSaveFileName in a utility process. Blocks until the result is
287 // received. Uses |blocking_task_runner| for IPC.
288 bool GetSaveFileNameInUtilityProcess(
289 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
290 OPENFILENAME* ofn) {
291 scoped_refptr<GetSaveFileNameClient> client(new GetSaveFileNameClient);
292 blocking_task_runner->PostTask(
293 FROM_HERE,
294 base::Bind(&DoInvokeGetSaveFileName,
295 base::Unretained(ofn), client, blocking_task_runner));
296 client->WaitForCompletion();
297
298 if (client->path().empty())
299 return false;
300
301 base::wcslcpy(ofn->lpstrFile, client->path().value().c_str(), ofn->nMaxFile);
302 ofn->nFilterIndex = client->one_based_filter_index();
303
304 return true;
305 }
306
307 // Implements GetSaveFileName for CreateWinSelectFileDialog by delegating either
308 // to Metro or a utility process.
309 bool GetSaveFileNameImpl(
310 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
311 OPENFILENAME* ofn) {
312 if (base::win::IsMetroProcess())
313 return CallMetroOPENFILENAMEMethod("MetroGetSaveFileName", ofn);
314
315 if (ShouldIsolateShellOperations())
316 return GetSaveFileNameInUtilityProcess(blocking_task_runner, ofn);
317
318 return ::GetSaveFileName(ofn) == TRUE;
319 }
320
174 } // namespace 321 } // namespace
175 322
176 ChromeSelectFileDialogFactory::ChromeSelectFileDialogFactory( 323 ChromeSelectFileDialogFactory::ChromeSelectFileDialogFactory(
177 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner) 324 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner)
178 : blocking_task_runner_(blocking_task_runner) { 325 : blocking_task_runner_(blocking_task_runner) {
179 } 326 }
180 327
181 ChromeSelectFileDialogFactory::~ChromeSelectFileDialogFactory() {} 328 ChromeSelectFileDialogFactory::~ChromeSelectFileDialogFactory() {}
182 329
183 ui::SelectFileDialog* ChromeSelectFileDialogFactory::Create( 330 ui::SelectFileDialog* ChromeSelectFileDialogFactory::Create(
184 ui::SelectFileDialog::Listener* listener, 331 ui::SelectFileDialog::Listener* listener,
185 ui::SelectFilePolicy* policy) { 332 ui::SelectFilePolicy* policy) {
186 return ui::CreateWinSelectFileDialog( 333 return ui::CreateWinSelectFileDialog(
187 listener, 334 listener,
188 policy, 335 policy,
189 base::Bind(GetOpenFileNameImpl, blocking_task_runner_)); 336 base::Bind(GetOpenFileNameImpl, blocking_task_runner_),
337 base::Bind(GetSaveFileNameImpl, blocking_task_runner_));
190 } 338 }
OLDNEW
« no previous file with comments | « no previous file | chrome/common/chrome_utility_messages.h » ('j') | ui/base/win/open_file_name_win.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698