Index: components/nacl/browser/nacl_process_host.cc |
diff --git a/components/nacl/browser/nacl_process_host.cc b/components/nacl/browser/nacl_process_host.cc |
index 08bf18d15d805d3325fb09a670abd661cec50241..63a90dae576501617da5efdb9f8aa9e5eec8ec86 100644 |
--- a/components/nacl/browser/nacl_process_host.cc |
+++ b/components/nacl/browser/nacl_process_host.cc |
@@ -203,6 +203,72 @@ void CloseFile(base::File file) { |
unsigned NaClProcessHost::keepalive_throttle_interval_milliseconds_ = |
ppapi::kKeepaliveThrottleIntervalDefaultMilliseconds; |
+// Unfortunately, we cannot use ScopedGeneric directly for IPC::ChannelHandle, |
+// because there is neither operator== nor operator != definition for it. |
+// Instead, define a simple wrapper for IPC::ChannelHandle with an assumption |
+// that this only takes a transferred IPC::ChannelHandle or one to be |
+// transferred via IPC. |
+class NaClProcessHost::ScopedChannelHandle { |
+ MOVE_ONLY_TYPE_FOR_CPP_03(ScopedChannelHandle, RValue); |
+ public: |
+ ScopedChannelHandle() { |
+ } |
+ explicit ScopedChannelHandle(const IPC::ChannelHandle& handle) |
+ : handle_(handle) { |
+ DCHECK(IsSupportedHandle(handle_)); |
+ } |
+ ScopedChannelHandle(RValue other) : handle_(other.object->handle_) { |
+ other.object->handle_ = IPC::ChannelHandle(); |
+ DCHECK(IsSupportedHandle(handle_)); |
+ } |
+ ~ScopedChannelHandle() { |
+ CloseIfNecessary(); |
+ } |
+ |
+ const IPC::ChannelHandle& get() const { return handle_; } |
+ IPC::ChannelHandle release() WARN_UNUSED_RESULT { |
+ IPC::ChannelHandle result = handle_; |
+ handle_ = IPC::ChannelHandle(); |
+ return result; |
+ } |
+ |
+ void reset(const IPC::ChannelHandle& handle = IPC::ChannelHandle()) { |
+ DCHECK(IsSupportedHandle(handle)); |
+#if defined(OS_POSIX) |
+ // Following the manner of base::ScopedGeneric, we do not support |
+ // reset() with same handle for simplicity of the implementation. |
+ CHECK(handle.socket.fd == -1 || handle.socket.fd != handle_.socket.fd); |
+#endif |
+ CloseIfNecessary(); |
+ handle_ = handle; |
+ } |
+ |
+ private: |
+ // Returns true if the given handle is closable automatically by this |
+ // class. This function is just a helper for validation. |
+ static bool IsSupportedHandle(const IPC::ChannelHandle& handle) { |
+#if defined(OS_WIN) |
+ // On Windows, it is not supported to marshal the |pipe.handle|. |
+ // In our case, we wrap a transferred ChannelHandle (or one to be |
+ // transferred) via IPC, so we can assume |handle.pipe.handle| is NULL. |
+ return handle.pipe.handle == NULL; |
+#else |
+ return true; |
+#endif |
+ } |
+ |
+ void CloseIfNecessary() { |
+#if defined(OS_POSIX) |
+ if (handle_.socket.auto_close) { |
+ // Defer closing task to the ScopedFD. |
+ base::ScopedFD(handle_.socket.fd); |
+ } |
+#endif |
+ } |
+ |
+ IPC::ChannelHandle handle_; |
+}; |
+ |
NaClProcessHost::NaClProcessHost( |
const GURL& manifest_url, |
base::File nexe_file, |
@@ -656,10 +722,10 @@ void NaClProcessHost::OnResourcesReady() { |
} |
} |
-bool NaClProcessHost::ReplyToRenderer( |
- const IPC::ChannelHandle& ppapi_channel_handle, |
- const IPC::ChannelHandle& trusted_channel_handle, |
- const IPC::ChannelHandle& manifest_service_channel_handle) { |
+void NaClProcessHost::ReplyToRenderer( |
+ ScopedChannelHandle ppapi_channel_handle, |
+ ScopedChannelHandle trusted_channel_handle, |
+ ScopedChannelHandle manifest_service_channel_handle) { |
#if defined(OS_WIN) |
// If we are on 64-bit Windows, the NaCl process's sandbox is |
// managed by a different process from the renderer's sandbox. We |
@@ -669,58 +735,44 @@ bool NaClProcessHost::ReplyToRenderer( |
if (RunningOnWOW64()) { |
if (!content::BrokerAddTargetPeer(process_->GetData().handle)) { |
SendErrorToRenderer("BrokerAddTargetPeer() failed"); |
- return false; |
+ return; |
} |
} |
#endif |
- FileDescriptor imc_handle_for_renderer; |
-#if defined(OS_WIN) |
- // Copy the handle into the renderer process. |
- HANDLE handle_in_renderer; |
- if (!DuplicateHandle(base::GetCurrentProcessHandle(), |
- socket_for_renderer_.TakePlatformFile(), |
- nacl_host_message_filter_->PeerHandle(), |
- &handle_in_renderer, |
- 0, // Unused given DUPLICATE_SAME_ACCESS. |
- FALSE, |
- DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { |
- SendErrorToRenderer("DuplicateHandle() failed"); |
- return false; |
- } |
- imc_handle_for_renderer = reinterpret_cast<FileDescriptor>( |
- handle_in_renderer); |
-#else |
- // No need to dup the imc_handle - we don't pass it anywhere else so |
- // it cannot be closed. |
- FileDescriptor imc_handle; |
- imc_handle.fd = socket_for_renderer_.TakePlatformFile(); |
- imc_handle.auto_close = true; |
- imc_handle_for_renderer = imc_handle; |
-#endif |
+ // Hereafter, we always send an IPC message with handles which, on Windows, |
+ // are not closable in this process. |
+ IPC::PlatformFileForTransit imc_handle_for_renderer = |
+ IPC::TakeFileHandleForProcess(socket_for_renderer_.Pass(), |
Mark Seaborn
2015/05/07 22:19:56
Looking again, I noticed that you're not checking
hidehiko
2015/05/11 12:08:35
Ah, you're right. I'll send another CL.
|
+ nacl_host_message_filter_->PeerHandle()); |
- const ChildProcessData& data = process_->GetData(); |
+ std::string error_message; |
base::SharedMemoryHandle crash_info_shmem_renderer_handle; |
if (!crash_info_shmem_.ShareToProcess(nacl_host_message_filter_->PeerHandle(), |
&crash_info_shmem_renderer_handle)) { |
- SendErrorToRenderer("ShareToProcess() failed"); |
- return false; |
+ // On error, we do not send "IPC::ChannelHandle"s to the renderer process. |
+ // Note that some other FDs/handles still get sent to the renderer, but |
+ // will be closed there. |
+ ppapi_channel_handle.reset(); |
+ trusted_channel_handle.reset(); |
+ manifest_service_channel_handle.reset(); |
+ error_message = "ShareToProcess() failed"; |
} |
+ const ChildProcessData& data = process_->GetData(); |
SendMessageToRenderer( |
NaClLaunchResult(imc_handle_for_renderer, |
- ppapi_channel_handle, |
- trusted_channel_handle, |
- manifest_service_channel_handle, |
+ ppapi_channel_handle.release(), |
+ trusted_channel_handle.release(), |
+ manifest_service_channel_handle.release(), |
base::GetProcId(data.handle), |
data.id, |
crash_info_shmem_renderer_handle), |
- std::string() /* error_message */); |
+ error_message); |
// Now that the crash information shmem handles have been shared with the |
// plugin and the renderer, the browser can close its handle. |
crash_info_shmem_.Close(); |
- return true; |
} |
void NaClProcessHost::SendErrorToRenderer(const std::string& error_message) { |
@@ -733,13 +785,18 @@ void NaClProcessHost::SendMessageToRenderer( |
const std::string& error_message) { |
DCHECK(nacl_host_message_filter_.get()); |
DCHECK(reply_msg_); |
- if (nacl_host_message_filter_.get() != NULL && reply_msg_ != NULL) { |
- NaClHostMsg_LaunchNaCl::WriteReplyParams( |
- reply_msg_, result, error_message); |
- nacl_host_message_filter_->Send(reply_msg_); |
- nacl_host_message_filter_ = NULL; |
- reply_msg_ = NULL; |
+ if (nacl_host_message_filter_.get() == NULL || reply_msg_ == NULL) { |
+ // As DCHECKed above, this case should not happen in general. |
+ // Though, in this case, unfortunately there is no proper way to release |
+ // resources which are already created in |result|. We just give up on |
+ // releasing them, and leak them. |
+ return; |
} |
+ |
+ NaClHostMsg_LaunchNaCl::WriteReplyParams(reply_msg_, result, error_message); |
+ nacl_host_message_filter_->Send(reply_msg_); |
+ nacl_host_message_filter_ = NULL; |
+ reply_msg_ = NULL; |
} |
void NaClProcessHost::SetDebugStubPort(int port) { |
@@ -941,74 +998,83 @@ void NaClProcessHost::StartNaClFileResolved( |
// This method is called when NaClProcessHostMsg_PpapiChannelCreated is |
// received. |
void NaClProcessHost::OnPpapiChannelsCreated( |
- const IPC::ChannelHandle& browser_channel_handle, |
- const IPC::ChannelHandle& ppapi_renderer_channel_handle, |
- const IPC::ChannelHandle& trusted_renderer_channel_handle, |
- const IPC::ChannelHandle& manifest_service_channel_handle) { |
+ const IPC::ChannelHandle& raw_browser_channel_handle, |
+ const IPC::ChannelHandle& raw_ppapi_renderer_channel_handle, |
+ const IPC::ChannelHandle& raw_trusted_renderer_channel_handle, |
+ const IPC::ChannelHandle& raw_manifest_service_channel_handle) { |
+ ScopedChannelHandle browser_channel_handle(raw_browser_channel_handle); |
+ ScopedChannelHandle ppapi_renderer_channel_handle( |
+ raw_ppapi_renderer_channel_handle); |
+ ScopedChannelHandle trusted_renderer_channel_handle( |
+ raw_trusted_renderer_channel_handle); |
+ ScopedChannelHandle manifest_service_channel_handle( |
+ raw_manifest_service_channel_handle); |
+ |
if (!enable_ppapi_proxy()) { |
- ReplyToRenderer(IPC::ChannelHandle(), |
- trusted_renderer_channel_handle, |
- manifest_service_channel_handle); |
+ ReplyToRenderer(ScopedChannelHandle(), |
+ trusted_renderer_channel_handle.Pass(), |
+ manifest_service_channel_handle.Pass()); |
return; |
} |
- if (!ipc_proxy_channel_.get()) { |
- DCHECK_EQ(PROCESS_TYPE_NACL_LOADER, process_->GetData().process_type); |
+ if (ipc_proxy_channel_.get()) { |
+ // Attempt to open more than 1 browser channel is not supported. |
+ // Shut down the NaCl process. |
+ process_->GetHost()->ForceShutdown(); |
+ return; |
+ } |
- ipc_proxy_channel_ = |
- IPC::ChannelProxy::Create(browser_channel_handle, |
- IPC::Channel::MODE_CLIENT, |
- NULL, |
- base::MessageLoopProxy::current().get()); |
- // Create the browser ppapi host and enable PPAPI message dispatching to the |
- // browser process. |
- ppapi_host_.reset(content::BrowserPpapiHost::CreateExternalPluginProcess( |
- ipc_proxy_channel_.get(), // sender |
- permissions_, |
- process_->GetData().handle, |
- ipc_proxy_channel_.get(), |
- nacl_host_message_filter_->render_process_id(), |
- render_view_id_, |
- profile_directory_)); |
- ppapi_host_->SetOnKeepaliveCallback( |
- NaClBrowser::GetDelegate()->GetOnKeepaliveCallback()); |
- |
- ppapi::PpapiNaClPluginArgs args; |
- args.off_the_record = nacl_host_message_filter_->off_the_record(); |
- args.permissions = permissions_; |
- args.keepalive_throttle_interval_milliseconds = |
- keepalive_throttle_interval_milliseconds_; |
- base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess(); |
- DCHECK(cmdline); |
- std::string flag_whitelist[] = { |
- switches::kV, |
- switches::kVModule, |
- }; |
- for (size_t i = 0; i < arraysize(flag_whitelist); ++i) { |
- std::string value = cmdline->GetSwitchValueASCII(flag_whitelist[i]); |
- if (!value.empty()) { |
- args.switch_names.push_back(flag_whitelist[i]); |
- args.switch_values.push_back(value); |
- } |
+ DCHECK_EQ(PROCESS_TYPE_NACL_LOADER, process_->GetData().process_type); |
+ |
+ ipc_proxy_channel_ = |
+ IPC::ChannelProxy::Create(browser_channel_handle.release(), |
+ IPC::Channel::MODE_CLIENT, |
+ NULL, |
+ base::MessageLoopProxy::current().get()); |
+ // Create the browser ppapi host and enable PPAPI message dispatching to the |
+ // browser process. |
+ ppapi_host_.reset(content::BrowserPpapiHost::CreateExternalPluginProcess( |
+ ipc_proxy_channel_.get(), // sender |
+ permissions_, |
+ process_->GetData().handle, |
+ ipc_proxy_channel_.get(), |
+ nacl_host_message_filter_->render_process_id(), |
+ render_view_id_, |
+ profile_directory_)); |
+ ppapi_host_->SetOnKeepaliveCallback( |
+ NaClBrowser::GetDelegate()->GetOnKeepaliveCallback()); |
+ |
+ ppapi::PpapiNaClPluginArgs args; |
+ args.off_the_record = nacl_host_message_filter_->off_the_record(); |
+ args.permissions = permissions_; |
+ args.keepalive_throttle_interval_milliseconds = |
+ keepalive_throttle_interval_milliseconds_; |
+ base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess(); |
+ DCHECK(cmdline); |
+ std::string flag_whitelist[] = { |
+ switches::kV, |
+ switches::kVModule, |
+ }; |
+ for (size_t i = 0; i < arraysize(flag_whitelist); ++i) { |
+ std::string value = cmdline->GetSwitchValueASCII(flag_whitelist[i]); |
+ if (!value.empty()) { |
+ args.switch_names.push_back(flag_whitelist[i]); |
+ args.switch_values.push_back(value); |
} |
+ } |
- ppapi_host_->GetPpapiHost()->AddHostFactoryFilter( |
- scoped_ptr<ppapi::host::HostFactory>( |
- NaClBrowser::GetDelegate()->CreatePpapiHostFactory( |
- ppapi_host_.get()))); |
+ ppapi_host_->GetPpapiHost()->AddHostFactoryFilter( |
+ scoped_ptr<ppapi::host::HostFactory>( |
+ NaClBrowser::GetDelegate()->CreatePpapiHostFactory( |
+ ppapi_host_.get()))); |
- // Send a message to initialize the IPC dispatchers in the NaCl plugin. |
- ipc_proxy_channel_->Send(new PpapiMsg_InitializeNaClDispatcher(args)); |
+ // Send a message to initialize the IPC dispatchers in the NaCl plugin. |
+ ipc_proxy_channel_->Send(new PpapiMsg_InitializeNaClDispatcher(args)); |
- // Let the renderer know that the IPC channels are established. |
- ReplyToRenderer(ppapi_renderer_channel_handle, |
- trusted_renderer_channel_handle, |
- manifest_service_channel_handle); |
- } else { |
- // Attempt to open more than 1 browser channel is not supported. |
- // Shut down the NaCl process. |
- process_->GetHost()->ForceShutdown(); |
- } |
+ // Let the renderer know that the IPC channels are established. |
+ ReplyToRenderer(ppapi_renderer_channel_handle.Pass(), |
+ trusted_renderer_channel_handle.Pass(), |
+ manifest_service_channel_handle.Pass()); |
} |
bool NaClProcessHost::StartWithLaunchedProcess() { |