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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | chrome/common/chrome_utility_messages.h » ('j') | ui/base/win/open_file_name_win.h » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/chrome_select_file_dialog_factory_win.cc
diff --git a/chrome/browser/chrome_select_file_dialog_factory_win.cc b/chrome/browser/chrome_select_file_dialog_factory_win.cc
index 3522358795274aba4e5e54c501e09ecd1e3c7c50..c24a491a6a3f6c201001e724b55614c1fc0c437b 100644
--- a/chrome/browser/chrome_select_file_dialog_factory_win.cc
+++ b/chrome/browser/chrome_select_file_dialog_factory_win.cc
@@ -25,6 +25,29 @@
namespace {
+bool CallMetroOPENFILENAMEMethod(const char* method_name, OPENFILENAME* ofn) {
+ typedef BOOL (*MetroOPENFILENAMEMethod)(OPENFILENAME*);
+ MetroOPENFILENAMEMethod metro_method = NULL;
+ HMODULE metro_module = base::win::GetMetroModule();
+
+ if (metro_module != NULL) {
+ metro_method = reinterpret_cast<MetroOPENFILENAMEMethod>(
+ ::GetProcAddress(metro_module, method_name));
+ }
+
+ if (metro_method != NULL)
+ return metro_method(ofn) == TRUE;
+
+ NOTREACHED();
+
+ return false;
+}
+
+bool ShouldIsolateShellOperations() {
+ return base::FieldTrialList::FindFullName("IsolateShellOperations") ==
+ "Enabled";
+}
+
// Receives the GetOpenFileName result from the utility process.
class GetOpenFileNameClient : public content::UtilityProcessHostClient {
public:
@@ -117,7 +140,7 @@ void DoInvokeGetOpenFileName(
utility_process_host->DisableSandbox();
utility_process_host->Send(new ChromeUtilityMsg_GetOpenFileName(
ofn->hwndOwner,
- ofn->Flags,
+ ofn->Flags & ~OFN_ENABLEHOOK, // We can't send a hook function over IPC.
ui::win::OpenFileName::GetFilters(ofn),
base::FilePath(ofn->lpstrInitialDir ? ofn->lpstrInitialDir
: base::string16()),
@@ -149,28 +172,152 @@ bool GetOpenFileNameInUtilityProcess(
bool GetOpenFileNameImpl(
const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
OPENFILENAME* ofn) {
- HMODULE metro_module = base::win::GetMetroModule();
- if (metro_module != NULL) {
- typedef BOOL (*MetroGetOpenFileName)(OPENFILENAME*);
- MetroGetOpenFileName metro_get_open_file_name =
- reinterpret_cast<MetroGetOpenFileName>(
- ::GetProcAddress(metro_module, "MetroGetOpenFileName"));
- if (metro_get_open_file_name == NULL) {
- NOTREACHED();
- return false;
- }
-
- return metro_get_open_file_name(ofn) == TRUE;
- }
+ if (base::win::IsMetroProcess())
+ return CallMetroOPENFILENAMEMethod("MetroGetOpenFileName", ofn);
- if (base::FieldTrialList::FindFullName("IsolateShellOperations") ==
- "Enabled") {
+ if (ShouldIsolateShellOperations())
return GetOpenFileNameInUtilityProcess(blocking_task_runner, ofn);
- }
return ::GetOpenFileName(ofn) == TRUE;
}
+class GetSaveFileNameClient : public content::UtilityProcessHostClient {
+ public:
+ GetSaveFileNameClient();
+
+ // Blocks until the GetSaveFileName result is received (including failure to
+ // launch or a crash of the utility process).
+ void WaitForCompletion();
+
+ // Returns the selected path.
+ const base::FilePath& path() const { return path_; }
+
+ // Returns the index of the user-selected filter.
+ int one_based_filter_index() const { return one_based_filter_index_; }
+
+ // UtilityProcessHostClient implementation
+ virtual void OnProcessCrashed(int exit_code) OVERRIDE;
+ virtual void OnProcessLaunchFailed() OVERRIDE;
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+
+ protected:
+ virtual ~GetSaveFileNameClient();
+
+ private:
+ void OnResult(const base::FilePath& path, int one_based_filter_index);
+ void OnFailure();
+
+ base::FilePath path_;
+ int one_based_filter_index_;
+ base::WaitableEvent event_;
+
+ DISALLOW_COPY_AND_ASSIGN(GetSaveFileNameClient);
+};
+
+GetSaveFileNameClient::GetSaveFileNameClient()
+ : event_(true, false), one_based_filter_index_(0) {
+}
+
+void GetSaveFileNameClient::WaitForCompletion() {
+ event_.Wait();
+}
+
+void GetSaveFileNameClient::OnProcessCrashed(int exit_code) {
+ event_.Signal();
+}
+
+void GetSaveFileNameClient::OnProcessLaunchFailed() {
+ event_.Signal();
+}
+
+bool GetSaveFileNameClient::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(GetSaveFileNameClient, message)
+ IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetSaveFileName_Failed,
+ OnFailure)
+ IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetSaveFileName_Result,
+ OnResult)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+GetSaveFileNameClient::~GetSaveFileNameClient() {}
+
+void GetSaveFileNameClient::OnResult(const base::FilePath& path,
+ int one_based_filter_index) {
+ path_ = path;
+ one_based_filter_index_ = one_based_filter_index;
+ event_.Signal();
+}
+
+void GetSaveFileNameClient::OnFailure() {
+ event_.Signal();
+}
+
+// Initiates IPC with a new utility process using |client|. Instructs the
+// utility process to call GetSaveFileName with |ofn|. |current_task_runner|
+// must be the currently executing task runner.
+void DoInvokeGetSaveFileName(
+ OPENFILENAME* ofn,
+ scoped_refptr<GetSaveFileNameClient> client,
+ const scoped_refptr<base::SequencedTaskRunner>& current_task_runner) {
+ DCHECK(current_task_runner->RunsTasksOnCurrentThread());
+
+ base::WeakPtr<content::UtilityProcessHost> utility_process_host(
+ content::UtilityProcessHost::Create(client, current_task_runner)
+ ->AsWeakPtr());
+ utility_process_host->DisableSandbox();
+ ChromeUtilityMsg_GetSaveFileName_Params params;
+ params.owner = ofn->hwndOwner;
+ // We can't pass the hook function over IPC.
+ params.flags = ofn->Flags & ~OFN_ENABLEHOOK;
+ params.filters = ui::win::OpenFileName::GetFilters(ofn);
+ params.one_based_filter_index = ofn->nFilterIndex;
+ params.suggested_filename = base::FilePath(ofn->lpstrFile);
+ params.initial_directory = base::FilePath(
+ ofn->lpstrInitialDir ? ofn->lpstrInitialDir : base::string16());
+ params.default_extension =
+ ofn->lpstrDefExt ? base::string16(ofn->lpstrDefExt) : base::string16();
+
+ utility_process_host->Send(new ChromeUtilityMsg_GetSaveFileName(params));
+}
+
+// Invokes GetSaveFileName in a utility process. Blocks until the result is
+// received. Uses |blocking_task_runner| for IPC.
+bool GetSaveFileNameInUtilityProcess(
+ const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
+ OPENFILENAME* ofn) {
+ scoped_refptr<GetSaveFileNameClient> client(new GetSaveFileNameClient);
+ blocking_task_runner->PostTask(
+ FROM_HERE,
+ base::Bind(&DoInvokeGetSaveFileName,
+ base::Unretained(ofn), client, blocking_task_runner));
+ client->WaitForCompletion();
+
+ if (client->path().empty())
+ return false;
+
+ base::wcslcpy(ofn->lpstrFile, client->path().value().c_str(), ofn->nMaxFile);
+ ofn->nFilterIndex = client->one_based_filter_index();
+
+ return true;
+}
+
+// Implements GetSaveFileName for CreateWinSelectFileDialog by delegating either
+// to Metro or a utility process.
+bool GetSaveFileNameImpl(
+ const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
+ OPENFILENAME* ofn) {
+ if (base::win::IsMetroProcess())
+ return CallMetroOPENFILENAMEMethod("MetroGetSaveFileName", ofn);
+
+ if (ShouldIsolateShellOperations())
+ return GetSaveFileNameInUtilityProcess(blocking_task_runner, ofn);
+
+ return ::GetSaveFileName(ofn) == TRUE;
+}
+
} // namespace
ChromeSelectFileDialogFactory::ChromeSelectFileDialogFactory(
@@ -186,5 +333,6 @@ ui::SelectFileDialog* ChromeSelectFileDialogFactory::Create(
return ui::CreateWinSelectFileDialog(
listener,
policy,
- base::Bind(GetOpenFileNameImpl, blocking_task_runner_));
+ base::Bind(GetOpenFileNameImpl, blocking_task_runner_),
+ base::Bind(GetSaveFileNameImpl, blocking_task_runner_));
}
« 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