// Copyright (c) 2013 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 "content/child/child_shared_bitmap_manager.h" #include "base/debug/alias.h" #include "base/process/process_metrics.h" #include "content/child/child_thread.h" #include "content/common/child_process_messages.h" #include "ui/gfx/geometry/size.h" namespace content { namespace { class ChildSharedBitmap : public SharedMemoryBitmap { public: ChildSharedBitmap(scoped_refptr sender, base::SharedMemory* shared_memory, const cc::SharedBitmapId& id) : SharedMemoryBitmap(static_cast(shared_memory->memory()), id, shared_memory), sender_(sender) {} ChildSharedBitmap(scoped_refptr sender, scoped_ptr shared_memory_holder, const cc::SharedBitmapId& id) : ChildSharedBitmap(sender, shared_memory_holder.get(), id) { shared_memory_holder_ = shared_memory_holder.Pass(); } ~ChildSharedBitmap() override { sender_->Send(new ChildProcessHostMsg_DeletedSharedBitmap(id())); } private: scoped_refptr sender_; scoped_ptr shared_memory_holder_; }; #if defined(OS_WIN) // Collect extra information for debugging bitmap creation failures. void CollectMemoryUsageAndDie(const gfx::Size& size) { int width = size.width(); int height = size.height(); DWORD last_error = GetLastError(); scoped_ptr metrics( base::ProcessMetrics::CreateProcessMetrics( base::GetCurrentProcessHandle())); size_t private_bytes = 0; size_t shared_bytes = 0; metrics->GetMemoryBytes(&private_bytes, &shared_bytes); base::debug::Alias(&width); base::debug::Alias(&height); base::debug::Alias(&last_error); base::debug::Alias(&private_bytes); base::debug::Alias(&shared_bytes); CHECK(false); } #endif } // namespace SharedMemoryBitmap::SharedMemoryBitmap(uint8* pixels, const cc::SharedBitmapId& id, base::SharedMemory* shared_memory) : SharedBitmap(pixels, id), shared_memory_(shared_memory) { } ChildSharedBitmapManager::ChildSharedBitmapManager( scoped_refptr sender) : sender_(sender) { } ChildSharedBitmapManager::~ChildSharedBitmapManager() {} scoped_ptr ChildSharedBitmapManager::AllocateSharedBitmap( const gfx::Size& size) { scoped_ptr bitmap = AllocateSharedMemoryBitmap(size); #if defined(OS_POSIX) // Close file descriptor to avoid running out. if (bitmap) bitmap->shared_memory()->Close(); #endif return bitmap.Pass(); } scoped_ptr ChildSharedBitmapManager::AllocateSharedMemoryBitmap(const gfx::Size& size) { TRACE_EVENT2("renderer", "ChildSharedBitmapManager::AllocateSharedMemoryBitmap", "width", size.width(), "height", size.height()); size_t memory_size; if (!cc::SharedBitmap::SizeInBytes(size, &memory_size)) return scoped_ptr(); cc::SharedBitmapId id = cc::SharedBitmap::GenerateId(); scoped_ptr memory; #if defined(OS_POSIX) base::SharedMemoryHandle handle; sender_->Send(new ChildProcessHostMsg_SyncAllocateSharedBitmap( memory_size, id, &handle)); memory = make_scoped_ptr(new base::SharedMemory(handle, false)); if (!memory->Map(memory_size)) CHECK(false); #else memory = ChildThread::AllocateSharedMemory(memory_size, sender_.get()); #if defined(OS_WIN) if (!memory) CollectMemoryUsageAndDie(size); #endif CHECK(memory); if (!memory->Map(memory_size)) { #if defined(OS_WIN) CollectMemoryUsageAndDie(size); #endif CHECK(false); } base::SharedMemoryHandle handle_to_send = memory->handle(); sender_->Send(new ChildProcessHostMsg_AllocatedSharedBitmap( memory_size, handle_to_send, id)); #endif return make_scoped_ptr(new ChildSharedBitmap(sender_, memory.Pass(), id)); } scoped_ptr ChildSharedBitmapManager::GetSharedBitmapFromId( const gfx::Size&, const cc::SharedBitmapId&) { NOTREACHED(); return scoped_ptr(); } scoped_ptr ChildSharedBitmapManager::GetBitmapForSharedMemory( base::SharedMemory* mem) { cc::SharedBitmapId id = cc::SharedBitmap::GenerateId(); base::SharedMemoryHandle handle_to_send = mem->handle(); #if defined(OS_POSIX) if (!mem->ShareToProcess(base::GetCurrentProcessHandle(), &handle_to_send)) return scoped_ptr(); #endif sender_->Send(new ChildProcessHostMsg_AllocatedSharedBitmap( mem->mapped_size(), handle_to_send, id)); return make_scoped_ptr(new ChildSharedBitmap(sender_, mem, id)); } } // namespace content