| // Copyright 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 "components/viz/service/display_embedder/server_shared_bitmap_manager.h" |
| |
| #include <stdint.h> |
| |
| #include <utility> |
| |
| #include "base/lazy_instance.h" |
| #include "base/macros.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/stl_util.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/trace_event/process_memory_dump.h" |
| #include "components/viz/common/resources/resource_sizes.h" |
| #include "mojo/public/cpp/system/platform_handle.h" |
| #include "ui/gfx/geometry/size.h" |
| |
| namespace viz { |
| |
| class BitmapData : public base::RefCounted<BitmapData> { |
| public: |
| explicit BitmapData(size_t buffer_size) : buffer_size(buffer_size) {} |
| std::unique_ptr<base::SharedMemory> memory; |
| size_t buffer_size; |
| |
| private: |
| friend class base::RefCounted<BitmapData>; |
| ~BitmapData() {} |
| DISALLOW_COPY_AND_ASSIGN(BitmapData); |
| }; |
| |
| namespace { |
| |
| // Holds a reference on the BitmapData so that the SharedMemory can outlive the |
| // SharedBitmapId registration as long as this SharedBitmap object is held |
| // alive. |
| class ServerSharedBitmap : public SharedBitmap { |
| public: |
| explicit ServerSharedBitmap(scoped_refptr<BitmapData> bitmap_data) |
| : SharedBitmap(static_cast<uint8_t*>(bitmap_data->memory->memory())), |
| bitmap_data_(std::move(bitmap_data)) {} |
| |
| ~ServerSharedBitmap() override { |
| } |
| |
| private: |
| scoped_refptr<BitmapData> bitmap_data_; |
| }; |
| |
| } // namespace |
| |
| ServerSharedBitmapManager::ServerSharedBitmapManager() = default; |
| |
| ServerSharedBitmapManager::~ServerSharedBitmapManager() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| DCHECK(handle_map_.empty()); |
| } |
| |
| std::unique_ptr<SharedBitmap> ServerSharedBitmapManager::GetSharedBitmapFromId( |
| const gfx::Size& size, |
| ResourceFormat format, |
| const SharedBitmapId& id) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| |
| auto it = handle_map_.find(id); |
| if (it == handle_map_.end()) |
| return nullptr; |
| |
| BitmapData* data = it->second.get(); |
| |
| size_t bitmap_size; |
| if (!ResourceSizes::MaybeSizeInBytes(size, format, &bitmap_size) || |
| bitmap_size > data->buffer_size) |
| return nullptr; |
| |
| if (!data->memory->memory()) { |
| return nullptr; |
| } |
| |
| return std::make_unique<ServerSharedBitmap>(data); |
| } |
| |
| base::UnguessableToken |
| ServerSharedBitmapManager::GetSharedBitmapTracingGUIDFromId( |
| const SharedBitmapId& id) { |
| auto it = handle_map_.find(id); |
| if (it == handle_map_.end()) |
| return {}; |
| BitmapData* data = it->second.get(); |
| return data->memory->mapped_id(); |
| } |
| |
| bool ServerSharedBitmapManager::ChildAllocatedSharedBitmap( |
| mojo::ScopedSharedBufferHandle buffer, |
| const SharedBitmapId& id) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| |
| // Duplicate ids are not allowed. |
| if (base::ContainsKey(handle_map_, id)) |
| return false; |
| |
| base::SharedMemoryHandle memory_handle; |
| size_t buffer_size; |
| MojoResult result = mojo::UnwrapSharedMemoryHandle( |
| std::move(buffer), &memory_handle, &buffer_size, nullptr); |
| |
| // This function handles public API requests, so verify we unwrapped a shared |
| // memory handle before trying to use the handle. |
| if (result != MOJO_RESULT_OK) |
| return false; |
| |
| auto data = base::MakeRefCounted<BitmapData>(buffer_size); |
| data->memory = std::make_unique<base::SharedMemory>(memory_handle, false); |
| // Map the memory to get a pointer to it, then close it to free up the fd so |
| // it can be reused. This doesn't unmap the memory. Some OS have a very |
| // limited number of fds and this avoids consuming them all. |
| data->memory->Map(data->buffer_size); |
| data->memory->Close(); |
| |
| handle_map_[id] = std::move(data); |
| return true; |
| } |
| |
| void ServerSharedBitmapManager::ChildDeletedSharedBitmap( |
| const SharedBitmapId& id) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| handle_map_.erase(id); |
| } |
| |
| bool ServerSharedBitmapManager::OnMemoryDump( |
| const base::trace_event::MemoryDumpArgs& args, |
| base::trace_event::ProcessMemoryDump* pmd) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| |
| for (const auto& pair : handle_map_) { |
| const SharedBitmapId& id = pair.first; |
| BitmapData* data = pair.second.get(); |
| |
| std::string dump_str = base::StringPrintf( |
| "sharedbitmap/%s", base::HexEncode(id.name, sizeof(id.name)).c_str()); |
| base::trace_event::MemoryAllocatorDump* dump = |
| pmd->CreateAllocatorDump(dump_str); |
| if (!dump) |
| return false; |
| |
| dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, |
| base::trace_event::MemoryAllocatorDump::kUnitsBytes, |
| data->buffer_size); |
| |
| // This GUID is the same returned by GetSharedBitmapTracingGUIDFromId() so |
| // other components use a consistent GUID for a given SharedBitmapId. |
| base::UnguessableToken shared_memory_guid = data->memory->mapped_id(); |
| DCHECK(!shared_memory_guid.is_empty()); |
| pmd->CreateSharedMemoryOwnershipEdge(dump->guid(), shared_memory_guid, |
| 0 /* importance*/); |
| } |
| |
| return true; |
| } |
| |
| } // namespace viz |