blob: 2e2e7e78603fbe8c007f44c1866e3f2e64f3d7e2 [file] [log] [blame]
// 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