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

Side by Side Diff: chrome/browser/win/chrome_select_file_dialog_factory.cc

Issue 2141093005: Revert of Revive experiment to isolate shell operations. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 5 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
« no previous file with comments | « chrome/browser/win/chrome_select_file_dialog_factory.h ('k') | chrome/chrome_common.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/win/chrome_select_file_dialog_factory.h" 5 #include "chrome/browser/win/chrome_select_file_dialog_factory.h"
6 6
7 #include <Windows.h> 7 #include <Windows.h>
8 #include <commdlg.h> 8 #include <commdlg.h>
9 9
10 #include <vector>
11
12 #include "base/bind.h" 10 #include "base/bind.h"
13 #include "base/bind_helpers.h" 11 #include "base/bind_helpers.h"
14 #include "base/feature_list.h" 12 #include "base/callback.h"
15 #include "base/strings/string_util.h" 13 #include "base/location.h"
14 #include "base/logging.h"
15 #include "base/macros.h"
16 #include "base/metrics/field_trial.h"
17 #include "base/strings/string16.h"
16 #include "base/synchronization/waitable_event.h" 18 #include "base/synchronization/waitable_event.h"
17 #include "base/win/win_util.h" 19 #include "chrome/common/chrome_utility_messages.h"
18 #include "chrome/common/shell_handler_win.mojom.h"
19 #include "chrome/grit/generated_resources.h" 20 #include "chrome/grit/generated_resources.h"
20 #include "content/public/browser/utility_process_mojo_client.h" 21 #include "content/public/browser/utility_process_host.h"
22 #include "content/public/browser/utility_process_host_client.h"
23 #include "ipc/ipc_message_macros.h"
21 #include "ui/base/l10n/l10n_util.h" 24 #include "ui/base/l10n/l10n_util.h"
22 #include "ui/base/win/open_file_name_win.h" 25 #include "ui/base/win/open_file_name_win.h"
23 #include "ui/shell_dialogs/select_file_dialog_win.h" 26 #include "ui/shell_dialogs/select_file_dialog_win.h"
24 27
25 namespace { 28 namespace {
26 29
27 constexpr base::Feature kIsolateShellOperations{ 30 bool ShouldIsolateShellOperations() {
28 "IsolateShellOperations", base::FEATURE_DISABLED_BY_DEFAULT}; 31 return base::FieldTrialList::FindFullName("IsolateShellOperations") ==
29 32 "Enabled";
30 // Implements GetOpenFileName() and GetSaveFileName() for 33 }
31 // CreateWinSelectFileDialog by delegating to a utility process. 34
32 class OpenFileNameClient { 35 // Receives the GetOpenFileName result from the utility process.
36 class GetOpenFileNameClient : public content::UtilityProcessHostClient {
33 public: 37 public:
34 OpenFileNameClient(); 38 GetOpenFileNameClient();
35 39
36 // Invokes ::GetOpenFileName() and stores the result into |directory| and 40 // Blocks until the GetOpenFileName result is received (including failure to
37 // |filenames|. Returns false on failure. 41 // launch or a crash of the utility process).
38 bool BlockingGetOpenFileName(OPENFILENAME* ofn); 42 void WaitForCompletion();
39 43
40 // Invokes ::GetSaveFileName() and stores the result into |path| and 44 // Returns the selected directory.
41 // |one_based_filter_index|. Returns false on failure. 45 const base::FilePath& directory() const { return directory_; }
42 bool BlockingGetSaveFileName(OPENFILENAME* ofn); 46
47 // Returns the list of selected filenames. Each should be interpreted as a
48 // child of directory().
49 const std::vector<base::FilePath>& filenames() const { return filenames_; }
50
51 // UtilityProcessHostClient implementation
52 void OnProcessCrashed(int exit_code) override;
53 void OnProcessLaunchFailed(int error_code) override;
54 bool OnMessageReceived(const IPC::Message& message) override;
55
56 protected:
57 ~GetOpenFileNameClient() override;
43 58
44 private: 59 private:
45 void StartClient(); 60 void OnResult(const base::FilePath& directory,
46 61 const std::vector<base::FilePath>& filenames);
47 void InvokeGetOpenFileNameOnIOThread(OPENFILENAME* ofn); 62 void OnFailure();
48 void InvokeGetSaveFileNameOnIOThread(OPENFILENAME* ofn); 63
49
50 // Callbacks for Mojo invokation.
51 void OnDidGetOpenFileNames(const base::FilePath& directory,
52 mojo::Array<base::FilePath> filenames);
53 void OnDidGetSaveFileName(const base::FilePath& path,
54 uint32_t one_based_filter_index);
55
56 void OnConnectionError();
57
58 // Must only be accessed on the IO thread.
59 std::unique_ptr<content::UtilityProcessMojoClient<mojom::ShellHandler>>
60 client_;
61
62 // This is used to block until the result is received.
63 base::WaitableEvent result_received_event_;
64
65 // Result variables for GetOpenFileName.
66 base::FilePath directory_; 64 base::FilePath directory_;
67 std::vector<base::FilePath> filenames_; 65 std::vector<base::FilePath> filenames_;
68 66 base::WaitableEvent event_;
69 // Result variables for GetSaveFileName. 67
68 DISALLOW_COPY_AND_ASSIGN(GetOpenFileNameClient);
69 };
70
71 GetOpenFileNameClient::GetOpenFileNameClient()
72 : event_(base::WaitableEvent::ResetPolicy::MANUAL,
73 base::WaitableEvent::InitialState::NOT_SIGNALED) {}
74
75 void GetOpenFileNameClient::WaitForCompletion() {
76 event_.Wait();
77 }
78
79 void GetOpenFileNameClient::OnProcessCrashed(int exit_code) {
80 event_.Signal();
81 }
82
83 void GetOpenFileNameClient::OnProcessLaunchFailed(int error_code) {
84 event_.Signal();
85 }
86
87 bool GetOpenFileNameClient::OnMessageReceived(const IPC::Message& message) {
88 bool handled = true;
89 IPC_BEGIN_MESSAGE_MAP(GetOpenFileNameClient, message)
90 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetOpenFileName_Failed,
91 OnFailure)
92 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetOpenFileName_Result,
93 OnResult)
94 IPC_MESSAGE_UNHANDLED(handled = false)
95 IPC_END_MESSAGE_MAP()
96 return handled;
97 }
98
99 GetOpenFileNameClient::~GetOpenFileNameClient() {}
100
101 void GetOpenFileNameClient::OnResult(
102 const base::FilePath& directory,
103 const std::vector<base::FilePath>& filenames) {
104 directory_ = directory;
105 filenames_ = filenames;
106 event_.Signal();
107 }
108
109 void GetOpenFileNameClient::OnFailure() {
110 event_.Signal();
111 }
112
113 // Initiates IPC with a new utility process using |client|. Instructs the
114 // utility process to call GetOpenFileName with |ofn|. |current_task_runner|
115 // must be the currently executing task runner.
116 void DoInvokeGetOpenFileName(
117 OPENFILENAME* ofn,
118 scoped_refptr<GetOpenFileNameClient> client,
119 const scoped_refptr<base::SequencedTaskRunner>& current_task_runner) {
120 DCHECK(current_task_runner->RunsTasksOnCurrentThread());
121
122 base::WeakPtr<content::UtilityProcessHost> utility_process_host(
123 content::UtilityProcessHost::Create(client, current_task_runner)
124 ->AsWeakPtr());
125 utility_process_host->SetName(l10n_util::GetStringUTF16(
126 IDS_UTILITY_PROCESS_FILE_DIALOG_NAME));
127 utility_process_host->DisableSandbox();
128 utility_process_host->Send(new ChromeUtilityMsg_GetOpenFileName(
129 ofn->hwndOwner,
130 ofn->Flags & ~OFN_ENABLEHOOK, // We can't send a hook function over IPC.
131 ui::win::OpenFileName::GetFilters(ofn),
132 base::FilePath(ofn->lpstrInitialDir ? ofn->lpstrInitialDir
133 : base::string16()),
134 base::FilePath(ofn->lpstrFile)));
135 }
136
137 // Invokes GetOpenFileName in a utility process. Blocks until the result is
138 // received. Uses |blocking_task_runner| for IPC.
139 bool GetOpenFileNameInUtilityProcess(
140 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
141 OPENFILENAME* ofn) {
142 scoped_refptr<GetOpenFileNameClient> client(new GetOpenFileNameClient);
143 blocking_task_runner->PostTask(
144 FROM_HERE,
145 base::Bind(&DoInvokeGetOpenFileName,
146 base::Unretained(ofn), client, blocking_task_runner));
147 client->WaitForCompletion();
148
149 if (client->filenames().empty())
150 return false;
151
152 ui::win::OpenFileName::SetResult(
153 client->directory(), client->filenames(), ofn);
154 return true;
155 }
156
157 // Implements GetOpenFileName for CreateWinSelectFileDialog by delegating to a
158 // utility process.
159 bool GetOpenFileNameImpl(
160 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
161 OPENFILENAME* ofn) {
162 if (ShouldIsolateShellOperations())
163 return GetOpenFileNameInUtilityProcess(blocking_task_runner, ofn);
164
165 return ::GetOpenFileName(ofn) == TRUE;
166 }
167
168 class GetSaveFileNameClient : public content::UtilityProcessHostClient {
169 public:
170 GetSaveFileNameClient();
171
172 // Blocks until the GetSaveFileName result is received (including failure to
173 // launch or a crash of the utility process).
174 void WaitForCompletion();
175
176 // Returns the selected path.
177 const base::FilePath& path() const { return path_; }
178
179 // Returns the index of the user-selected filter.
180 int one_based_filter_index() const { return one_based_filter_index_; }
181
182 // UtilityProcessHostClient implementation
183 void OnProcessCrashed(int exit_code) override;
184 void OnProcessLaunchFailed(int error_code) override;
185 bool OnMessageReceived(const IPC::Message& message) override;
186
187 protected:
188 ~GetSaveFileNameClient() override;
189
190 private:
191 void OnResult(const base::FilePath& path, int one_based_filter_index);
192 void OnFailure();
193
70 base::FilePath path_; 194 base::FilePath path_;
71 DWORD one_based_filter_index_ = 0; 195 int one_based_filter_index_;
72 196 base::WaitableEvent event_;
73 DISALLOW_COPY_AND_ASSIGN(OpenFileNameClient); 197
198 DISALLOW_COPY_AND_ASSIGN(GetSaveFileNameClient);
74 }; 199 };
75 200
76 OpenFileNameClient::OpenFileNameClient() 201 GetSaveFileNameClient::GetSaveFileNameClient()
77 : result_received_event_(base::WaitableEvent::ResetPolicy::MANUAL, 202 : one_based_filter_index_(0),
78 base::WaitableEvent::InitialState::NOT_SIGNALED) {} 203 event_(base::WaitableEvent::ResetPolicy::MANUAL,
79 204 base::WaitableEvent::InitialState::NOT_SIGNALED) {}
80 bool OpenFileNameClient::BlockingGetOpenFileName(OPENFILENAME* ofn) { 205
81 content::BrowserThread::PostTask( 206 void GetSaveFileNameClient::WaitForCompletion() {
82 content::BrowserThread::IO, FROM_HERE, 207 event_.Wait();
83 base::Bind(&OpenFileNameClient::InvokeGetOpenFileNameOnIOThread, 208 }
84 base::Unretained(this), ofn)); 209
85 210 void GetSaveFileNameClient::OnProcessCrashed(int exit_code) {
86 result_received_event_.Wait(); 211 event_.Signal();
87 212 }
88 if (filenames_.empty()) 213
89 return false; 214 void GetSaveFileNameClient::OnProcessLaunchFailed(int error_code) {
90 215 event_.Signal();
91 ui::win::OpenFileName::SetResult(directory_, filenames_, ofn); 216 }
92 return true; 217
93 } 218 bool GetSaveFileNameClient::OnMessageReceived(const IPC::Message& message) {
94 219 bool handled = true;
95 bool OpenFileNameClient::BlockingGetSaveFileName(OPENFILENAME* ofn) { 220 IPC_BEGIN_MESSAGE_MAP(GetSaveFileNameClient, message)
96 content::BrowserThread::PostTask( 221 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetSaveFileName_Failed,
97 content::BrowserThread::IO, FROM_HERE, 222 OnFailure)
98 base::Bind(&OpenFileNameClient::InvokeGetSaveFileNameOnIOThread, 223 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetSaveFileName_Result,
99 base::Unretained(this), ofn)); 224 OnResult)
100 225 IPC_MESSAGE_UNHANDLED(handled = false)
101 result_received_event_.Wait(); 226 IPC_END_MESSAGE_MAP()
102 227 return handled;
103 if (path_.empty()) 228 }
104 return false; 229
105 230 GetSaveFileNameClient::~GetSaveFileNameClient() {}
106 base::wcslcpy(ofn->lpstrFile, path_.value().c_str(), ofn->nMaxFile); 231
107 ofn->nFilterIndex = one_based_filter_index_; 232 void GetSaveFileNameClient::OnResult(const base::FilePath& path,
108 return true; 233 int one_based_filter_index) {
109 }
110
111 void OpenFileNameClient::StartClient() {
112 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
113 client_.reset(new content::UtilityProcessMojoClient<mojom::ShellHandler>(
114 l10n_util::GetStringUTF16(IDS_UTILITY_PROCESS_FILE_DIALOG_NAME)));
115
116 client_->set_disable_sandbox();
117 client_->set_error_callback(base::Bind(&OpenFileNameClient::OnConnectionError,
118 base::Unretained(this)));
119
120 client_->Start();
121 }
122
123 void OpenFileNameClient::InvokeGetOpenFileNameOnIOThread(OPENFILENAME* ofn) {
124 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
125 StartClient();
126 client_->service()->DoGetOpenFileName(
127 base::win::HandleToUint32(ofn->hwndOwner),
128 static_cast<uint32_t>(ofn->Flags), ui::win::OpenFileName::GetFilters(ofn),
129 ofn->lpstrInitialDir ? base::FilePath(ofn->lpstrInitialDir)
130 : base::FilePath(),
131 base::FilePath(ofn->lpstrFile),
132 base::Bind(&OpenFileNameClient::OnDidGetOpenFileNames,
133 base::Unretained(this)));
134 }
135
136 void OpenFileNameClient::InvokeGetSaveFileNameOnIOThread(OPENFILENAME* ofn) {
137 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
138 StartClient();
139 client_->service()->DoGetSaveFileName(
140 base::win::HandleToUint32(ofn->hwndOwner),
141 static_cast<uint32_t>(ofn->Flags), ui::win::OpenFileName::GetFilters(ofn),
142 ofn->nFilterIndex,
143 ofn->lpstrInitialDir ? base::FilePath(ofn->lpstrInitialDir)
144 : base::FilePath(),
145 base::FilePath(ofn->lpstrFile),
146 ofn->lpstrDefExt ? base::FilePath(ofn->lpstrDefExt) : base::FilePath(),
147 base::Bind(&OpenFileNameClient::OnDidGetSaveFileName,
148 base::Unretained(this)));
149 }
150
151 void OpenFileNameClient::OnDidGetOpenFileNames(
152 const base::FilePath& directory,
153 mojo::Array<base::FilePath> filenames) {
154 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
155 client_.reset();
156 directory_ = directory;
157 filenames_ = filenames.storage();
158
159 result_received_event_.Signal();
160 }
161
162 void OpenFileNameClient::OnDidGetSaveFileName(const base::FilePath& path,
163 uint32_t one_based_filter_index) {
164 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
165 client_.reset();
166 path_ = path; 234 path_ = path;
167 one_based_filter_index_ = one_based_filter_index; 235 one_based_filter_index_ = one_based_filter_index;
168 236 event_.Signal();
169 result_received_event_.Signal(); 237 }
170 } 238
171 239 void GetSaveFileNameClient::OnFailure() {
172 void OpenFileNameClient::OnConnectionError() { 240 event_.Signal();
173 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); 241 }
174 client_.reset(); 242
175 result_received_event_.Signal(); 243 // Initiates IPC with a new utility process using |client|. Instructs the
176 } 244 // utility process to call GetSaveFileName with |ofn|. |current_task_runner|
177 245 // must be the currently executing task runner.
178 bool GetOpenFileNameImpl(OPENFILENAME* ofn) { 246 void DoInvokeGetSaveFileName(
179 if (base::FeatureList::IsEnabled(kIsolateShellOperations)) 247 OPENFILENAME* ofn,
180 return OpenFileNameClient().BlockingGetOpenFileName(ofn); 248 scoped_refptr<GetSaveFileNameClient> client,
181 249 const scoped_refptr<base::SequencedTaskRunner>& current_task_runner) {
182 return ::GetOpenFileName(ofn) == TRUE; 250 DCHECK(current_task_runner->RunsTasksOnCurrentThread());
183 } 251
184 252 base::WeakPtr<content::UtilityProcessHost> utility_process_host(
185 bool GetSaveFileNameImpl(OPENFILENAME* ofn) { 253 content::UtilityProcessHost::Create(client, current_task_runner)
186 if (base::FeatureList::IsEnabled(kIsolateShellOperations)) 254 ->AsWeakPtr());
187 return OpenFileNameClient().BlockingGetSaveFileName(ofn); 255 utility_process_host->SetName(l10n_util::GetStringUTF16(
256 IDS_UTILITY_PROCESS_FILE_DIALOG_NAME));
257 utility_process_host->DisableSandbox();
258 ChromeUtilityMsg_GetSaveFileName_Params params;
259 params.owner = ofn->hwndOwner;
260 // We can't pass the hook function over IPC.
261 params.flags = ofn->Flags & ~OFN_ENABLEHOOK;
262 params.filters = ui::win::OpenFileName::GetFilters(ofn);
263 params.one_based_filter_index = ofn->nFilterIndex;
264 params.suggested_filename = base::FilePath(ofn->lpstrFile);
265 params.initial_directory = base::FilePath(
266 ofn->lpstrInitialDir ? ofn->lpstrInitialDir : base::string16());
267 params.default_extension =
268 ofn->lpstrDefExt ? base::string16(ofn->lpstrDefExt) : base::string16();
269
270 utility_process_host->Send(new ChromeUtilityMsg_GetSaveFileName(params));
271 }
272
273 // Invokes GetSaveFileName in a utility process. Blocks until the result is
274 // received. Uses |blocking_task_runner| for IPC.
275 bool GetSaveFileNameInUtilityProcess(
276 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
277 OPENFILENAME* ofn) {
278 scoped_refptr<GetSaveFileNameClient> client(new GetSaveFileNameClient);
279 blocking_task_runner->PostTask(
280 FROM_HERE,
281 base::Bind(&DoInvokeGetSaveFileName,
282 base::Unretained(ofn), client, blocking_task_runner));
283 client->WaitForCompletion();
284
285 if (client->path().empty())
286 return false;
287
288 base::wcslcpy(ofn->lpstrFile, client->path().value().c_str(), ofn->nMaxFile);
289 ofn->nFilterIndex = client->one_based_filter_index();
290
291 return true;
292 }
293
294 // Implements GetSaveFileName for CreateWinSelectFileDialog by delegating to a
295 // utility process.
296 bool GetSaveFileNameImpl(
297 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
298 OPENFILENAME* ofn) {
299 if (ShouldIsolateShellOperations())
300 return GetSaveFileNameInUtilityProcess(blocking_task_runner, ofn);
188 301
189 return ::GetSaveFileName(ofn) == TRUE; 302 return ::GetSaveFileName(ofn) == TRUE;
190 } 303 }
191 304
192 } // namespace 305 } // namespace
193 306
194 ChromeSelectFileDialogFactory::ChromeSelectFileDialogFactory() = default; 307 ChromeSelectFileDialogFactory::ChromeSelectFileDialogFactory(
195 308 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner)
196 ChromeSelectFileDialogFactory::~ChromeSelectFileDialogFactory() = default; 309 : blocking_task_runner_(blocking_task_runner) {
310 }
311
312 ChromeSelectFileDialogFactory::~ChromeSelectFileDialogFactory() {}
197 313
198 ui::SelectFileDialog* ChromeSelectFileDialogFactory::Create( 314 ui::SelectFileDialog* ChromeSelectFileDialogFactory::Create(
199 ui::SelectFileDialog::Listener* listener, 315 ui::SelectFileDialog::Listener* listener,
200 ui::SelectFilePolicy* policy) { 316 ui::SelectFilePolicy* policy) {
201 return ui::CreateWinSelectFileDialog(listener, policy, 317 return ui::CreateWinSelectFileDialog(
202 base::Bind(GetOpenFileNameImpl), 318 listener,
203 base::Bind(GetSaveFileNameImpl)); 319 policy,
204 } 320 base::Bind(GetOpenFileNameImpl, blocking_task_runner_),
321 base::Bind(GetSaveFileNameImpl, blocking_task_runner_));
322 }
OLDNEW
« no previous file with comments | « chrome/browser/win/chrome_select_file_dialog_factory.h ('k') | chrome/chrome_common.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698