Commit b7faec8d authored by pmonette's avatar pmonette Committed by Commit bot

Isolate shell operations to the utility process.

Shell operations can cause 3rd-party shell extensions to be
loaded into the caller's process. The utility process protects the browser process from potential instability.

Also convert the IPC mechanism to Mojo.

BUG=73098

Review-Url: https://codereview.chromium.org/2122303002
Cr-Commit-Position: refs/heads/master@{#405270}
parent 62a15512
...@@ -1455,8 +1455,7 @@ int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() { ...@@ -1455,8 +1455,7 @@ int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() {
parsed_command_line_); parsed_command_line_);
} }
ui::SelectFileDialog::SetFactory(new ChromeSelectFileDialogFactory( ui::SelectFileDialog::SetFactory(new ChromeSelectFileDialogFactory());
BrowserThread::GetTaskRunnerForThread(BrowserThread::IO)));
#endif // defined(OS_WIN) #endif // defined(OS_WIN)
if (parsed_command_line().HasSwitch(switches::kMakeDefaultBrowser)) { if (parsed_command_line().HasSwitch(switches::kMakeDefaultBrowser)) {
......
...@@ -7,316 +7,198 @@ ...@@ -7,316 +7,198 @@
#include <Windows.h> #include <Windows.h>
#include <commdlg.h> #include <commdlg.h>
#include <vector>
#include "base/bind.h" #include "base/bind.h"
#include "base/bind_helpers.h" #include "base/bind_helpers.h"
#include "base/callback.h" #include "base/feature_list.h"
#include "base/location.h" #include "base/strings/string_util.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/metrics/field_trial.h"
#include "base/strings/string16.h"
#include "base/synchronization/waitable_event.h" #include "base/synchronization/waitable_event.h"
#include "chrome/common/chrome_utility_messages.h" #include "base/win/win_util.h"
#include "chrome/common/shell_handler_win.mojom.h"
#include "chrome/grit/generated_resources.h" #include "chrome/grit/generated_resources.h"
#include "content/public/browser/utility_process_host.h" #include "content/public/browser/utility_process_mojo_client.h"
#include "content/public/browser/utility_process_host_client.h"
#include "ipc/ipc_message_macros.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
#include "ui/base/win/open_file_name_win.h" #include "ui/base/win/open_file_name_win.h"
#include "ui/shell_dialogs/select_file_dialog_win.h" #include "ui/shell_dialogs/select_file_dialog_win.h"
namespace { namespace {
bool ShouldIsolateShellOperations() { constexpr base::Feature kIsolateShellOperations{
return base::FieldTrialList::FindFullName("IsolateShellOperations") == "IsolateShellOperations", base::FEATURE_DISABLED_BY_DEFAULT};
"Enabled";
}
// Receives the GetOpenFileName result from the utility process. // Implements GetOpenFileName() and GetSaveFileName() for
class GetOpenFileNameClient : public content::UtilityProcessHostClient { // CreateWinSelectFileDialog by delegating to a utility process.
class OpenFileNameClient {
public: public:
GetOpenFileNameClient(); OpenFileNameClient();
// Blocks until the GetOpenFileName result is received (including failure to
// launch or a crash of the utility process).
void WaitForCompletion();
// Returns the selected directory. // Invokes ::GetOpenFileName() and stores the result into |directory| and
const base::FilePath& directory() const { return directory_; } // |filenames|. Returns false on failure.
bool BlockingGetOpenFileName(OPENFILENAME* ofn);
// Returns the list of selected filenames. Each should be interpreted as a // Invokes ::GetSaveFileName() and stores the result into |path| and
// child of directory(). // |one_based_filter_index|. Returns false on failure.
const std::vector<base::FilePath>& filenames() const { return filenames_; } bool BlockingGetSaveFileName(OPENFILENAME* ofn);
// UtilityProcessHostClient implementation
void OnProcessCrashed(int exit_code) override;
void OnProcessLaunchFailed(int error_code) override;
bool OnMessageReceived(const IPC::Message& message) override;
protected:
~GetOpenFileNameClient() override;
private: private:
void OnResult(const base::FilePath& directory, void StartClient();
const std::vector<base::FilePath>& filenames);
void OnFailure();
base::FilePath directory_; void InvokeGetOpenFileNameOnIOThread(OPENFILENAME* ofn);
std::vector<base::FilePath> filenames_; void InvokeGetSaveFileNameOnIOThread(OPENFILENAME* ofn);
base::WaitableEvent event_;
DISALLOW_COPY_AND_ASSIGN(GetOpenFileNameClient); // Callbacks for Mojo invokation.
}; void OnDidGetOpenFileNames(const base::FilePath& directory,
mojo::Array<base::FilePath> filenames);
void OnDidGetSaveFileName(const base::FilePath& path,
uint32_t one_based_filter_index);
GetOpenFileNameClient::GetOpenFileNameClient() void OnConnectionError();
: event_(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED) {}
void GetOpenFileNameClient::WaitForCompletion() { // Must only be accessed on the IO thread.
event_.Wait(); std::unique_ptr<content::UtilityProcessMojoClient<mojom::ShellHandler>>
} client_;
void GetOpenFileNameClient::OnProcessCrashed(int exit_code) { // This is used to block until the result is received.
event_.Signal(); base::WaitableEvent result_received_event_;
}
void GetOpenFileNameClient::OnProcessLaunchFailed(int error_code) { // Result variables for GetOpenFileName.
event_.Signal(); base::FilePath directory_;
} std::vector<base::FilePath> filenames_;
bool GetOpenFileNameClient::OnMessageReceived(const IPC::Message& message) { // Result variables for GetSaveFileName.
bool handled = true; base::FilePath path_;
IPC_BEGIN_MESSAGE_MAP(GetOpenFileNameClient, message) DWORD one_based_filter_index_ = 0;
IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetOpenFileName_Failed,
OnFailure)
IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetOpenFileName_Result,
OnResult)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
GetOpenFileNameClient::~GetOpenFileNameClient() {} DISALLOW_COPY_AND_ASSIGN(OpenFileNameClient);
};
void GetOpenFileNameClient::OnResult( OpenFileNameClient::OpenFileNameClient()
const base::FilePath& directory, : result_received_event_(base::WaitableEvent::ResetPolicy::MANUAL,
const std::vector<base::FilePath>& filenames) { base::WaitableEvent::InitialState::NOT_SIGNALED) {}
directory_ = directory;
filenames_ = filenames;
event_.Signal();
}
void GetOpenFileNameClient::OnFailure() { bool OpenFileNameClient::BlockingGetOpenFileName(OPENFILENAME* ofn) {
event_.Signal(); content::BrowserThread::PostTask(
} content::BrowserThread::IO, FROM_HERE,
base::Bind(&OpenFileNameClient::InvokeGetOpenFileNameOnIOThread,
base::Unretained(this), ofn));
// Initiates IPC with a new utility process using |client|. Instructs the result_received_event_.Wait();
// utility process to call GetOpenFileName with |ofn|. |current_task_runner|
// must be the currently executing task runner.
void DoInvokeGetOpenFileName(
OPENFILENAME* ofn,
scoped_refptr<GetOpenFileNameClient> 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->SetName(l10n_util::GetStringUTF16(
IDS_UTILITY_PROCESS_FILE_DIALOG_NAME));
utility_process_host->DisableSandbox();
utility_process_host->Send(new ChromeUtilityMsg_GetOpenFileName(
ofn->hwndOwner,
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()),
base::FilePath(ofn->lpstrFile)));
}
// Invokes GetOpenFileName in a utility process. Blocks until the result is if (filenames_.empty())
// received. Uses |blocking_task_runner| for IPC.
bool GetOpenFileNameInUtilityProcess(
const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
OPENFILENAME* ofn) {
scoped_refptr<GetOpenFileNameClient> client(new GetOpenFileNameClient);
blocking_task_runner->PostTask(
FROM_HERE,
base::Bind(&DoInvokeGetOpenFileName,
base::Unretained(ofn), client, blocking_task_runner));
client->WaitForCompletion();
if (client->filenames().empty())
return false; return false;
ui::win::OpenFileName::SetResult( ui::win::OpenFileName::SetResult(directory_, filenames_, ofn);
client->directory(), client->filenames(), ofn);
return true; return true;
} }
// Implements GetOpenFileName for CreateWinSelectFileDialog by delegating to a bool OpenFileNameClient::BlockingGetSaveFileName(OPENFILENAME* ofn) {
// utility process. content::BrowserThread::PostTask(
bool GetOpenFileNameImpl( content::BrowserThread::IO, FROM_HERE,
const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner, base::Bind(&OpenFileNameClient::InvokeGetSaveFileNameOnIOThread,
OPENFILENAME* ofn) { base::Unretained(this), ofn));
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 result_received_event_.Wait();
void OnProcessCrashed(int exit_code) override;
void OnProcessLaunchFailed(int error_code) override;
bool OnMessageReceived(const IPC::Message& message) override;
protected: if (path_.empty())
~GetSaveFileNameClient() override; return false;
private: base::wcslcpy(ofn->lpstrFile, path_.value().c_str(), ofn->nMaxFile);
void OnResult(const base::FilePath& path, int one_based_filter_index); ofn->nFilterIndex = one_based_filter_index_;
void OnFailure(); return true;
}
base::FilePath path_; void OpenFileNameClient::StartClient() {
int one_based_filter_index_; DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
base::WaitableEvent event_; client_.reset(new content::UtilityProcessMojoClient<mojom::ShellHandler>(
l10n_util::GetStringUTF16(IDS_UTILITY_PROCESS_FILE_DIALOG_NAME)));
DISALLOW_COPY_AND_ASSIGN(GetSaveFileNameClient); client_->set_disable_sandbox();
}; client_->set_error_callback(base::Bind(&OpenFileNameClient::OnConnectionError,
base::Unretained(this)));
GetSaveFileNameClient::GetSaveFileNameClient() client_->Start();
: one_based_filter_index_(0),
event_(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED) {}
void GetSaveFileNameClient::WaitForCompletion() {
event_.Wait();
} }
void GetSaveFileNameClient::OnProcessCrashed(int exit_code) { void OpenFileNameClient::InvokeGetOpenFileNameOnIOThread(OPENFILENAME* ofn) {
event_.Signal(); DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
StartClient();
client_->service()->DoGetOpenFileName(
base::win::HandleToUint32(ofn->hwndOwner),
static_cast<uint32_t>(ofn->Flags), ui::win::OpenFileName::GetFilters(ofn),
ofn->lpstrInitialDir ? base::FilePath(ofn->lpstrInitialDir)
: base::FilePath(),
base::FilePath(ofn->lpstrFile),
base::Bind(&OpenFileNameClient::OnDidGetOpenFileNames,
base::Unretained(this)));
} }
void GetSaveFileNameClient::OnProcessLaunchFailed(int error_code) { void OpenFileNameClient::InvokeGetSaveFileNameOnIOThread(OPENFILENAME* ofn) {
event_.Signal(); DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
StartClient();
client_->service()->DoGetSaveFileName(
base::win::HandleToUint32(ofn->hwndOwner),
static_cast<uint32_t>(ofn->Flags), ui::win::OpenFileName::GetFilters(ofn),
ofn->nFilterIndex,
ofn->lpstrInitialDir ? base::FilePath(ofn->lpstrInitialDir)
: base::FilePath(),
base::FilePath(ofn->lpstrFile),
ofn->lpstrDefExt ? base::FilePath(ofn->lpstrDefExt) : base::FilePath(),
base::Bind(&OpenFileNameClient::OnDidGetSaveFileName,
base::Unretained(this)));
} }
bool GetSaveFileNameClient::OnMessageReceived(const IPC::Message& message) { void OpenFileNameClient::OnDidGetOpenFileNames(
bool handled = true; const base::FilePath& directory,
IPC_BEGIN_MESSAGE_MAP(GetSaveFileNameClient, message) mojo::Array<base::FilePath> filenames) {
IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetSaveFileName_Failed, DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
OnFailure) client_.reset();
IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetSaveFileName_Result, directory_ = directory;
OnResult) filenames_ = filenames.storage();
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
GetSaveFileNameClient::~GetSaveFileNameClient() {} result_received_event_.Signal();
}
void GetSaveFileNameClient::OnResult(const base::FilePath& path, void OpenFileNameClient::OnDidGetSaveFileName(const base::FilePath& path,
int one_based_filter_index) { uint32_t one_based_filter_index) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
client_.reset();
path_ = path; path_ = path;
one_based_filter_index_ = one_based_filter_index; one_based_filter_index_ = one_based_filter_index;
event_.Signal();
}
void GetSaveFileNameClient::OnFailure() { result_received_event_.Signal();
event_.Signal();
} }
// Initiates IPC with a new utility process using |client|. Instructs the void OpenFileNameClient::OnConnectionError() {
// utility process to call GetSaveFileName with |ofn|. |current_task_runner| DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
// must be the currently executing task runner. client_.reset();
void DoInvokeGetSaveFileName( result_received_event_.Signal();
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->SetName(l10n_util::GetStringUTF16(
IDS_UTILITY_PROCESS_FILE_DIALOG_NAME));
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 bool GetOpenFileNameImpl(OPENFILENAME* ofn) {
// received. Uses |blocking_task_runner| for IPC. if (base::FeatureList::IsEnabled(kIsolateShellOperations))
bool GetSaveFileNameInUtilityProcess( return OpenFileNameClient().BlockingGetOpenFileName(ofn);
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; return ::GetOpenFileName(ofn) == TRUE;
} }
// Implements GetSaveFileName for CreateWinSelectFileDialog by delegating to a bool GetSaveFileNameImpl(OPENFILENAME* ofn) {
// utility process. if (base::FeatureList::IsEnabled(kIsolateShellOperations))
bool GetSaveFileNameImpl( return OpenFileNameClient().BlockingGetSaveFileName(ofn);
const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
OPENFILENAME* ofn) {
if (ShouldIsolateShellOperations())
return GetSaveFileNameInUtilityProcess(blocking_task_runner, ofn);
return ::GetSaveFileName(ofn) == TRUE; return ::GetSaveFileName(ofn) == TRUE;
} }
} // namespace } // namespace
ChromeSelectFileDialogFactory::ChromeSelectFileDialogFactory( ChromeSelectFileDialogFactory::ChromeSelectFileDialogFactory() = default;
const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner)
: blocking_task_runner_(blocking_task_runner) {
}
ChromeSelectFileDialogFactory::~ChromeSelectFileDialogFactory() {} ChromeSelectFileDialogFactory::~ChromeSelectFileDialogFactory() = default;
ui::SelectFileDialog* ChromeSelectFileDialogFactory::Create( ui::SelectFileDialog* ChromeSelectFileDialogFactory::Create(
ui::SelectFileDialog::Listener* listener, ui::SelectFileDialog::Listener* listener,
ui::SelectFilePolicy* policy) { ui::SelectFilePolicy* policy) {
return ui::CreateWinSelectFileDialog( return ui::CreateWinSelectFileDialog(listener, policy,
listener, base::Bind(GetOpenFileNameImpl),
policy, base::Bind(GetSaveFileNameImpl));
base::Bind(GetOpenFileNameImpl, blocking_task_runner_),
base::Bind(GetSaveFileNameImpl, blocking_task_runner_));
} }
...@@ -5,24 +5,16 @@ ...@@ -5,24 +5,16 @@
#ifndef CHROME_BROWSER_WIN_CHROME_SELECT_FILE_DIALOG_FACTORY_H_ #ifndef CHROME_BROWSER_WIN_CHROME_SELECT_FILE_DIALOG_FACTORY_H_
#define CHROME_BROWSER_WIN_CHROME_SELECT_FILE_DIALOG_FACTORY_H_ #define CHROME_BROWSER_WIN_CHROME_SELECT_FILE_DIALOG_FACTORY_H_
#include "base/compiler_specific.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "ui/shell_dialogs/select_file_dialog_factory.h" #include "ui/shell_dialogs/select_file_dialog_factory.h"
namespace base {
class SequencedTaskRunner;
} // namespace base
// Implements a Select File dialog that delegates to a Metro file picker on // Implements a Select File dialog that delegates to a Metro file picker on
// Metro and to a utility process otherwise. The utility process is used in // Metro and to a utility process otherwise. The utility process is used in
// order to isolate the Chrome browser process from potential instability // order to isolate the Chrome browser process from potential instability
// caused by Shell extension modules loaded by GetOpenFileName. // caused by Shell extension modules loaded by GetOpenFileName.
class ChromeSelectFileDialogFactory : public ui::SelectFileDialogFactory { class ChromeSelectFileDialogFactory : public ui::SelectFileDialogFactory {
public: public:
// Uses |blocking_task_runner| to perform IPC with the utility process. ChromeSelectFileDialogFactory();
explicit ChromeSelectFileDialogFactory(
const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner);
~ChromeSelectFileDialogFactory() override; ~ChromeSelectFileDialogFactory() override;
// ui::SelectFileDialogFactory implementation // ui::SelectFileDialogFactory implementation
...@@ -30,8 +22,6 @@ class ChromeSelectFileDialogFactory : public ui::SelectFileDialogFactory { ...@@ -30,8 +22,6 @@ class ChromeSelectFileDialogFactory : public ui::SelectFileDialogFactory {
ui::SelectFilePolicy* policy) override; ui::SelectFilePolicy* policy) override;
private: private:
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
DISALLOW_COPY_AND_ASSIGN(ChromeSelectFileDialogFactory); DISALLOW_COPY_AND_ASSIGN(ChromeSelectFileDialogFactory);
}; };
......
...@@ -658,6 +658,7 @@ ...@@ -658,6 +658,7 @@
], ],
}, },
'dependencies': [ 'dependencies': [
'../mojo/mojo_base.gyp:mojo_common_custom_types_mojom',
'../mojo/mojo_public.gyp:mojo_cpp_bindings', '../mojo/mojo_public.gyp:mojo_cpp_bindings',
'../skia/skia.gyp:skia_mojo', '../skia/skia.gyp:skia_mojo',
], ],
......
...@@ -15,8 +15,6 @@ ...@@ -15,8 +15,6 @@
'utility/cloud_print/pwg_encoder.h', 'utility/cloud_print/pwg_encoder.h',
'utility/image_decoder_impl.cc', 'utility/image_decoder_impl.cc',
'utility/image_decoder_impl.h', 'utility/image_decoder_impl.h',
'utility/ipc_shell_handler_win.cc',
'utility/ipc_shell_handler_win.h',
'utility/printing_handler.cc', 'utility/printing_handler.cc',
'utility/printing_handler.h', 'utility/printing_handler.h',
'utility/shell_handler_impl_win.cc', 'utility/shell_handler_impl_win.cc',
......
...@@ -434,4 +434,7 @@ mojom("mojo_bindings") { ...@@ -434,4 +434,7 @@ mojom("mojo_bindings") {
public_deps = [ public_deps = [
"//skia/public/interfaces", "//skia/public/interfaces",
] ]
deps = [
"//mojo/common:common_custom_types",
]
} }
...@@ -4,16 +4,10 @@ ...@@ -4,16 +4,10 @@
// Multiply-included message file, so no include guard. // Multiply-included message file, so no include guard.
#if defined(OS_WIN)
#include <Windows.h>
#endif // defined(OS_WIN)
#include <string> #include <string>
#include <tuple>
#include <vector> #include <vector>
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/strings/string16.h"
#include "base/values.h" #include "base/values.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "ipc/ipc_message_macros.h" #include "ipc/ipc_message_macros.h"
...@@ -31,13 +25,6 @@ ...@@ -31,13 +25,6 @@
#ifndef CHROME_COMMON_CHROME_UTILITY_MESSAGES_H_ #ifndef CHROME_COMMON_CHROME_UTILITY_MESSAGES_H_
#define CHROME_COMMON_CHROME_UTILITY_MESSAGES_H_ #define CHROME_COMMON_CHROME_UTILITY_MESSAGES_H_
#if defined(OS_WIN)
// A vector of filters, each being a tuple containing a display string (i.e.
// "Text Files") and a filter pattern (i.e. "*.txt").
typedef std::vector<std::tuple<base::string16, base::string16>>
GetOpenFileNameFilter;
#endif // OS_WIN
#endif // CHROME_COMMON_CHROME_UTILITY_MESSAGES_H_ #endif // CHROME_COMMON_CHROME_UTILITY_MESSAGES_H_
#define IPC_MESSAGE_START ChromeUtilityMsgStart #define IPC_MESSAGE_START ChromeUtilityMsgStart
...@@ -124,18 +111,6 @@ IPC_STRUCT_TRAITS_BEGIN(safe_browsing::zip_analyzer::Results) ...@@ -124,18 +111,6 @@ IPC_STRUCT_TRAITS_BEGIN(safe_browsing::zip_analyzer::Results)
IPC_STRUCT_TRAITS_END() IPC_STRUCT_TRAITS_END()
#endif // FULL_SAFE_BROWSING #endif // FULL_SAFE_BROWSING
#if defined(OS_WIN)
IPC_STRUCT_BEGIN(ChromeUtilityMsg_GetSaveFileName_Params)
IPC_STRUCT_MEMBER(HWND, owner)
IPC_STRUCT_MEMBER(DWORD, flags)
IPC_STRUCT_MEMBER(GetOpenFileNameFilter, filters)
IPC_STRUCT_MEMBER(int, one_based_filter_index)
IPC_STRUCT_MEMBER(base::FilePath, suggested_filename)
IPC_STRUCT_MEMBER(base::FilePath, initial_directory)
IPC_STRUCT_MEMBER(base::string16, default_extension)
IPC_STRUCT_END()
#endif // OS_WIN
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Utility process messages: // Utility process messages:
// These are messages from the browser to the utility process. // These are messages from the browser to the utility process.
...@@ -180,25 +155,6 @@ IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_AnalyzeDmgFileForDownloadProtection, ...@@ -180,25 +155,6 @@ IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_AnalyzeDmgFileForDownloadProtection,
#endif // defined(OS_MACOSX) #endif // defined(OS_MACOSX)
#endif // defined(FULL_SAFE_BROWSING) #endif // defined(FULL_SAFE_BROWSING)
#if defined(OS_WIN)
// Instructs the utility process to invoke GetOpenFileName. |owner| is the
// parent of the modal dialog, |flags| are OFN_* flags. |filter| constrains the
// user's file choices. |initial_directory| and |filename| select the directory
// to be displayed and the file to be initially selected.
//
// Either ChromeUtilityHostMsg_GetOpenFileName_Failed or
// ChromeUtilityHostMsg_GetOpenFileName_Result will be returned when the
// operation completes whether due to error or user action.
IPC_MESSAGE_CONTROL5(ChromeUtilityMsg_GetOpenFileName,
HWND /* owner */,
DWORD /* flags */,
GetOpenFileNameFilter /* filter */,
base::FilePath /* initial_directory */,
base::FilePath /* filename */)
IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_GetSaveFileName,
ChromeUtilityMsg_GetSaveFileName_Params /* params */)
#endif // defined(OS_WIN)
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Utility process host messages: // Utility process host messages:
// These are messages from the utility process to the browser. // These are messages from the utility process to the browser.
...@@ -233,14 +189,3 @@ IPC_MESSAGE_CONTROL1( ...@@ -233,14 +189,3 @@ IPC_MESSAGE_CONTROL1(
safe_browsing::zip_analyzer::Results) safe_browsing::zip_analyzer::Results)
#endif // defined(OS_MACOSX) #endif // defined(OS_MACOSX)
#endif // defined(FULL_SAFE_BROWSING) #endif // defined(FULL_SAFE_BROWSING)
#if defined(OS_WIN)
IPC_MESSAGE_CONTROL0(ChromeUtilityHostMsg_GetOpenFileName_Failed)
IPC_MESSAGE_CONTROL2(ChromeUtilityHostMsg_GetOpenFileName_Result,
base::FilePath /* directory */,
std::vector<base::FilePath> /* filenames */)
IPC_MESSAGE_CONTROL0(ChromeUtilityHostMsg_GetSaveFileName_Failed)
IPC_MESSAGE_CONTROL2(ChromeUtilityHostMsg_GetSaveFileName_Result,
base::FilePath /* path */,
int /* one_based_filter_index */)
#endif // defined(OS_WIN)
...@@ -4,7 +4,52 @@ ...@@ -4,7 +4,52 @@
module mojom; module mojom;
import "mojo/common/common_custom_types.mojom";
[Native]
struct FileExtensionFilters;
interface ShellHandler { interface ShellHandler {
// Returns the pinned state of the current executable. // Returns the pinned state of the current executable.
IsPinnedToTaskbar() => (bool succeeded, bool is_pinned_to_taskbar); IsPinnedToTaskbar() => (bool succeeded, bool is_pinned_to_taskbar);
};
\ No newline at end of file // Invokes GetOpenFileName.
// |owner| is the HWND to use as the parent of the modal dialog.
// |flags| is the OFN_* flags of OPENFILENAME.
// |filters| constrains the user's file choices.
// |initial_directory| is the directory to be displayed.
// |filename| is the file initially selected.
//
// Returns the list of selected |files|, which are all childs of |directory|.
// On cancelation or failure, |files| will be empty.
DoGetOpenFileName(uint32 owner,
uint32 flags,
FileExtensionFilters filters,
mojo.common.mojom.FilePath initial_directory,
mojo.common.mojom.FilePath filename) =>
(mojo.common.mojom.FilePath directory,
array<mojo.common.mojom.FilePath> files);
// Invokes GetSaveFileName.
// |owner| is the HWND to use as the parent of the modal dialog.
// |flags| is the OFN_* flags of OPENFILENAME.
// |filters| constrains the user's file choices.
// |one_based_filter_index| is The index of the currently selected filter in
// |filters|.
// |initial_directory| is the directory to be displayed.
// |filename| is the file initially selected.
// |default_extension| is the extension to add to the file if the user doesn't
// type one.
//
// Returns the selected |path| and the |one_based_filter_index| of the filter
// passed to the initial call to DoGetSaveFileName. On cancelation or failure,
// |path| will be empty.
DoGetSaveFileName(uint32 owner,
uint32 flags,
FileExtensionFilters filters,
uint32 one_based_filter_index,
mojo.common.mojom.FilePath initial_directory,
mojo.common.mojom.FilePath suggested_filename,
mojo.common.mojom.FilePath default_extension) =>
(mojo.common.mojom.FilePath path, uint32 one_based_filter_index);
};
# Copyright 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
mojom = "//chrome/common/shell_handler_win.mojom"
public_headers = [ "//base/strings/string16.h" ]
deps = [
"//base",
]
type_mappings = [ "mojom.FileExtensionFilters=" +
"std::vector<std::tuple<base::string16, base::string16>>" ]
# Copyright 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
typemaps = [ "//chrome/common/shell_handler_win.typemap" ]
...@@ -38,7 +38,6 @@ ...@@ -38,7 +38,6 @@
#endif #endif
#if defined(OS_WIN) #if defined(OS_WIN)
#include "chrome/utility/ipc_shell_handler_win.h"
#include "chrome/utility/shell_handler_impl_win.h" #include "chrome/utility/shell_handler_impl_win.h"
#endif #endif
...@@ -126,10 +125,6 @@ ChromeContentUtilityClient::ChromeContentUtilityClient() ...@@ -126,10 +125,6 @@ ChromeContentUtilityClient::ChromeContentUtilityClient()
(defined(ENABLE_BASIC_PRINTING) && defined(OS_WIN)) (defined(ENABLE_BASIC_PRINTING) && defined(OS_WIN))
handlers_.push_back(new printing::PrintingHandler()); handlers_.push_back(new printing::PrintingHandler());
#endif #endif
#if defined(OS_WIN)
handlers_.push_back(new IPCShellHandler());
#endif
} }
ChromeContentUtilityClient::~ChromeContentUtilityClient() { ChromeContentUtilityClient::~ChromeContentUtilityClient() {
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/utility/ipc_shell_handler_win.h"
#include <commdlg.h>
#include <memory>
#include "base/files/file_path.h"
#include "chrome/common/chrome_utility_messages.h"
#include "content/public/utility/utility_thread.h"
#include "ui/base/win/open_file_name_win.h"
IPCShellHandler::IPCShellHandler() {}
IPCShellHandler::~IPCShellHandler() {}
bool IPCShellHandler::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(IPCShellHandler, message)
IPC_MESSAGE_HANDLER(ChromeUtilityMsg_GetOpenFileName, OnGetOpenFileName)
IPC_MESSAGE_HANDLER(ChromeUtilityMsg_GetSaveFileName, OnGetSaveFileName)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void IPCShellHandler::OnGetOpenFileName(HWND owner,
DWORD flags,
const GetOpenFileNameFilter& filter,
const base::FilePath& initial_directory,
const base::FilePath& filename) {
ui::win::OpenFileName open_file_name(owner, flags);
open_file_name.SetInitialSelection(initial_directory, filename);
open_file_name.SetFilters(filter);
base::FilePath directory;
std::vector<base::FilePath> filenames;
if (::GetOpenFileName(open_file_name.GetOPENFILENAME()))
open_file_name.GetResult(&directory, &filenames);
if (filenames.size()) {
content::UtilityThread::Get()->Send(
new ChromeUtilityHostMsg_GetOpenFileName_Result(directory, filenames));
} else {
content::UtilityThread::Get()->Send(
new ChromeUtilityHostMsg_GetOpenFileName_Failed());
}
}
void IPCShellHandler::OnGetSaveFileName(
const ChromeUtilityMsg_GetSaveFileName_Params& params) {
ui::win::OpenFileName open_file_name(params.owner, params.flags);
open_file_name.SetInitialSelection(params.initial_directory,
params.suggested_filename);
open_file_name.SetFilters(params.filters);
open_file_name.GetOPENFILENAME()->nFilterIndex =
params.one_based_filter_index;
open_file_name.GetOPENFILENAME()->lpstrDefExt =
params.default_extension.c_str();
if (::GetSaveFileName(open_file_name.GetOPENFILENAME())) {
content::UtilityThread::Get()->Send(
new ChromeUtilityHostMsg_GetSaveFileName_Result(
base::FilePath(open_file_name.GetOPENFILENAME()->lpstrFile),
open_file_name.GetOPENFILENAME()->nFilterIndex));
return;
}
// Zero means the dialog was closed, otherwise we had an error.
DWORD error_code = ::CommDlgExtendedError();
if (error_code != 0)
NOTREACHED() << "GetSaveFileName failed with code: " << error_code;
content::UtilityThread::Get()->Send(
new ChromeUtilityHostMsg_GetSaveFileName_Failed());
}
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_UTILITY_IPC_SHELL_HANDLER_WIN_H_
#define CHROME_UTILITY_IPC_SHELL_HANDLER_WIN_H_
#include <Windows.h>
#include <tuple>
#include <vector>
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/strings/string16.h"
#include "chrome/utility/utility_message_handler.h"
namespace base {
class FilePath;
} // namespace base
using GetOpenFileNameFilter =
std::vector<std::tuple<base::string16, base::string16>>;
struct ChromeUtilityMsg_GetSaveFileName_Params;
// Handles requests to execute shell operations. Used to protect the browser
// process from instability due to 3rd-party shell extensions. Must be invoked
// in a non-sandboxed utility process.
// Note: This class is deprecated in favor of the Mojo version.
// See chrome/common/shell_handler_win.mojom and
// chrome/utility/shell_handler_impl_win.h
class IPCShellHandler : public UtilityMessageHandler {
public:
IPCShellHandler();
~IPCShellHandler() override;
// IPC::Listener implementation
bool OnMessageReceived(const IPC::Message& message) override;
private:
void OnGetOpenFileName(HWND owner,
DWORD flags,
const GetOpenFileNameFilter& filter,
const base::FilePath& initial_directory,
const base::FilePath& filename);
void OnGetSaveFileName(const ChromeUtilityMsg_GetSaveFileName_Params& params);
DISALLOW_COPY_AND_ASSIGN(IPCShellHandler);
};
#endif // CHROME_UTILITY_IPC_SHELL_HANDLER_WIN_H_
...@@ -17,9 +17,14 @@ ...@@ -17,9 +17,14 @@
#include "base/win/shortcut.h" #include "base/win/shortcut.h"
#include "chrome/installer/util/install_util.h" #include "chrome/installer/util/install_util.h"
#include "content/public/utility/utility_thread.h" #include "content/public/utility/utility_thread.h"
#include "ui/base/win/open_file_name_win.h"
namespace { namespace {
HWND Uint32ToHWND(uint32_t value) {
return reinterpret_cast<HWND>(value);
}
// This class checks if the current executable is pinned to the taskbar. It also // This class checks if the current executable is pinned to the taskbar. It also
// keeps track of the errors that occurs that prevents it from getting a result. // keeps track of the errors that occurs that prevents it from getting a result.
class IsPinnedToTaskbarHelper { class IsPinnedToTaskbarHelper {
...@@ -222,3 +227,56 @@ void ShellHandlerImpl::IsPinnedToTaskbar( ...@@ -222,3 +227,56 @@ void ShellHandlerImpl::IsPinnedToTaskbar(
bool is_pinned_to_taskbar = helper.GetResult(); bool is_pinned_to_taskbar = helper.GetResult();
callback.Run(!helper.error_occured(), is_pinned_to_taskbar); callback.Run(!helper.error_occured(), is_pinned_to_taskbar);
} }
void ShellHandlerImpl::DoGetOpenFileName(
uint32_t owner,
uint32_t flags,
const std::vector<std::tuple<base::string16, base::string16>>& filters,
const base::FilePath& initial_directory,
const base::FilePath& filename,
const DoGetOpenFileNameCallback& callback) {
ui::win::OpenFileName open_file_name(Uint32ToHWND(owner), flags);
open_file_name.SetInitialSelection(initial_directory, filename);
open_file_name.SetFilters(filters);
base::FilePath directory;
std::vector<base::FilePath> filenames;
if (::GetOpenFileName(open_file_name.GetOPENFILENAME()))
open_file_name.GetResult(&directory, &filenames);
if (!filenames.empty())
callback.Run(directory, filenames);
else
callback.Run(base::FilePath(), std::vector<base::FilePath>());
}
void ShellHandlerImpl::DoGetSaveFileName(
uint32_t owner,
uint32_t flags,
const std::vector<std::tuple<base::string16, base::string16>>& filters,
uint32_t one_based_filter_index,
const base::FilePath& initial_directory,
const base::FilePath& suggested_filename,
const base::FilePath& default_extension,
const DoGetSaveFileNameCallback& callback) {
ui::win::OpenFileName open_file_name(reinterpret_cast<HWND>(owner), flags);
open_file_name.SetInitialSelection(initial_directory, suggested_filename);
open_file_name.SetFilters(filters);
open_file_name.GetOPENFILENAME()->nFilterIndex = one_based_filter_index;
open_file_name.GetOPENFILENAME()->lpstrDefExt =
default_extension.value().c_str();
if (::GetSaveFileName(open_file_name.GetOPENFILENAME())) {
callback.Run(base::FilePath(open_file_name.GetOPENFILENAME()->lpstrFile),
open_file_name.GetOPENFILENAME()->nFilterIndex);
return;
}
// Zero means the dialog was closed, otherwise we had an error.
DWORD error_code = ::CommDlgExtendedError();
if (error_code != 0)
NOTREACHED() << "GetSaveFileName failed with code: " << error_code;
callback.Run(base::FilePath(), 0);
}
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
#ifndef CHROME_UTILITY_SHELL_HANDLER_IMPL_WIN_H_ #ifndef CHROME_UTILITY_SHELL_HANDLER_IMPL_WIN_H_
#define CHROME_UTILITY_SHELL_HANDLER_IMPL_WIN_H_ #define CHROME_UTILITY_SHELL_HANDLER_IMPL_WIN_H_
#include <tuple>
#include <vector>
#include "base/macros.h" #include "base/macros.h"
#include "chrome/common/shell_handler_win.mojom.h" #include "chrome/common/shell_handler_win.mojom.h"
#include "mojo/public/cpp/bindings/strong_binding.h" #include "mojo/public/cpp/bindings/strong_binding.h"
...@@ -21,6 +24,24 @@ class ShellHandlerImpl : public mojom::ShellHandler { ...@@ -21,6 +24,24 @@ class ShellHandlerImpl : public mojom::ShellHandler {
// mojom::ShellHandler: // mojom::ShellHandler:
void IsPinnedToTaskbar(const IsPinnedToTaskbarCallback& callback) override; void IsPinnedToTaskbar(const IsPinnedToTaskbarCallback& callback) override;
void DoGetOpenFileName(
uint32_t owner,
uint32_t flags,
const std::vector<std::tuple<base::string16, base::string16>>& filters,
const base::FilePath& initial_directory,
const base::FilePath& filename,
const DoGetOpenFileNameCallback& callback) override;
void DoGetSaveFileName(
uint32_t owner,
uint32_t flags,
const std::vector<std::tuple<base::string16, base::string16>>& filters,
uint32_t one_based_filter_index,
const base::FilePath& initial_directory,
const base::FilePath& suggested_filename,
const base::FilePath& default_extension,
const DoGetSaveFileNameCallback& callback) override;
mojo::StrongBinding<ShellHandler> binding_; mojo::StrongBinding<ShellHandler> binding_;
DISALLOW_COPY_AND_ASSIGN(ShellHandlerImpl); DISALLOW_COPY_AND_ASSIGN(ShellHandlerImpl);
......
...@@ -4,9 +4,10 @@ ...@@ -4,9 +4,10 @@
_typemap_imports = [ _typemap_imports = [
"//cc/ipc/typemaps.gni", "//cc/ipc/typemaps.gni",
"//device/bluetooth/public/interfaces/typemaps.gni", "//chrome/common/typemaps.gni",
"//components/arc/common/typemaps.gni", "//components/arc/common/typemaps.gni",
"//components/typemaps.gni", "//components/typemaps.gni",
"//device/bluetooth/public/interfaces/typemaps.gni",
"//gpu/ipc/common/typemaps.gni", "//gpu/ipc/common/typemaps.gni",
"//media/mojo/interfaces/typemaps.gni", "//media/mojo/interfaces/typemaps.gni",
"//mojo/common/typemaps.gni", "//mojo/common/typemaps.gni",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment