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

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
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() { return directory_; }
sky 2014/07/31 20:47:46 make const.
erikwright (departed) 2014/08/01 13:53:15 Done.
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() { return filenames_; }
sky 2014/07/31 20:47:46 make const
erikwright (departed) 2014/08/01 13:53:15 Done.
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 GetOpenFileNameClient::~GetOpenFileNameClient() {}
sky 2014/07/31 20:47:46 declaration/definition order should match.
erikwright (departed) 2014/08/01 13:53:15 Done.
68
69 void GetOpenFileNameClient::WaitForCompletion() {
70 event_.Wait();
71 }
72
73 void GetOpenFileNameClient::OnProcessCrashed(int exit_code) {
74 event_.Signal();
75 }
76
77 void GetOpenFileNameClient::OnProcessLaunchFailed() {
78 event_.Signal();
79 }
80
81 bool GetOpenFileNameClient::OnMessageReceived(const IPC::Message& message) {
82 bool handled = true;
83 IPC_BEGIN_MESSAGE_MAP(GetOpenFileNameClient, message)
84 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetOpenFileName_Failed,
85 OnFailure)
86 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetOpenFileName_Result,
87 OnResult)
88 IPC_MESSAGE_UNHANDLED(handled = false)
89 IPC_END_MESSAGE_MAP()
90 return handled;
91 }
92
93 void GetOpenFileNameClient::OnResult(const base::FilePath& directory,
94 const std::vector<base::FilePath> &
sky 2014/07/31 20:47:46 wrapping here is weird. & should be next to >
erikwright (departed) 2014/08/01 13:53:15 Done.
95 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 : L""),
sky 2014/07/31 20:47:46 ""->std::wstring or string16.
erikwright (departed) 2014/08/01 13:53:15 Done.
123 base::FilePath(ofn->lpstrFile)));
124 }
125
126 // Invokes GetOpenFileName in a utility process. Blocks until the result is
127 // received. Uses |blocking_task_runner| for IPC.
128 bool GetOpenFileNameInUtilityProcess(
129 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
130 OPENFILENAME* ofn) {
131 scoped_refptr<GetOpenFileNameClient> client(new GetOpenFileNameClient);
132 blocking_task_runner->PostTask(
133 FROM_HERE,
134 base::Bind(&DoInvokeGetOpenFileName,
135 base::Unretained(ofn), client, blocking_task_runner));
136 client->WaitForCompletion();
137
138 if (!client->filenames().size())
139 return false;
140
141 ui::win::OpenFileName::SetResult(
142 client->directory(), client->filenames(), ofn);
143 return true;
144 }
145
146 // Implements GetOpenFileName for CreateWinSelectFileDialog by delegating either
147 // to Metro or a utility process.
148 bool GetOpenFileNameImpl(
149 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
150 OPENFILENAME* ofn) {
151 HMODULE metro_module = base::win::GetMetroModule();
152 if (metro_module != NULL) {
153 typedef BOOL (*MetroGetOpenFileName)(OPENFILENAME*);
154 MetroGetOpenFileName metro_get_open_file_name =
155 reinterpret_cast<MetroGetOpenFileName>(
156 ::GetProcAddress(metro_module, "MetroGetOpenFileName"));
157 if (metro_get_open_file_name == NULL) {
158 NOTREACHED();
159 return false;
160 }
161
162 return metro_get_open_file_name(ofn) == TRUE;
163 } else if (base::FieldTrialList::FindFullName("IsolateShellOperations") ==
sky 2014/07/31 20:47:46 nit: no else after return here and 166.
erikwright (departed) 2014/08/01 13:53:15 Done.
164 "Enabled") {
165 return GetOpenFileNameInUtilityProcess(blocking_task_runner, ofn);
166 } else {
167 return ::GetOpenFileName(ofn) == TRUE;
168 }
169 }
170
171 } // namespace
172
173 ChromeSelectFileDialogFactory::ChromeSelectFileDialogFactory(
174 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner)
175 : blocking_task_runner_(blocking_task_runner) {
176 }
177
178 ChromeSelectFileDialogFactory::~ChromeSelectFileDialogFactory() {}
179
180 ui::SelectFileDialog* ChromeSelectFileDialogFactory::Create(
181 ui::SelectFileDialog::Listener* listener,
182 ui::SelectFilePolicy* policy) {
183 return ui::CreateWinSelectFileDialog(
184 listener,
185 policy,
186 base::Bind(GetOpenFileNameImpl, blocking_task_runner_));
187 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698