diff options
author | apatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-24 22:54:50 +0000 |
---|---|---|
committer | apatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-24 22:54:50 +0000 |
commit | 0100b7a2759c96bfa3813c0eb5f92e9683edff2e (patch) | |
tree | 516c5b77a95bacf27a4414e75e7d8e29aaba3f3d | |
parent | f7c6df64064e4298e45635903264fe6b2971b229 (diff) | |
download | chromium_src-0100b7a2759c96bfa3813c0eb5f92e9683edff2e.zip chromium_src-0100b7a2759c96bfa3813c0eb5f92e9683edff2e.tar.gz chromium_src-0100b7a2759c96bfa3813c0eb5f92e9683edff2e.tar.bz2 |
Moved creation of GPU transfer buffers into the browser process.
Transfer buffer creation was previously done in the GPU process. This is one step required to sandbox the GPU process.
Rather than the GPU process opening a renderer process's handle by PID, which can't been done when sandboxed on Windows, the browser process passes the handle to the GPU process via the renderer process.
TEST=try
BUG=none
Review URL: http://codereview.chromium.org/6557006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@75980 0039d316-1c4b-4281-b951-d872f2087c98
30 files changed, 352 insertions, 88 deletions
diff --git a/chrome/browser/gpu_process_host_ui_shim.cc b/chrome/browser/gpu_process_host_ui_shim.cc index 3b7781b..cb49353 100644 --- a/chrome/browser/gpu_process_host_ui_shim.cc +++ b/chrome/browser/gpu_process_host_ui_shim.cc @@ -167,6 +167,7 @@ RenderWidgetHostView* GpuProcessHostUIShim::ViewSurface:: GpuProcessHostUIShim::GpuProcessHostUIShim() : host_id_(++g_last_host_id), + gpu_process_(NULL), gpu_feature_flags_set_(false) { g_hosts_by_id.AddWithID(this, host_id_); } @@ -206,6 +207,18 @@ void GpuProcessHostUIShim::Destroy(int host_id) { } // static +void GpuProcessHostUIShim::NotifyGpuProcessLaunched( + int host_id, + base::ProcessHandle gpu_process) { + DCHECK(gpu_process); + + GpuProcessHostUIShim* ui_shim = FromID(host_id); + DCHECK(ui_shim); + + ui_shim->gpu_process_ = gpu_process; +} + +// static GpuProcessHostUIShim* GpuProcessHostUIShim::FromID(int host_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); if (host_id == 0) @@ -230,20 +243,25 @@ namespace { void EstablishChannelCallbackDispatcher( GpuProcessHostUIShim::EstablishChannelCallback* callback, const IPC::ChannelHandle& channel_handle, + base::ProcessHandle renderer_process_for_gpu, const GPUInfo& gpu_info) { scoped_ptr<GpuProcessHostUIShim::EstablishChannelCallback> wrapped_callback(callback); - wrapped_callback->Run(channel_handle, gpu_info); + wrapped_callback->Run(channel_handle, renderer_process_for_gpu, gpu_info); } void EstablishChannelError( GpuProcessHostUIShim::EstablishChannelCallback* callback, const IPC::ChannelHandle& channel_handle, + base::ProcessHandle renderer_process_for_gpu, const GPUInfo& gpu_info) { BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableFunction(&EstablishChannelCallbackDispatcher, - callback, channel_handle, gpu_info)); + callback, + channel_handle, + renderer_process_for_gpu, + gpu_info)); } void SynchronizeCallbackDispatcher( @@ -284,7 +302,10 @@ void GpuProcessHostUIShim::SendOutstandingReplies() { while (!channel_requests_.empty()) { linked_ptr<EstablishChannelCallback> callback = channel_requests_.front(); channel_requests_.pop(); - EstablishChannelError(callback.release(), IPC::ChannelHandle(), GPUInfo()); + EstablishChannelError(callback.release(), + IPC::ChannelHandle(), + NULL, + GPUInfo()); } // Now unblock all renderers waiting for synchronization replies. @@ -305,14 +326,15 @@ bool GpuProcessHostUIShim::OnMessageReceived(const IPC::Message& message) { } void GpuProcessHostUIShim::EstablishGpuChannel( - int renderer_id, EstablishChannelCallback *callback) { + int renderer_id, + EstablishChannelCallback *callback) { DCHECK(CalledOnValidThread()); linked_ptr<EstablishChannelCallback> wrapped_callback(callback); // If GPU features are already blacklisted, no need to establish the channel. if (gpu_feature_flags_.flags() != 0) { EstablishChannelError( - wrapped_callback.release(), IPC::ChannelHandle(), GPUInfo()); + wrapped_callback.release(), IPC::ChannelHandle(), NULL, GPUInfo()); return; } @@ -320,7 +342,7 @@ void GpuProcessHostUIShim::EstablishGpuChannel( channel_requests_.push(wrapped_callback); } else { EstablishChannelError( - wrapped_callback.release(), IPC::ChannelHandle(), GPUInfo()); + wrapped_callback.release(), IPC::ChannelHandle(), NULL, GPUInfo()); } } @@ -399,6 +421,11 @@ const GPUInfo& GpuProcessHostUIShim::gpu_info() const { GpuProcessHostUIShim::~GpuProcessHostUIShim() { DCHECK(CalledOnValidThread()); g_hosts_by_id.Remove(host_id_); + +#if defined(OS_WIN) + if (gpu_process_) + CloseHandle(gpu_process_); +#endif } bool GpuProcessHostUIShim::Init() { @@ -449,6 +476,10 @@ bool GpuProcessHostUIShim::OnControlMessageReceived( void GpuProcessHostUIShim::OnChannelEstablished( const IPC::ChannelHandle& channel_handle, const GPUInfo& gpu_info) { + // The GPU process should have launched at this point and this object should + // have been notified of its process handle. + DCHECK(gpu_process_); + uint32 max_entry_id = gpu_blacklist_->max_entry_id(); // max_entry_id can be zero if we failed to load the GPU blacklist, don't // bother with histograms then. @@ -488,11 +519,15 @@ void GpuProcessHostUIShim::OnChannelEstablished( // GPU channel. if (gpu_feature_flags_.flags() != 0) { Send(new GpuMsg_CloseChannel(channel_handle)); - EstablishChannelError(callback.release(), IPC::ChannelHandle(), gpu_info); + EstablishChannelError(callback.release(), + IPC::ChannelHandle(), + NULL, + gpu_info); AddCustomLogMessage(logging::LOG_WARNING, "WARNING", "GPU is blacklisted."); - } else { - callback->Run(channel_handle, gpu_info); + return; } + + callback->Run(channel_handle, gpu_process_, gpu_info); } void GpuProcessHostUIShim::OnSynchronizeReply() { diff --git a/chrome/browser/gpu_process_host_ui_shim.h b/chrome/browser/gpu_process_host_ui_shim.h index 33d5cd2..f973860 100644 --- a/chrome/browser/gpu_process_host_ui_shim.h +++ b/chrome/browser/gpu_process_host_ui_shim.h @@ -17,6 +17,7 @@ #include "base/callback.h" #include "base/linked_ptr.h" +#include "base/process.h" #include "base/scoped_ptr.h" #include "base/singleton.h" #include "base/values.h" @@ -108,6 +109,12 @@ class GpuProcessHostUIShim // UI shim. static void Destroy(int host_id); + // The GPU process is launched asynchronously. If it launches successfully, + // this function is called on the UI thread with the process handle. On + // Windows, the UI shim takes ownership of the handle. + static void NotifyGpuProcessLaunched(int host_id, + base::ProcessHandle gpu_process); + static GpuProcessHostUIShim* FromID(int host_id); int host_id() const { return host_id_; } @@ -125,7 +132,9 @@ class GpuProcessHostUIShim // actually received on the IO thread. virtual bool OnMessageReceived(const IPC::Message& message); - typedef Callback2<const IPC::ChannelHandle&, const GPUInfo&>::Type + typedef Callback3<const IPC::ChannelHandle&, + base::ProcessHandle, + const GPUInfo&>::Type EstablishChannelCallback; // Tells the GPU process to create a new channel for communication with a @@ -210,6 +219,9 @@ class GpuProcessHostUIShim // The serial number of the GpuProcessHost / GpuProcessHostUIShim pair. int host_id_; + // The handle for the GPU process or null if it is not known to be launched. + base::ProcessHandle gpu_process_; + GPUInfo gpu_info_; ListValue log_messages_; diff --git a/chrome/common/gpu_messages_internal.h b/chrome/common/gpu_messages_internal.h index 4b611aa..b95a42a 100644 --- a/chrome/common/gpu_messages_internal.h +++ b/chrome/common/gpu_messages_internal.h @@ -179,6 +179,13 @@ IPC_MESSAGE_CONTROL2(GpuHostMsg_ScheduleComposite, // GPU Channel Messages // These are messages from a renderer process to the GPU process. +// Initialize a channel between a renderer process and a GPU process. The +// renderer passes its process handle to the GPU process, which gives gives the +// GPU process the ability to map handles from the renderer process. This must +// be the first message sent on a newly connected channel. +IPC_MESSAGE_CONTROL1(GpuChannelMsg_Initialize, + base::ProcessHandle /* renderer_process_for_gpu */) + // Tells the GPU process to create a new command buffer that renders to an // offscreen frame buffer. If parent_route_id is not zero, the texture backing // the frame buffer is mapped into the corresponding parent command buffer's @@ -257,6 +264,13 @@ IPC_SYNC_MESSAGE_ROUTED1_1(GpuCommandBufferMsg_CreateTransferBuffer, int32 /* size */, int32 /* id */) +// Register an existing shared memory transfer buffer. Returns an id that can be +// used to identify the transfer buffer from a command buffer. +IPC_SYNC_MESSAGE_ROUTED2_1(GpuCommandBufferMsg_RegisterTransferBuffer, + base::SharedMemoryHandle /* transfer_buffer */, + size_t /* size */, + int32 /* id */) + // Destroy a previously created transfer buffer. IPC_SYNC_MESSAGE_ROUTED1_0(GpuCommandBufferMsg_DestroyTransferBuffer, int32 /* id */) diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 05cc5b5..47b2f6e 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -653,8 +653,9 @@ IPC_MESSAGE_ROUTED0(ViewMsg_DisassociateFromPopupCount) // The browser sends this to a renderer process in response to a // GpuHostMsg_EstablishGpuChannel message. -IPC_MESSAGE_CONTROL2(ViewMsg_GpuChannelEstablished, +IPC_MESSAGE_CONTROL3(ViewMsg_GpuChannelEstablished, IPC::ChannelHandle /* handle to channel */, + base::ProcessHandle /* renderer_process_for_gpu */, GPUInfo /* stats about GPU process*/) // Notifies the renderer of the appcache that has been selected for a @@ -1914,13 +1915,11 @@ IPC_MESSAGE_CONTROL1(ViewHostMsg_TempFileForPrintingWritten, int /* fd in browser */) #endif -#if defined(OS_POSIX) // Asks the browser to create a block of shared memory for the renderer to // fill in and pass back to the browser. IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_AllocateSharedMemoryBuffer, uint32 /* buffer size */, base::SharedMemoryHandle /* browser handle */) -#endif // Provide the browser process with information about the WebCore resource // cache. diff --git a/chrome/gpu/gpu_channel.cc b/chrome/gpu/gpu_channel.cc index 6df37d0..dbbb9a5 100644 --- a/chrome/gpu/gpu_channel.cc +++ b/chrome/gpu/gpu_channel.cc @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/gpu/gpu_channel.h" - #if defined(OS_WIN) #include <windows.h> #endif +#include "chrome/gpu/gpu_channel.h" + #include "base/command_line.h" #include "base/process_util.h" #include "base/string_util.h" @@ -22,21 +22,23 @@ #include "ipc/ipc_channel_posix.h" #endif -GpuChannel::GpuChannel(GpuThread* gpu_thread, int renderer_id) +GpuChannel::GpuChannel(GpuThread* gpu_thread, + int renderer_id) : gpu_thread_(gpu_thread), - renderer_id_(renderer_id) { + renderer_id_(renderer_id), + renderer_process_(NULL), + renderer_pid_(NULL) { DCHECK(gpu_thread); + DCHECK(renderer_id); const CommandLine* command_line = CommandLine::ForCurrentProcess(); log_messages_ = command_line->HasSwitch(switches::kLogPluginMessages); } GpuChannel::~GpuChannel() { -} - -void GpuChannel::OnChannelConnected(int32 peer_pid) { - if (!renderer_process_.Open(peer_pid)) { - NOTREACHED(); - } +#if defined(OS_WIN) + if (renderer_process_) + CloseHandle(renderer_process_); +#endif } bool GpuChannel::OnMessageReceived(const IPC::Message& message) { @@ -65,6 +67,10 @@ void GpuChannel::OnChannelError() { gpu_thread_->RemoveChannel(renderer_id_); } +void GpuChannel::OnChannelConnected(int32 peer_pid) { + renderer_pid_ = peer_pid; +} + bool GpuChannel::Send(IPC::Message* message) { if (log_messages_) { VLOG(1) << "sending message @" << message << " on channel @" << this @@ -122,6 +128,7 @@ bool GpuChannel::IsRenderViewGone(int32 renderer_route_id) { bool GpuChannel::OnControlMessageReceived(const IPC::Message& msg) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(GpuChannel, msg) + IPC_MESSAGE_HANDLER(GpuChannelMsg_Initialize, OnInitialize) IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateOffscreenCommandBuffer, OnCreateOffscreenCommandBuffer) IPC_MESSAGE_HANDLER(GpuChannelMsg_DestroyCommandBuffer, @@ -141,6 +148,15 @@ int GpuChannel::GenerateRouteID() { return ++last_id; } +void GpuChannel::OnInitialize(base::ProcessHandle renderer_process) { + // Initialize should only happen once. + DCHECK(!renderer_process_); + + // Verify that the renderer has passed its own process handle. + if (base::GetProcId(renderer_process) == renderer_pid_) + renderer_process_ = renderer_process; +} + void GpuChannel::OnCreateOffscreenCommandBuffer( int32 parent_route_id, const gfx::Size& size, diff --git a/chrome/gpu/gpu_channel.h b/chrome/gpu/gpu_channel.h index 947dbfd..a3cb341 100644 --- a/chrome/gpu/gpu_channel.h +++ b/chrome/gpu/gpu_channel.h @@ -11,7 +11,7 @@ #include <vector> #include "base/id_map.h" -#include "base/scoped_open_process.h" +#include "base/process.h" #include "base/scoped_ptr.h" #include "build/build_config.h" #include "chrome/common/gpu_create_command_buffer_config.h" @@ -32,7 +32,9 @@ class GpuChannel : public IPC::Channel::Listener, public IPC::Message::Sender, public base::RefCountedThreadSafe<GpuChannel> { public: - GpuChannel(GpuThread* gpu_thread, int renderer_id); + // Takes ownership of the renderer process handle. + GpuChannel(GpuThread* gpu_thread, + int renderer_id); virtual ~GpuChannel(); bool Init(); @@ -47,14 +49,14 @@ class GpuChannel : public IPC::Channel::Listener, int GetRendererFileDescriptor(); #endif // defined(OS_POSIX) - base::ProcessHandle renderer_handle() const { - return renderer_process_.handle(); + base::ProcessHandle renderer_process() const { + return renderer_process_; } // IPC::Channel::Listener implementation: virtual bool OnMessageReceived(const IPC::Message& msg); - virtual void OnChannelConnected(int32 peer_pid); virtual void OnChannelError(); + virtual void OnChannelConnected(int32 peer_pid); // IPC::Message::Sender implementation: virtual bool Send(IPC::Message* msg); @@ -79,6 +81,7 @@ class GpuChannel : public IPC::Channel::Listener, int GenerateRouteID(); // Message handlers. + void OnInitialize(base::ProcessHandle renderer_process); void OnCreateOffscreenCommandBuffer( int32 parent_route_id, const gfx::Size& size, @@ -98,12 +101,15 @@ class GpuChannel : public IPC::Channel::Listener, scoped_ptr<IPC::SyncChannel> channel_; - // Handle to the renderer process who is on the other side of the channel. - base::ScopedOpenProcess renderer_process_; - // The id of the renderer who is on the other side of the channel. int renderer_id_; + // Handle to the renderer process that is on the other side of the channel. + base::ProcessHandle renderer_process_; + + // The process id of the renderer process. + base::ProcessId renderer_pid_; + // Used to implement message routing functionality to CommandBuffer objects MessageRouter router_; diff --git a/chrome/gpu/gpu_command_buffer_stub.cc b/chrome/gpu/gpu_command_buffer_stub.cc index 7808d3b..5c369eb 100644 --- a/chrome/gpu/gpu_command_buffer_stub.cc +++ b/chrome/gpu/gpu_command_buffer_stub.cc @@ -170,6 +170,8 @@ bool GpuCommandBufferStub::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_AsyncFlush, OnAsyncFlush); IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_CreateTransferBuffer, OnCreateTransferBuffer); + IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_RegisterTransferBuffer, + OnRegisterTransferBuffer); IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_DestroyTransferBuffer, OnDestroyTransferBuffer); IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_GetTransferBuffer, @@ -235,7 +237,7 @@ void GpuCommandBufferStub::OnInitialize( // Assume service is responsible for duplicating the handle from the // calling process. - buffer.shared_memory->ShareToProcess(channel_->renderer_handle(), + buffer.shared_memory->ShareToProcess(channel_->renderer_process(), ring_buffer); #if defined(OS_MACOSX) if (handle_) { @@ -289,6 +291,20 @@ void GpuCommandBufferStub::OnCreateTransferBuffer(int32 size, int32* id) { *id = command_buffer_->CreateTransferBuffer(size); } +void GpuCommandBufferStub::OnRegisterTransferBuffer( + base::SharedMemoryHandle transfer_buffer, + size_t size, + int32* id) { +#if defined(OS_WIN) + base::SharedMemory shared_memory(transfer_buffer, + false, + channel_->renderer_process()); +#else + base::SharedMemory shared_memory(transfer_buffer, false); +#endif + *id = command_buffer_->RegisterTransferBuffer(&shared_memory, size); +} + void GpuCommandBufferStub::OnDestroyTransferBuffer(int32 id) { command_buffer_->DestroyTransferBuffer(id); } @@ -300,13 +316,17 @@ void GpuCommandBufferStub::OnGetTransferBuffer( *transfer_buffer = base::SharedMemoryHandle(); *size = 0; + // Fail if the renderer process has not provided its process handle. + if (!channel_->renderer_process()) + return; + Buffer buffer = command_buffer_->GetTransferBuffer(id); if (buffer.shared_memory) { // Assume service is responsible for duplicating the handle to the calling // process. - buffer.shared_memory->ShareToProcess(channel_->renderer_handle(), + buffer.shared_memory->ShareToProcess(channel_->renderer_process(), transfer_buffer); - *size = buffer.shared_memory->created_size(); + *size = buffer.size; } } diff --git a/chrome/gpu/gpu_command_buffer_stub.h b/chrome/gpu/gpu_command_buffer_stub.h index da990b8..2382410 100644 --- a/chrome/gpu/gpu_command_buffer_stub.h +++ b/chrome/gpu/gpu_command_buffer_stub.h @@ -74,6 +74,9 @@ class GpuCommandBufferStub void OnFlush(int32 put_offset, gpu::CommandBuffer::State* state); void OnAsyncFlush(int32 put_offset); void OnCreateTransferBuffer(int32 size, int32* id); + void OnRegisterTransferBuffer(base::SharedMemoryHandle transfer_buffer, + size_t size, + int32* id); void OnDestroyTransferBuffer(int32 id); void OnGetTransferBuffer(int32 id, base::SharedMemoryHandle* transfer_buffer, diff --git a/chrome/gpu/gpu_video_service.cc b/chrome/gpu/gpu_video_service.cc index fb76e02..4221348 100644 --- a/chrome/gpu/gpu_video_service.cc +++ b/chrome/gpu/gpu_video_service.cc @@ -63,7 +63,7 @@ bool GpuVideoService::CreateVideoDecoder( decoder_info.decoder = new GpuVideoDecoder(MessageLoop::current(), decoder_host_id, channel, - channel->renderer_handle(), + channel->renderer_process(), gles2_decoder); decoder_info.channel = channel; decoder_map_[decoder_id] = decoder_info; diff --git a/chrome/renderer/command_buffer_proxy.cc b/chrome/renderer/command_buffer_proxy.cc index 57e5ddf..1fa3532 100644 --- a/chrome/renderer/command_buffer_proxy.cc +++ b/chrome/renderer/command_buffer_proxy.cc @@ -8,8 +8,10 @@ #include "base/task.h" #include "chrome/common/gpu_messages.h" #include "chrome/common/plugin_messages.h" +#include "chrome/common/render_messages.h" #include "chrome/renderer/command_buffer_proxy.h" #include "chrome/renderer/plugin_channel_host.h" +#include "chrome/renderer/render_thread.h" #include "gpu/command_buffer/common/cmd_buffer_common.h" #include "ui/gfx/size.h" @@ -123,30 +125,64 @@ void CommandBufferProxy::SetGetOffset(int32 get_offset) { } int32 CommandBufferProxy::CreateTransferBuffer(size_t size) { - if (last_state_.error == gpu::error::kNoError) { - int32 id; - if (Send(new GpuCommandBufferMsg_CreateTransferBuffer(route_id_, - size, - &id))) { - return id; - } + if (last_state_.error != gpu::error::kNoError) + return -1; + + RenderThread* render_thread = RenderThread::current(); + if (!render_thread) + return -1; + + base::SharedMemoryHandle handle; + if (!render_thread->Send(new ViewHostMsg_AllocateSharedMemoryBuffer( + size, + &handle))) { + return -1; + } + + // Take ownership of shared memory. This will close the handle if Send below + // fails. Otherwise, callee takes ownership before this variable + // goes out of scope by duping the handle. + base::SharedMemory shared_memory(handle, false); + + int32 id; + if (!Send(new GpuCommandBufferMsg_RegisterTransferBuffer(route_id_, + handle, + size, + &id))) { + return -1; + } + + return id; +} + +int32 CommandBufferProxy::RegisterTransferBuffer( + base::SharedMemory* shared_memory, + size_t size) { + if (last_state_.error != gpu::error::kNoError) + return -1; + + int32 id; + if (!Send(new GpuCommandBufferMsg_RegisterTransferBuffer( + route_id_, + shared_memory->handle(), + size, + &id))) { + return -1; } - return -1; + return id; } void CommandBufferProxy::DestroyTransferBuffer(int32 id) { if (last_state_.error != gpu::error::kNoError) return; - // Remove the transfer buffer from the client side4 cache. + // Remove the transfer buffer from the client side cache. TransferBufferMap::iterator it = transfer_buffers_.find(id); - DCHECK(it != transfer_buffers_.end()); - - // Delete the shared memory object, closing the handle in this process. - delete it->second.shared_memory; - - transfer_buffers_.erase(it); + if (it != transfer_buffers_.end()) { + delete it->second.shared_memory; + transfer_buffers_.erase(it); + } Send(new GpuCommandBufferMsg_DestroyTransferBuffer(route_id_, id)); } diff --git a/chrome/renderer/command_buffer_proxy.h b/chrome/renderer/command_buffer_proxy.h index c49e34a..bf5edc6 100644 --- a/chrome/renderer/command_buffer_proxy.h +++ b/chrome/renderer/command_buffer_proxy.h @@ -51,6 +51,8 @@ class CommandBufferProxy : public gpu::CommandBuffer, virtual State FlushSync(int32 put_offset); virtual void SetGetOffset(int32 get_offset); virtual int32 CreateTransferBuffer(size_t size); + virtual int32 RegisterTransferBuffer(base::SharedMemory* shared_memory, + size_t size); virtual void DestroyTransferBuffer(int32 id); virtual gpu::Buffer GetTransferBuffer(int32 handle); virtual void SetToken(int32 token); diff --git a/chrome/renderer/gpu_channel_host.cc b/chrome/renderer/gpu_channel_host.cc index c4354e7..4e6c075 100644 --- a/chrome/renderer/gpu_channel_host.cc +++ b/chrome/renderer/gpu_channel_host.cc @@ -17,7 +17,9 @@ GpuChannelHost::GpuChannelHost() : state_(kUnconnected) { GpuChannelHost::~GpuChannelHost() { } -void GpuChannelHost::Connect(const IPC::ChannelHandle& channel_handle) { +void GpuChannelHost::Connect( + const IPC::ChannelHandle& channel_handle, + base::ProcessHandle renderer_process_for_gpu) { // Open a channel to the GPU process. channel_.reset(new IPC::SyncChannel( channel_handle, IPC::Channel::MODE_CLIENT, this, @@ -28,6 +30,10 @@ void GpuChannelHost::Connect(const IPC::ChannelHandle& channel_handle) { // and receives the hello message from the GPU process. The messages get // cached. state_ = kConnected; + + // Notify the GPU process of our process handle. This gives it the ability + // to map renderer handles into the GPU process. + Send(new GpuChannelMsg_Initialize(renderer_process_for_gpu)); } void GpuChannelHost::set_gpu_info(const GPUInfo& gpu_info) { diff --git a/chrome/renderer/gpu_channel_host.h b/chrome/renderer/gpu_channel_host.h index 5648ecc..d086367 100644 --- a/chrome/renderer/gpu_channel_host.h +++ b/chrome/renderer/gpu_channel_host.h @@ -10,6 +10,7 @@ #include <vector> #include "base/hash_tables.h" +#include "base/process_util.h" #include "base/scoped_ptr.h" #include "chrome/common/gpu_info.h" #include "chrome/common/message_router.h" @@ -44,7 +45,8 @@ class GpuChannelHost : public IPC::Channel::Listener, ~GpuChannelHost(); // Connect to GPU process channel. - void Connect(const IPC::ChannelHandle& channel_handle); + void Connect(const IPC::ChannelHandle& channel_handle, + base::ProcessHandle renderer_process_for_gpu); State state() const { return state_; } diff --git a/chrome/renderer/mock_render_thread.cc b/chrome/renderer/mock_render_thread.cc index 846d2d8..f75d258 100644 --- a/chrome/renderer/mock_render_thread.cc +++ b/chrome/renderer/mock_render_thread.cc @@ -116,10 +116,8 @@ bool MockRenderThread::OnMessageReceived(const IPC::Message& msg) { #if defined(OS_WIN) IPC_MESSAGE_HANDLER(ViewHostMsg_DuplicateSection, OnDuplicateSection) #endif -#if defined(OS_POSIX) IPC_MESSAGE_HANDLER(ViewHostMsg_AllocateSharedMemoryBuffer, OnAllocateSharedMemoryBuffer) -#endif #if defined(OS_CHROMEOS) IPC_MESSAGE_HANDLER(ViewHostMsg_AllocateTempFileForPrinting, OnAllocateTempFileForPrinting) @@ -156,7 +154,6 @@ void MockRenderThread::OnDuplicateSection( } #endif -#if defined(OS_POSIX) void MockRenderThread::OnAllocateSharedMemoryBuffer( uint32 buffer_size, base::SharedMemoryHandle* handle) { base::SharedMemory shared_buf; @@ -167,7 +164,6 @@ void MockRenderThread::OnAllocateSharedMemoryBuffer( } shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), handle); } -#endif #if defined(OS_CHROMEOS) void MockRenderThread::OnAllocateTempFileForPrinting( diff --git a/chrome/renderer/mock_render_thread.h b/chrome/renderer/mock_render_thread.h index 0d8e313..1a62cf8 100644 --- a/chrome/renderer/mock_render_thread.h +++ b/chrome/renderer/mock_render_thread.h @@ -103,10 +103,8 @@ class MockRenderThread : public RenderThreadBase { base::SharedMemoryHandle* browser_handle); #endif -#if defined(OS_POSIX) void OnAllocateSharedMemoryBuffer(uint32 buffer_size, base::SharedMemoryHandle* handle); -#endif #if defined(OS_CHROMEOS) void OnAllocateTempFileForPrinting(base::FileDescriptor* renderer_fd, diff --git a/chrome/renderer/render_thread.cc b/chrome/renderer/render_thread.cc index 54e4694..49da6e2 100644 --- a/chrome/renderer/render_thread.cc +++ b/chrome/renderer/render_thread.cc @@ -1085,12 +1085,14 @@ void RenderThread::OnSetIsIncognitoProcess(bool is_incognito_process) { } void RenderThread::OnGpuChannelEstablished( - const IPC::ChannelHandle& channel_handle, const GPUInfo& gpu_info) { + const IPC::ChannelHandle& channel_handle, + base::ProcessHandle renderer_process_for_gpu, + const GPUInfo& gpu_info) { gpu_channel_->set_gpu_info(gpu_info); if (channel_handle.name.size() != 0) { // Connect to the GPU process if a channel name was received. - gpu_channel_->Connect(channel_handle); + gpu_channel_->Connect(channel_handle, renderer_process_for_gpu); } else { // Otherwise cancel the connection. gpu_channel_ = NULL; diff --git a/chrome/renderer/render_thread.h b/chrome/renderer/render_thread.h index 75ff7bb..d4bcbaf 100644 --- a/chrome/renderer/render_thread.h +++ b/chrome/renderer/render_thread.h @@ -317,6 +317,7 @@ class RenderThread : public RenderThreadBase, void OnSpellCheckEnableAutoSpellCorrect(bool enable); void OnGpuChannelEstablished(const IPC::ChannelHandle& channel_handle, + base::ProcessHandle renderer_process_for_gpu, const GPUInfo& gpu_info); void OnSetPhishingModel(IPC::PlatformFileForTransit model_file); diff --git a/content/browser/gpu_process_host.cc b/content/browser/gpu_process_host.cc index 4ef366a..6a4ee2d 100644 --- a/content/browser/gpu_process_host.cc +++ b/content/browser/gpu_process_host.cc @@ -2,6 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#if defined(OS_WIN) +#include <windows.h> +#endif + #include "content/browser/gpu_process_host.h" #include "app/app_switches.h" @@ -173,6 +177,31 @@ bool GpuProcessHost::CanShutdown() { return true; } +void GpuProcessHost::OnProcessLaunched() { + // Send the GPU process handle to the UI thread before it has to + // respond to any requests to establish a GPU channel. The response + // to such requests require that the GPU process handle be known. + base::ProcessHandle child_handle; +#if defined(OS_WIN) + DuplicateHandle(base::GetCurrentProcessHandle(), + handle(), + base::GetCurrentProcessHandle(), + &child_handle, + PROCESS_DUP_HANDLE, + FALSE, + 0); +#else + child_handle = handle(); +#endif + + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + NewRunnableFunction(&GpuProcessHostUIShim::NotifyGpuProcessLaunched, + host_id_, + child_handle)); +} + namespace { void SendOutstandingRepliesDispatcher(int host_id) { @@ -233,6 +262,9 @@ bool GpuProcessHost::LaunchGpuProcess() { if (!thread->StartWithOptions(options)) return false; + set_handle(base::GetCurrentProcessHandle()); + OnProcessLaunched(); + return true; } diff --git a/content/browser/gpu_process_host.h b/content/browser/gpu_process_host.h index 9881bee..69f5916 100644 --- a/content/browser/gpu_process_host.h +++ b/content/browser/gpu_process_host.h @@ -39,6 +39,7 @@ class GpuProcessHost : public BrowserChildProcessHost, void RouteOnUIThread(const IPC::Message& message); virtual bool CanShutdown(); + virtual void OnProcessLaunched(); virtual void OnChildDied(); virtual void OnProcessCrashed(int exit_code); diff --git a/content/browser/renderer_host/gpu_message_filter.cc b/content/browser/renderer_host/gpu_message_filter.cc index cbece30..c104f1d 100644 --- a/content/browser/renderer_host/gpu_message_filter.cc +++ b/content/browser/renderer_host/gpu_message_filter.cc @@ -2,6 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#if defined(OS_WIN) +#include <windows.h> +#endif + #include "chrome/browser/renderer_host/gpu_message_filter.h" #include "base/callback.h" @@ -53,7 +57,8 @@ void GpuMessageFilter::OnDestruct() const { namespace { class EstablishChannelCallback - : public CallbackRunner<Tuple2<const IPC::ChannelHandle&, + : public CallbackRunner<Tuple3<const IPC::ChannelHandle&, + base::ProcessHandle, const GPUInfo&> > { public: explicit EstablishChannelCallback(GpuMessageFilter* filter): @@ -66,17 +71,38 @@ class EstablishChannelCallback } void Send(const IPC::ChannelHandle& channel, + base::ProcessHandle gou_process_for_browser, const GPUInfo& gpu_info) { + if (!filter_) + return; + + base::ProcessHandle renderer_process_for_gpu; +#if defined(OS_WIN) + // Create a process handle that the renderer process can give to the GPU + // process to give it access to its handles. + DuplicateHandle(base::GetCurrentProcessHandle(), + filter_->peer_handle(), + gou_process_for_browser, + &renderer_process_for_gpu, + PROCESS_DUP_HANDLE, + FALSE, + 0); +#else + renderer_process_for_gpu = filter_->peer_handle(); +#endif + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); ViewMsg_GpuChannelEstablished* reply = - new ViewMsg_GpuChannelEstablished(channel, gpu_info); + new ViewMsg_GpuChannelEstablished(channel, + renderer_process_for_gpu, + gpu_info); + // If the renderer process is performing synchronous initialization, // it needs to handle this message before receiving the reply for // the synchronous GpuHostMsg_SynchronizeGpu message. reply->set_unblock(true); - if (filter_) - filter_->Send(reply); + filter_->Send(reply); } private: @@ -148,7 +174,9 @@ void GpuMessageFilter::OnEstablishGpuChannel() { if (!ui_shim) { ui_shim = GpuProcessHostUIShim::GetForRenderer(render_process_id_); if (!ui_shim) { - callback->Run(IPC::ChannelHandle(), GPUInfo()); + callback->Run(IPC::ChannelHandle(), + static_cast<base::ProcessHandle>(NULL), + GPUInfo()); return; } diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc index 4308e7a..6fefd70 100644 --- a/content/browser/renderer_host/render_message_filter.cc +++ b/content/browser/renderer_host/render_message_filter.cc @@ -446,10 +446,8 @@ bool RenderMessageFilter::OnMessageReceived(const IPC::Message& message, #if defined(OS_WIN) IPC_MESSAGE_HANDLER(ViewHostMsg_DuplicateSection, OnDuplicateSection) #endif -#if defined(OS_POSIX) IPC_MESSAGE_HANDLER(ViewHostMsg_AllocateSharedMemoryBuffer, OnAllocateSharedMemoryBuffer) -#endif #if defined(OS_CHROMEOS) IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_AllocateTempFileForPrinting, OnAllocateTempFileForPrinting) @@ -1000,7 +998,6 @@ void RenderMessageFilter::OnDuplicateSection( } #endif -#if defined(OS_POSIX) void RenderMessageFilter::OnAllocateSharedMemoryBuffer( uint32 buffer_size, base::SharedMemoryHandle* handle) { @@ -1010,9 +1007,8 @@ void RenderMessageFilter::OnAllocateSharedMemoryBuffer( NOTREACHED() << "Cannot map shared memory buffer"; return; } - shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), handle); + shared_buf.GiveToProcess(peer_handle(), handle); } -#endif void RenderMessageFilter::OnResourceTypeStats( const WebCache::ResourceTypeStats& stats) { diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h index b44a56c..4f16c62 100644 --- a/content/browser/renderer_host/render_message_filter.h +++ b/content/browser/renderer_host/render_message_filter.h @@ -229,13 +229,11 @@ class RenderMessageFilter : public BrowserMessageFilter, void OnTempFileForPrintingWritten(int sequence_number); #endif -#if defined(OS_POSIX) // Used to ask the browser to allocate a block of shared memory for the // renderer to send back data in, since shared memory can't be created // in the renderer on POSIX due to the sandbox. void OnAllocateSharedMemoryBuffer(uint32 buffer_size, base::SharedMemoryHandle* handle); -#endif void OnResourceTypeStats(const WebKit::WebCache::ResourceTypeStats& stats); static void OnResourceTypeStatsOnUIThread( diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc index aa187e0..dc088fd 100644 --- a/gpu/command_buffer/client/gles2_implementation_unittest.cc +++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc @@ -73,6 +73,12 @@ class GLES2MockCommandBufferHelper : public CommandBuffer { return transfer_buffer_buffer_; } + virtual int32 RegisterTransferBuffer(base::SharedMemory* shared_memory, + size_t size) { + GPU_NOTREACHED(); + return -1; + } + virtual void SetToken(int32 token) { GPU_NOTREACHED(); state_.token = token; diff --git a/gpu/command_buffer/common/command_buffer.h b/gpu/command_buffer/common/command_buffer.h index 963b228..b758333 100644 --- a/gpu/command_buffer/common/command_buffer.h +++ b/gpu/command_buffer/common/command_buffer.h @@ -80,6 +80,12 @@ class CommandBuffer { // identifies it or -1 on error. virtual int32 CreateTransferBuffer(size_t size) = 0; + // Register an existing shared memory object and get an ID that can be used + // to identify it in the command buffer. Callee dups the handle until + // DestroyTransferBuffer is called. + virtual int32 RegisterTransferBuffer(base::SharedMemory* shared_memory, + size_t size) = 0; + // Destroy a transfer buffer and recycle the handle. virtual void DestroyTransferBuffer(int32 id) = 0; diff --git a/gpu/command_buffer/common/command_buffer_mock.h b/gpu/command_buffer/common/command_buffer_mock.h index a633d24..99a72d3 100644 --- a/gpu/command_buffer/common/command_buffer_mock.h +++ b/gpu/command_buffer/common/command_buffer_mock.h @@ -8,6 +8,10 @@ #include "../common/command_buffer.h" #include "testing/gmock/include/gmock/gmock.h" +namespace base { +class SharedMemory; +} + namespace gpu { // An NPObject that implements a shared memory command buffer and a synchronous @@ -26,6 +30,8 @@ class MockCommandBuffer : public CommandBuffer { MOCK_METHOD1(CreateTransferBuffer, int32(size_t size)); MOCK_METHOD1(DestroyTransferBuffer, void(int32 handle)); MOCK_METHOD1(GetTransferBuffer, Buffer(int32 handle)); + MOCK_METHOD2(RegisterTransferBuffer, int32(base::SharedMemory* shared_memory, + size_t size)); MOCK_METHOD1(SetToken, void(int32 token)); MOCK_METHOD1(SetParseError, void(error::Error error)); diff --git a/gpu/command_buffer/service/command_buffer_service.cc b/gpu/command_buffer/service/command_buffer_service.cc index c2a85af..d806de1 100644 --- a/gpu/command_buffer/service/command_buffer_service.cc +++ b/gpu/command_buffer/service/command_buffer_service.cc @@ -7,6 +7,7 @@ #include <limits> #include "base/callback.h" +#include "base/process_util.h" #include "gpu/command_buffer/common/cmd_buffer_common.h" using ::base::SharedMemory; @@ -20,10 +21,14 @@ CommandBufferService::CommandBufferService() token_(0), error_(error::kNoError) { // Element zero is always NULL. - registered_objects_.push_back(linked_ptr<SharedMemory>()); + registered_objects_.push_back(Buffer()); } CommandBufferService::~CommandBufferService() { + for (size_t i = 0; i < registered_objects_.size(); ++i) { + if (registered_objects_[i].shared_memory) + delete registered_objects_[i].shared_memory; + } } bool CommandBufferService::Initialize(int32 size) { @@ -102,9 +107,26 @@ void CommandBufferService::SetGetOffset(int32 get_offset) { } int32 CommandBufferService::CreateTransferBuffer(size_t size) { - linked_ptr<SharedMemory> buffer(new SharedMemory); - if (!buffer->CreateAnonymous(size)) + SharedMemory buffer; + if (!buffer.CreateAnonymous(size)) + return -1; + + return RegisterTransferBuffer(&buffer, size); +} + +int32 CommandBufferService::RegisterTransferBuffer( + base::SharedMemory* shared_memory, size_t size) { + // Duplicate the handle. + base::SharedMemoryHandle shared_memory_handle; + if (!shared_memory->ShareToProcess(base::GetCurrentProcessHandle(), + &shared_memory_handle)) { return -1; + } + + Buffer buffer; + buffer.ptr = NULL; + buffer.size = size; + buffer.shared_memory = new SharedMemory(shared_memory_handle, false); if (unused_registered_object_elements_.empty()) { // Check we haven't exceeded the range that fits in a 32-bit integer. @@ -119,7 +141,7 @@ int32 CommandBufferService::CreateTransferBuffer(size_t size) { int32 handle = *unused_registered_object_elements_.begin(); unused_registered_object_elements_.erase( unused_registered_object_elements_.begin()); - DCHECK(!registered_objects_[handle].get()); + DCHECK(!registered_objects_[handle].shared_memory); registered_objects_[handle] = buffer; return handle; } @@ -131,13 +153,15 @@ void CommandBufferService::DestroyTransferBuffer(int32 handle) { if (static_cast<size_t>(handle) >= registered_objects_.size()) return; - registered_objects_[handle].reset(); + delete registered_objects_[handle].shared_memory; + registered_objects_[handle] = Buffer(); unused_registered_object_elements_.insert(handle); // Remove all null objects from the end of the vector. This allows the vector // to shrink when, for example, all objects are unregistered. Note that this // loop never removes element zero, which is always NULL. - while (registered_objects_.size() > 1 && !registered_objects_.back().get()) { + while (registered_objects_.size() > 1 && + !registered_objects_.back().shared_memory) { registered_objects_.pop_back(); unused_registered_object_elements_.erase( static_cast<int32>(registered_objects_.size())); @@ -151,19 +175,16 @@ Buffer CommandBufferService::GetTransferBuffer(int32 handle) { if (static_cast<size_t>(handle) >= registered_objects_.size()) return Buffer(); - base::SharedMemory* shared_memory = registered_objects_[handle].get(); - if (!shared_memory) - return Buffer(); + Buffer buffer = registered_objects_[handle]; + if (!buffer.shared_memory) + return Buffer(); - if (!shared_memory->memory()) { - if (!shared_memory->Map(shared_memory->created_size())) + if (!buffer.shared_memory->memory()) { + if (!buffer.shared_memory->Map(buffer.size)) return Buffer(); } - Buffer buffer; - buffer.ptr = shared_memory->memory(); - buffer.size = shared_memory->created_size(); - buffer.shared_memory = shared_memory; + buffer.ptr = buffer.shared_memory->memory(); return buffer; } diff --git a/gpu/command_buffer/service/command_buffer_service.h b/gpu/command_buffer/service/command_buffer_service.h index 94d77c3..9706008 100644 --- a/gpu/command_buffer/service/command_buffer_service.h +++ b/gpu/command_buffer/service/command_buffer_service.h @@ -32,6 +32,8 @@ class CommandBufferService : public CommandBuffer { virtual State FlushSync(int32 put_offset); virtual void SetGetOffset(int32 get_offset); virtual int32 CreateTransferBuffer(size_t size); + virtual int32 RegisterTransferBuffer(base::SharedMemory* shared_memory, + size_t size); virtual void DestroyTransferBuffer(int32 id); virtual Buffer GetTransferBuffer(int32 handle); virtual void SetToken(int32 token); @@ -55,7 +57,7 @@ class CommandBufferService : public CommandBuffer { int32 get_offset_; int32 put_offset_; scoped_ptr<Callback0::Type> put_offset_change_callback_; - std::vector<linked_ptr< base::SharedMemory> > registered_objects_; + std::vector<Buffer> registered_objects_; std::set<int32> unused_registered_object_elements_; int32 token_; error::Error error_; diff --git a/gpu/pgl/command_buffer_pepper.cc b/gpu/pgl/command_buffer_pepper.cc index db72474..e4b6ce8 100644 --- a/gpu/pgl/command_buffer_pepper.cc +++ b/gpu/pgl/command_buffer_pepper.cc @@ -142,6 +142,14 @@ int32 CommandBufferPepper::CreateTransferBuffer(size_t size) { return static_cast<int32>(id); } +int32 CommandBufferPepper::RegisterTransferBuffer( + base::SharedMemory* shared_memory, + size_t size) { + // Not implemented by proxy. + GPU_NOTREACHED(); + return -1; +} + void CommandBufferPepper::DestroyTransferBuffer(int32 id) { device_->destroyBuffer(npp_, context_, id); } diff --git a/gpu/pgl/command_buffer_pepper.h b/gpu/pgl/command_buffer_pepper.h index fe80625..902db36 100644 --- a/gpu/pgl/command_buffer_pepper.h +++ b/gpu/pgl/command_buffer_pepper.h @@ -35,6 +35,8 @@ class CommandBufferPepper : public gpu::CommandBuffer { virtual int32 CreateTransferBuffer(size_t size); virtual void DestroyTransferBuffer(int32 id); virtual gpu::Buffer GetTransferBuffer(int32 handle); + virtual int32 RegisterTransferBuffer(base::SharedMemory* shared_memory, + size_t size); virtual void SetToken(int32 token); virtual void SetParseError(gpu::error::Error error); diff --git a/ppapi/proxy/ppb_context_3d_proxy.cc b/ppapi/proxy/ppb_context_3d_proxy.cc index 076f133..d36ed2a 100644 --- a/ppapi/proxy/ppb_context_3d_proxy.cc +++ b/ppapi/proxy/ppb_context_3d_proxy.cc @@ -180,6 +180,8 @@ class PepperCommandBuffer : public gpu::CommandBuffer { virtual State FlushSync(int32 put_offset); virtual void SetGetOffset(int32 get_offset); virtual int32 CreateTransferBuffer(size_t size); + virtual int32 RegisterTransferBuffer(base::SharedMemory* shared_memory, + size_t size); virtual void DestroyTransferBuffer(int32 id); virtual gpu::Buffer GetTransferBuffer(int32 handle); virtual void SetToken(int32 token); @@ -303,6 +305,14 @@ int32 PepperCommandBuffer::CreateTransferBuffer(size_t size) { return -1; } +int32 PepperCommandBuffer::RegisterTransferBuffer( + base::SharedMemory* shared_memory, + size_t size) { + // Not implemented in proxy. + NOTREACHED(); + return -1; +} + void PepperCommandBuffer::DestroyTransferBuffer(int32 id) { if (last_state_.error != gpu::error::kNoError) return; |