| // Copyright 2017 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 "media/capture/video/shared_memory_handle_provider.h" |
| |
| namespace media { |
| |
| SharedMemoryHandleProvider::SharedMemoryHandleProvider() { |
| #if DCHECK_IS_ON() |
| map_ref_count_ = 0; |
| #endif |
| } |
| |
| SharedMemoryHandleProvider::~SharedMemoryHandleProvider() { |
| base::AutoLock lock(mapping_lock_); |
| |
| // If the tracker is being destroyed, there must be no outstanding |
| // Handles. If this DCHECK() triggers, it means that either there is a logic |
| // flaw in VideoCaptureBufferPoolImpl, or a client did not delete all of its |
| // owned VideoCaptureBufferHandles before calling Pool::ReliquishXYZ(). |
| #if DCHECK_IS_ON() |
| DCHECK_EQ(map_ref_count_, 0); |
| #endif |
| |
| if (shared_memory_ && shared_memory_->memory()) { |
| DVLOG(3) << __func__ << ": Unmapping memory for in-process access @" |
| << shared_memory_->memory() << '.'; |
| CHECK(shared_memory_->Unmap()); |
| } |
| } |
| |
| bool SharedMemoryHandleProvider::InitForSize(size_t size) { |
| #if DCHECK_IS_ON() |
| DCHECK_EQ(map_ref_count_, 0); |
| #endif |
| DCHECK(!shared_memory_); |
| shared_memory_.emplace(); |
| if (shared_memory_->CreateAnonymous(size)) { |
| mapped_size_ = size; |
| read_only_flag_ = false; |
| return true; |
| } |
| return false; |
| } |
| |
| bool SharedMemoryHandleProvider::InitFromMojoHandle( |
| mojo::ScopedSharedBufferHandle buffer_handle) { |
| #if DCHECK_IS_ON() |
| DCHECK_EQ(map_ref_count_, 0); |
| #endif |
| DCHECK(!shared_memory_); |
| |
| base::SharedMemoryHandle memory_handle; |
| mojo::UnwrappedSharedMemoryHandleProtection protection; |
| const MojoResult result = mojo::UnwrapSharedMemoryHandle( |
| std::move(buffer_handle), &memory_handle, &mapped_size_, &protection); |
| if (result != MOJO_RESULT_OK) |
| return false; |
| read_only_flag_ = |
| protection == mojo::UnwrappedSharedMemoryHandleProtection::kReadOnly; |
| shared_memory_.emplace(memory_handle, read_only_flag_); |
| return true; |
| } |
| |
| #if defined(OS_LINUX) |
| bool SharedMemoryHandleProvider::InitAsReadOnlyFromRawFileDescriptor( |
| mojo::ScopedHandle fd_handle, |
| uint32_t memory_size_in_bytes) { |
| base::PlatformFile platform_file; |
| const MojoResult result = |
| mojo::UnwrapPlatformFile(std::move(fd_handle), &platform_file); |
| if (result != MOJO_RESULT_OK) |
| return false; |
| base::UnguessableToken guid = base::UnguessableToken::Create(); |
| base::SharedMemoryHandle memory_handle( |
| base::FileDescriptor(platform_file, true), 0u, guid); |
| mapped_size_ = memory_size_in_bytes; |
| read_only_flag_ = true; |
| shared_memory_.emplace(memory_handle, read_only_flag_); |
| return true; |
| } |
| #endif // defined(OS_LINUX) |
| |
| mojo::ScopedSharedBufferHandle |
| SharedMemoryHandleProvider::GetHandleForInterProcessTransit(bool read_only) { |
| if (read_only_flag_ && !read_only) { |
| // Wanted read-write access, but read-only access is all that is available. |
| NOTREACHED(); |
| return mojo::ScopedSharedBufferHandle(); |
| } |
| // TODO(https://crbug.com/803136): This does not actually obey |read_only| in |
| // any capacity because it uses DuplicateHandle. In order to properly obey |
| // |read_only| (when true), we need to use |SharedMemory::GetReadOnlyHandle()| |
| // but that is not possible. With the base::SharedMemory API and this |
| // SharedMemoryHandleProvider API as they are today, it isn't possible to know |
| // whether |shared_memory_| even supports read-only duplication. Note that |
| // changing |kReadWrite| to |kReadOnly| does NOT affect the ability to map |
| // the handle read-write. |
| return mojo::WrapSharedMemoryHandle( |
| base::SharedMemory::DuplicateHandle(shared_memory_->handle()), |
| mapped_size_, mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite); |
| } |
| |
| base::SharedMemoryHandle |
| SharedMemoryHandleProvider::GetNonOwnedSharedMemoryHandleForLegacyIPC() { |
| return shared_memory_->handle(); |
| } |
| |
| uint32_t SharedMemoryHandleProvider::GetMemorySizeInBytes() { |
| return static_cast<uint32_t>(mapped_size_); |
| } |
| |
| std::unique_ptr<VideoCaptureBufferHandle> |
| SharedMemoryHandleProvider::GetHandleForInProcessAccess() { |
| { |
| base::AutoLock lock(mapping_lock_); |
| #if DCHECK_IS_ON() |
| DCHECK_GE(map_ref_count_, 0); |
| ++map_ref_count_; |
| #endif |
| if (!shared_memory_->memory()) { |
| CHECK(shared_memory_->Map(mapped_size_)); |
| DVLOG(3) << __func__ << ": Mapped memory for in-process access @" |
| << shared_memory_->memory() << '.'; |
| } |
| } |
| |
| return std::make_unique<Handle>(this); |
| } |
| |
| #if DCHECK_IS_ON() |
| void SharedMemoryHandleProvider::OnHandleDestroyed() { |
| base::AutoLock lock(mapping_lock_); |
| DCHECK_GT(map_ref_count_, 0); |
| --map_ref_count_; |
| } |
| #endif |
| |
| SharedMemoryHandleProvider::Handle::Handle(SharedMemoryHandleProvider* owner) |
| : owner_(owner) {} |
| |
| SharedMemoryHandleProvider::Handle::~Handle() { |
| #if DCHECK_IS_ON() |
| owner_->OnHandleDestroyed(); |
| #endif |
| } |
| |
| size_t SharedMemoryHandleProvider::Handle::mapped_size() const { |
| return owner_->mapped_size_; |
| } |
| |
| uint8_t* SharedMemoryHandleProvider::Handle::data() const { |
| return static_cast<uint8_t*>(owner_->shared_memory_->memory()); |
| } |
| |
| const uint8_t* SharedMemoryHandleProvider::Handle::const_data() const { |
| return static_cast<const uint8_t*>(owner_->shared_memory_->memory()); |
| } |
| |
| } // namespace media |