Commit 097248f0 authored by Ken Rockot's avatar Ken Rockot Committed by Commit Bot

Base [android]: Introduce ScopedHardwareBufferHandle

This is a scoping wrapper around an owned AHardwareBuffer reference.

Removes code in SharedMemory/SharedMemoryHandle to serve the same
purpose, such that shared memory objects on Android are now always
actually ashmem objects.

Updates GpuMemoryBufferHandle and
GpuMemoryBufferImplAndroidHardwareBuffer (the only existing use of the
special not-really-shared-memory type) to use a raw AHarwdwareBuffer*
(unowned) or ScopedHardwareBufferHandle (owned) instead.

Also fixes a bug in MailboxToSurfaceBridge which was stealing an
a AHardwareBuffer ref from its caller.

Bug: 826213
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: I9e8403ad9e120cc9c68012dd537a0bc4af9a513c
Reviewed-on: https://chromium-review.googlesource.com/1014541
Commit-Queue: Ken Rockot <rockot@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarDavid Reveman <reveman@chromium.org>
Reviewed-by: default avatarKlaus Weidner <klausw@chromium.org>
Cr-Commit-Position: refs/heads/master@{#552723}
parent 5ae6948a
......@@ -209,6 +209,8 @@ jumbo_component("base") {
"android/path_utils.h",
"android/record_histogram.cc",
"android/record_user_action.cc",
"android/scoped_hardware_buffer_handle.cc",
"android/scoped_hardware_buffer_handle.h",
"android/scoped_java_ref.cc",
"android/scoped_java_ref.h",
"android/statistics_recorder_android.cc",
......
// Copyright 2018 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 "base/android/scoped_hardware_buffer_handle.h"
#include "base/android/android_hardware_buffer_compat.h"
#include "base/logging.h"
#include "base/posix/unix_domain_socket.h"
namespace base {
namespace android {
ScopedHardwareBufferHandle::ScopedHardwareBufferHandle() = default;
ScopedHardwareBufferHandle::ScopedHardwareBufferHandle(
ScopedHardwareBufferHandle&& other) {
*this = std::move(other);
}
ScopedHardwareBufferHandle::~ScopedHardwareBufferHandle() {
reset();
}
// static
ScopedHardwareBufferHandle ScopedHardwareBufferHandle::Adopt(
AHardwareBuffer* buffer) {
return ScopedHardwareBufferHandle(buffer);
}
ScopedHardwareBufferHandle& ScopedHardwareBufferHandle::operator=(
ScopedHardwareBufferHandle&& other) {
reset();
std::swap(buffer_, other.buffer_);
return *this;
}
bool ScopedHardwareBufferHandle::is_valid() const {
return buffer_ != nullptr;
}
AHardwareBuffer* ScopedHardwareBufferHandle::get() const {
return buffer_;
}
void ScopedHardwareBufferHandle::reset() {
if (buffer_) {
AndroidHardwareBufferCompat::GetInstance().Release(buffer_);
buffer_ = nullptr;
}
}
AHardwareBuffer* ScopedHardwareBufferHandle::Take() {
AHardwareBuffer* buffer = nullptr;
std::swap(buffer, buffer_);
return buffer;
}
ScopedHardwareBufferHandle ScopedHardwareBufferHandle::Clone() const {
DCHECK(buffer_);
AndroidHardwareBufferCompat::GetInstance().Acquire(buffer_);
return ScopedHardwareBufferHandle(buffer_);
}
ScopedFD ScopedHardwareBufferHandle::SerializeAsFileDescriptor() const {
DCHECK(is_valid());
ScopedFD reader, writer;
if (!CreateSocketPair(&reader, &writer)) {
PLOG(ERROR) << "socketpair";
return ScopedFD();
}
// NOTE: SendHandleToUnixSocket does NOT acquire or retain a reference to the
// buffer object. The caller is therefore responsible for ensuring that the
// buffer remains alive through the lifetime of this file descriptor.
int result =
AndroidHardwareBufferCompat::GetInstance().SendHandleToUnixSocket(
buffer_, writer.get());
if (result < 0) {
PLOG(ERROR) << "send";
return ScopedFD();
}
return reader;
}
// static
ScopedHardwareBufferHandle
ScopedHardwareBufferHandle::DeserializeFromFileDescriptor(ScopedFD fd) {
DCHECK(fd.is_valid());
DCHECK(AndroidHardwareBufferCompat::IsSupportAvailable());
AHardwareBuffer* buffer = nullptr;
// NOTE: Upon success, RecvHandleFromUnixSocket acquires a new reference to
// the AHardwareBuffer.
int result =
AndroidHardwareBufferCompat::GetInstance().RecvHandleFromUnixSocket(
fd.get(), &buffer);
if (result < 0) {
PLOG(ERROR) << "recv";
return ScopedHardwareBufferHandle();
}
return ScopedHardwareBufferHandle(buffer);
}
ScopedHardwareBufferHandle::ScopedHardwareBufferHandle(AHardwareBuffer* buffer)
: buffer_(buffer) {
DCHECK(AndroidHardwareBufferCompat::IsSupportAvailable());
}
} // namespace android
} // namespace base
// Copyright 2018 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.
#ifndef BASE_ANDROID_SCOPED_HARDWARE_BUFFER_HANDLE_H_
#define BASE_ANDROID_SCOPED_HARDWARE_BUFFER_HANDLE_H_
#include "base/base_export.h"
#include "base/files/scoped_file.h"
#include "base/macros.h"
extern "C" typedef struct AHardwareBuffer AHardwareBuffer;
namespace base {
namespace android {
// Owns a single reference to an AHardwareBuffer object.
class BASE_EXPORT ScopedHardwareBufferHandle {
public:
ScopedHardwareBufferHandle();
// Takes ownership of |other|'s buffer reference. Does NOT acquire a new one.
ScopedHardwareBufferHandle(ScopedHardwareBufferHandle&& other);
// Releases this handle's reference to the underlying buffer object if still
// valid.
~ScopedHardwareBufferHandle();
// Assumes ownership of an existing reference to |buffer|. This does NOT
// acquire a new reference.
static ScopedHardwareBufferHandle Adopt(AHardwareBuffer* buffer);
// Takes ownership of |other|'s buffer reference. Does NOT acquire a new one.
ScopedHardwareBufferHandle& operator=(ScopedHardwareBufferHandle&& other);
bool is_valid() const;
AHardwareBuffer* get() const;
// Releases this handle's reference to the underlying buffer object if still
// valid. Invalidates this handle.
void reset();
// Passes implicit ownership of this handle's reference over to the caller,
// invalidating |this|. Returns the raw buffer handle.
//
// The caller is responsible for eventually releasing this reference to the
// buffer object.
AHardwareBuffer* Take() WARN_UNUSED_RESULT;
// Creates a new handle with its own newly acquired reference to the
// underlying buffer object. |this| must be a valid handle.
ScopedHardwareBufferHandle Clone() const;
// Consumes a handle and returns a file descriptor which can be used to
// transmit the handle over IPC. A subsequent receiver may use
// |DeserializeFromFileDescriptor()| to recover the buffer handle.
//
// NOTE: The returned file descriptor DOES NOT own a reference to the
// underlying AHardwareBuffer. When using this for IPC, the caller is
// responsible for retaining at least one reference to the buffer object to
// keep it alive while the descriptor is in transit.
ScopedFD SerializeAsFileDescriptor() const;
// Consumes the supplied single-use file descriptor (which must have been
// returned by a previous call to |SerializeAsFileDescriptor()|, perhaps in
// a different process), and recovers an AHardwareBuffer object from it.
//
// This acquires a new reference to the AHardwareBuffer, with ownership passed
// to the caller via the returned ScopedHardwareBufferHandle.
static ScopedHardwareBufferHandle DeserializeFromFileDescriptor(ScopedFD fd)
WARN_UNUSED_RESULT;
private:
// Assumes ownership of an existing reference to |buffer|. This does NOT
// acquire a new reference.
explicit ScopedHardwareBufferHandle(AHardwareBuffer* buffer);
AHardwareBuffer* buffer_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(ScopedHardwareBufferHandle);
};
} // namespace android
} // namespace base
#endif // BASE_ANDROID_SCOPED_HARDWARE_BUFFER_HANDLE_H_
......@@ -24,10 +24,6 @@
#include "base/file_descriptor_posix.h"
#endif
#if defined(OS_ANDROID)
extern "C" typedef struct AHardwareBuffer AHardwareBuffer;
#endif
namespace base {
// SharedMemoryHandle is the smallest possible IPC-transportable "reference" to
......@@ -149,32 +145,6 @@ class BASE_EXPORT SharedMemoryHandle {
#endif
#if defined(OS_ANDROID)
enum class Type {
// The SharedMemoryHandle is not backed by a handle. This is used for
// a default-constructed SharedMemoryHandle() or for a failed duplicate.
// The other types are assumed to be valid.
INVALID,
// The SharedMemoryHandle is backed by a valid fd for ashmem.
ASHMEM,
// The SharedMemoryHandle is backed by a valid AHardwareBuffer object.
ANDROID_HARDWARE_BUFFER,
LAST = ANDROID_HARDWARE_BUFFER
};
Type GetType() const { return type_; }
SharedMemoryHandle(AHardwareBuffer* buffer,
size_t size,
const base::UnguessableToken& guid);
// Constructs a handle from file descriptor and type. Both ASHMEM and
// AHardwareBuffer types are transported via file descriptor for IPC, so the
// type field is needed to distinguish them. The generic file descriptor
// constructor below assumes type ASHMEM.
SharedMemoryHandle(Type type,
const base::FileDescriptor& file_descriptor,
size_t size,
const base::UnguessableToken& guid);
AHardwareBuffer* GetMemoryObject() const;
// Marks the current file descriptor as read-only, for the purpose of
// mapping. This is independent of the region's read-only status.
void SetReadOnly() { read_only_ = true; }
......@@ -237,13 +207,7 @@ class BASE_EXPORT SharedMemoryHandle {
#elif defined(OS_ANDROID)
friend class SharedMemory;
// Each instance of a SharedMemoryHandle is either INVALID, or backed by an
// ashmem fd, or backed by an AHardwareBuffer. |type_| determines the backing
// member.
Type type_ = Type::INVALID;
FileDescriptor file_descriptor_;
AHardwareBuffer* memory_object_ = nullptr;
bool ownership_passes_to_ipc_ = false;
bool read_only_ = false;
#elif defined(OS_FUCHSIA)
zx_handle_t handle_ = ZX_HANDLE_INVALID;
......
......@@ -7,7 +7,6 @@
#include <sys/mman.h>
#include <unistd.h>
#include "base/android/android_hardware_buffer_compat.h"
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "base/posix/unix_domain_socket.h"
......@@ -25,77 +24,20 @@ static int GetAshmemRegionProtectionMask(int fd) {
return prot;
}
SharedMemoryHandle::SharedMemoryHandle() {}
SharedMemoryHandle::SharedMemoryHandle() = default;
SharedMemoryHandle::SharedMemoryHandle(
const base::FileDescriptor& file_descriptor,
size_t size,
const base::UnguessableToken& guid)
: SharedMemoryHandle(Type::ASHMEM, file_descriptor, size, guid) {}
SharedMemoryHandle::SharedMemoryHandle(
Type type,
const base::FileDescriptor& file_descriptor,
size_t size,
const base::UnguessableToken& guid)
: type_(type), guid_(guid), size_(size) {
switch (type) {
case Type::INVALID:
NOTREACHED() << "Can't create a Type::INVALID from a file descriptor";
break;
case Type::ASHMEM:
DCHECK_GE(file_descriptor.fd, 0);
file_descriptor_ = file_descriptor;
break;
case Type::ANDROID_HARDWARE_BUFFER:
// This may be the first use of AHardwareBuffers in this process, so we
// need to load symbols. This should not fail since we're supposedly
// receiving one from IPC, but better to be paranoid.
if (!AndroidHardwareBufferCompat::IsSupportAvailable()) {
NOTREACHED() << "AHardwareBuffer support not available";
type_ = Type::INVALID;
return;
}
AHardwareBuffer* ahb = nullptr;
// A successful receive increments refcount, we don't need to do so
// separately.
int ret =
AndroidHardwareBufferCompat::GetInstance().RecvHandleFromUnixSocket(
file_descriptor.fd, &ahb);
// We need to take ownership of the FD and close it if it came from IPC.
if (file_descriptor.auto_close) {
if (IGNORE_EINTR(close(file_descriptor.fd)) < 0)
PLOG(ERROR) << "close";
}
if (ret < 0) {
PLOG(ERROR) << "recv";
type_ = Type::INVALID;
return;
}
memory_object_ = ahb;
}
}
SharedMemoryHandle::SharedMemoryHandle(AHardwareBuffer* buffer,
size_t size,
const base::UnguessableToken& guid)
: type_(Type::ANDROID_HARDWARE_BUFFER),
memory_object_(buffer),
ownership_passes_to_ipc_(false),
guid_(guid),
size_(size) {
// Don't call Acquire on the AHardwareBuffer here. Getting a handle doesn't
// take ownership.
: guid_(guid), size_(size) {
DCHECK_GE(file_descriptor.fd, 0);
file_descriptor_ = file_descriptor;
}
// static
SharedMemoryHandle SharedMemoryHandle::ImportHandle(int fd, size_t size) {
SharedMemoryHandle handle;
handle.type_ = Type::ASHMEM;
handle.file_descriptor_.fd = fd;
handle.file_descriptor_.auto_close = false;
handle.guid_ = UnguessableToken::Create();
......@@ -104,122 +46,53 @@ SharedMemoryHandle SharedMemoryHandle::ImportHandle(int fd, size_t size) {
}
int SharedMemoryHandle::GetHandle() const {
switch (type_) {
case Type::INVALID:
return -1;
case Type::ASHMEM:
DCHECK(IsValid());
return file_descriptor_.fd;
case Type::ANDROID_HARDWARE_BUFFER:
DCHECK(IsValid());
ScopedFD read_fd, write_fd;
if (!CreateSocketPair(&read_fd, &write_fd)) {
PLOG(ERROR) << "SocketPair";
return -1;
}
int ret =
AndroidHardwareBufferCompat::GetInstance().SendHandleToUnixSocket(
memory_object_, write_fd.get());
if (ret < 0) {
PLOG(ERROR) << "send";
return -1;
}
// Close write end now to avoid timeouts in case the receiver goes away.
write_fd.reset();
return read_fd.release();
}
DCHECK(IsValid());
return file_descriptor_.fd;
}
bool SharedMemoryHandle::IsValid() const {
return type_ != Type::INVALID;
return file_descriptor_.fd >= 0;
}
void SharedMemoryHandle::Close() const {
switch (type_) {
case Type::INVALID:
return;
case Type::ASHMEM:
DCHECK(IsValid());
if (IGNORE_EINTR(close(file_descriptor_.fd)) < 0)
PLOG(ERROR) << "close";
break;
case Type::ANDROID_HARDWARE_BUFFER:
DCHECK(IsValid());
AndroidHardwareBufferCompat::GetInstance().Release(memory_object_);
}
DCHECK(IsValid());
if (IGNORE_EINTR(close(file_descriptor_.fd)) < 0)
PLOG(ERROR) << "close";
}
int SharedMemoryHandle::Release() {
DCHECK_EQ(type_, Type::ASHMEM);
int old_fd = file_descriptor_.fd;
file_descriptor_.fd = -1;
return old_fd;
}
SharedMemoryHandle SharedMemoryHandle::Duplicate() const {
switch (type_) {
case Type::INVALID:
return SharedMemoryHandle();
case Type::ASHMEM: {
DCHECK(IsValid());
SharedMemoryHandle result;
int duped_handle = HANDLE_EINTR(dup(file_descriptor_.fd));
if (duped_handle >= 0) {
result = SharedMemoryHandle(FileDescriptor(duped_handle, true),
GetSize(), GetGUID());
if (IsReadOnly())
result.SetReadOnly();
}
return result;
}
case Type::ANDROID_HARDWARE_BUFFER:
DCHECK(IsValid());
AndroidHardwareBufferCompat::GetInstance().Acquire(memory_object_);
SharedMemoryHandle handle(*this);
handle.SetOwnershipPassesToIPC(true);
return handle;
DCHECK(IsValid());
SharedMemoryHandle result;
int duped_handle = HANDLE_EINTR(dup(file_descriptor_.fd));
if (duped_handle >= 0) {
result = SharedMemoryHandle(FileDescriptor(duped_handle, true), GetSize(),
GetGUID());
if (IsReadOnly())
result.SetReadOnly();
}
}
AHardwareBuffer* SharedMemoryHandle::GetMemoryObject() const {
DCHECK_EQ(type_, Type::ANDROID_HARDWARE_BUFFER);
return memory_object_;
return result;
}
void SharedMemoryHandle::SetOwnershipPassesToIPC(bool ownership_passes) {
switch (type_) {
case Type::ASHMEM:
file_descriptor_.auto_close = ownership_passes;
break;
case Type::INVALID:
case Type::ANDROID_HARDWARE_BUFFER:
ownership_passes_to_ipc_ = ownership_passes;
}
file_descriptor_.auto_close = ownership_passes;
}
bool SharedMemoryHandle::OwnershipPassesToIPC() const {
switch (type_) {
case Type::ASHMEM:
return file_descriptor_.auto_close;
case Type::INVALID:
case Type::ANDROID_HARDWARE_BUFFER:
return ownership_passes_to_ipc_;
}
return file_descriptor_.auto_close;
}
bool SharedMemoryHandle::IsRegionReadOnly() const {
if (type_ != Type::ASHMEM)
return false;
int prot = GetAshmemRegionProtectionMask(file_descriptor_.fd);
return (prot >= 0 && (prot & PROT_WRITE) == 0);
}
bool SharedMemoryHandle::SetRegionReadOnly() const {
DCHECK_EQ(type_, Type::ASHMEM);
int fd = file_descriptor_.fd;
int prot = GetAshmemRegionProtectionMask(fd);
if (prot < 0)
......
......@@ -360,7 +360,7 @@ void MailboxToSurfaceBridge::DestroyMailboxTexture(const gpu::Mailbox& mailbox,
}
uint32_t MailboxToSurfaceBridge::BindSharedBufferImage(
const gfx::GpuMemoryBufferHandle& handle,
gfx::GpuMemoryBuffer* buffer,
const gfx::Size& size,
gfx::BufferFormat format,
gfx::BufferUsage usage,
......@@ -368,10 +368,6 @@ uint32_t MailboxToSurfaceBridge::BindSharedBufferImage(
TRACE_EVENT0("gpu", __FUNCTION__);
DCHECK(IsConnected());
auto buffer = gpu::GpuMemoryBufferImplAndroidHardwareBuffer::CreateFromHandle(
handle, size, format, usage,
gpu::GpuMemoryBufferImpl::DestructionCallback());
auto img = gl_->CreateImageCHROMIUM(buffer->AsClientBuffer(), size.width(),
size.height(), GL_RGBA);
......
......@@ -20,7 +20,7 @@ class SurfaceTexture;
} // namespace gl
namespace gfx {
struct GpuMemoryBufferHandle;
class GpuMemoryBuffer;
}
namespace gpu {
......@@ -90,10 +90,10 @@ class MailboxToSurfaceBridge {
// Unbinds the texture from the mailbox and destroys it.
void DestroyMailboxTexture(const gpu::Mailbox& mailbox, uint32_t texture_id);
// Creates a GLImage from the handle's GpuMemoryBuffer and binds it to
// the supplied texture_id in the GPU process. Returns the image ID in the
// command buffer context.
uint32_t BindSharedBufferImage(const gfx::GpuMemoryBufferHandle&,
// Creates a GLImage from the |buffer| and binds it to the supplied texture_id
// in the GPU process. Returns the image ID in the command buffer context.
// Does not take ownership of |buffer| or retain any references to it.
uint32_t BindSharedBufferImage(gfx::GpuMemoryBuffer* buffer,
const gfx::Size& size,
gfx::BufferFormat format,
gfx::BufferUsage usage,
......
......@@ -564,13 +564,13 @@ void VrShellGl::WebVrCreateOrResizeSharedBufferImage(WebXrSharedBuffer* buffer,
gpu::GpuMemoryBufferImpl::DestructionCallback());
buffer->remote_image = mailbox_bridge_->BindSharedBufferImage(
buffer->gmb->GetHandle(), size, format, usage, buffer->remote_texture);
buffer->gmb.get(), size, format, usage, buffer->remote_texture);
DVLOG(2) << ": BindSharedBufferImage, remote_image=" << buffer->remote_image;
scoped_refptr<gl::GLImageAHardwareBuffer> img(
new gl::GLImageAHardwareBuffer(webvr_surface_size_));
AHardwareBuffer* ahb = buffer->gmb->GetHandle().handle.GetMemoryObject();
AHardwareBuffer* ahb = buffer->gmb->GetHandle().android_hardware_buffer;
bool ret = img->Initialize(ahb, false /* preserved */);
if (!ret) {
DLOG(WARNING) << __FUNCTION__ << ": ERROR: failed to initialize image!";
......
......@@ -11,7 +11,6 @@
#include "base/bind_helpers.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/memory/shared_memory_handle.h"
#include "gpu/ipc/common/gpu_memory_buffer_impl_android_hardware_buffer.h"
#include "gpu/ipc/common/gpu_memory_buffer_support.h"
#include "ui/gfx/geometry/size.h"
......@@ -61,9 +60,9 @@ GpuMemoryBufferImplAndroidHardwareBuffer::
const gfx::Size& size,
gfx::BufferFormat format,
const DestructionCallback& callback,
const base::SharedMemoryHandle& handle)
base::android::ScopedHardwareBufferHandle handle)
: GpuMemoryBufferImpl(id, size, format, callback),
shared_memory_(handle, false) {}
hardware_buffer_handle_(std::move(handle)) {}
GpuMemoryBufferImplAndroidHardwareBuffer::
~GpuMemoryBufferImplAndroidHardwareBuffer() {}
......@@ -88,7 +87,7 @@ GpuMemoryBufferImplAndroidHardwareBuffer::Create(
return base::WrapUnique(new GpuMemoryBufferImplAndroidHardwareBuffer(
id, size, format, callback,
base::SharedMemoryHandle(buffer, 0, base::UnguessableToken::Create())));
base::android::ScopedHardwareBufferHandle::Adopt(buffer)));
}
// static
......@@ -99,9 +98,11 @@ GpuMemoryBufferImplAndroidHardwareBuffer::CreateFromHandle(
gfx::BufferFormat format,
gfx::BufferUsage usage,
const DestructionCallback& callback) {
DCHECK(base::SharedMemory::IsHandleValid(handle.handle));
DCHECK(handle.android_hardware_buffer);
return base::WrapUnique(new GpuMemoryBufferImplAndroidHardwareBuffer(
handle.id, size, format, callback, handle.handle));
handle.id, size, format, callback,
base::android::ScopedHardwareBufferHandle::Adopt(
handle.android_hardware_buffer)));
}
bool GpuMemoryBufferImplAndroidHardwareBuffer::Map() {
......@@ -123,8 +124,7 @@ gfx::GpuMemoryBufferHandle GpuMemoryBufferImplAndroidHardwareBuffer::GetHandle()
gfx::GpuMemoryBufferHandle handle;
handle.type = gfx::ANDROID_HARDWARE_BUFFER;
handle.id = id_;
handle.handle = shared_memory_.handle();
handle.android_hardware_buffer = hardware_buffer_handle_.get();
return handle;
}
......@@ -141,8 +141,7 @@ base::Closure GpuMemoryBufferImplAndroidHardwareBuffer::AllocateForTesting(
AHardwareBuffer_Desc desc = GetBufferDescription(size, format, usage);
base::AndroidHardwareBufferCompat::GetInstance().Allocate(&desc, &buffer);
DCHECK(buffer);
handle->handle =
base::SharedMemoryHandle(buffer, 0, base::UnguessableToken::Create());
handle->android_hardware_buffer = buffer;
return base::DoNothing();
}
......
......@@ -5,12 +5,10 @@
#ifndef GPU_IPC_COMMON_GPU_MEMORY_BUFFER_IMPL_ANDROID_HARDWARE_BUFFER_H_
#define GPU_IPC_COMMON_GPU_MEMORY_BUFFER_IMPL_ANDROID_HARDWARE_BUFFER_H_
#include "base/memory/shared_memory.h"
#include "base/android/scoped_hardware_buffer_handle.h"
#include "gpu/gpu_export.h"
#include "gpu/ipc/common/gpu_memory_buffer_impl.h"
extern "C" typedef struct AHardwareBuffer AHardwareBuffer;
namespace gpu {
// Implementation of GPU memory buffer based on AHardwareBuffer.
......@@ -54,9 +52,9 @@ class GPU_EXPORT GpuMemoryBufferImplAndroidHardwareBuffer
const gfx::Size& size,
gfx::BufferFormat format,
const DestructionCallback& callback,
const base::SharedMemoryHandle& handle);
base::android::ScopedHardwareBufferHandle handle);
base::SharedMemory shared_memory_;
base::android::ScopedHardwareBufferHandle hardware_buffer_handle_;
DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferImplAndroidHardwareBuffer);
};
......
......@@ -49,10 +49,8 @@ GpuMemoryBufferFactoryAndroidHardwareBuffer::CreateImageForGpuMemoryBuffer(
// We should only end up in this code path if the memory buffer has a valid
// AHardwareBuffer.
DCHECK_EQ(handle.type, gfx::ANDROID_HARDWARE_BUFFER);
DCHECK_EQ(handle.handle.GetType(),
base::SharedMemoryHandle::Type::ANDROID_HARDWARE_BUFFER);
AHardwareBuffer* buffer = handle.handle.GetMemoryObject();
AHardwareBuffer* buffer = handle.android_hardware_buffer;
DCHECK(buffer);
scoped_refptr<gl::GLImageAHardwareBuffer> image(
......
......@@ -41,6 +41,13 @@
#include "ipc/handle_fuchsia.h"
#endif
#if defined(OS_ANDROID)
#include "base/android/scoped_hardware_buffer_handle.h"
#include "ipc/ipc_mojo_handle_attachment.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "mojo/public/cpp/system/scope_to_message_pipe.h"
#endif
namespace IPC {
namespace {
......@@ -567,31 +574,76 @@ void ParamTraits<base::FileDescriptor>::Log(const param_type& p,
#endif // defined(OS_POSIX)
#if defined(OS_ANDROID)
void ParamTraits<base::SharedMemoryHandle::Type>::Write(base::Pickle* m,
const param_type& p) {
DCHECK(static_cast<int>(p) >= 0 && p <= base::SharedMemoryHandle::Type::LAST);
m->WriteInt(static_cast<int>(p));
void ParamTraits<AHardwareBuffer*>::Write(base::Pickle* m,
const param_type& p) {
const bool is_valid = p != nullptr;
WriteParam(m, is_valid);
if (!is_valid)
return;
// Assume ownership of the input AHardwareBuffer.
auto handle = base::android::ScopedHardwareBufferHandle::Adopt(p);
// We must keep a ref to the AHardwareBuffer alive until the receiver has
// acquired its own reference. We do this by sending a message pipe handle
// along with the buffer. When the receiver deserializes (or even if they
// die without ever reading the message) their end of the pipe will be
// closed. We will eventually detect this and release the AHB reference.
mojo::MessagePipe tracking_pipe;
m->WriteAttachment(new internal::MojoHandleAttachment(
mojo::ScopedHandle::From(std::move(tracking_pipe.handle0))));
WriteParam(m,
base::FileDescriptor(handle.SerializeAsFileDescriptor().release(),
true /* auto_close */));
// Pass ownership of the input handle to our tracking pipe to keep the AHB
// alive long enough to be deserialized by the receiver.
mojo::ScopeToMessagePipe(std::move(handle), std::move(tracking_pipe.handle1));
}
bool ParamTraits<base::SharedMemoryHandle::Type>::Read(
const base::Pickle* m,
base::PickleIterator* iter,
param_type* r) {
int value;
if (!iter->ReadInt(&value))
bool ParamTraits<AHardwareBuffer*>::Read(const base::Pickle* m,
base::PickleIterator* iter,
param_type* r) {
*r = nullptr;
bool is_valid;
if (!ReadParam(m, iter, &is_valid))
return false;
if (value < 0 ||
value > static_cast<int>(base::SharedMemoryHandle::Type::LAST))
if (!is_valid)
return true;
scoped_refptr<base::Pickle::Attachment> tracking_pipe_attachment;
if (!m->ReadAttachment(iter, &tracking_pipe_attachment))
return false;
*r = static_cast<param_type>(value);
// We keep this alive until the AHB is safely deserialized below. When this
// goes out of scope, the sender holding the other end of this pipe will treat
// this handle closure as a signal that it's safe to release their AHB
// keepalive ref.
mojo::ScopedHandle tracking_pipe =
static_cast<MessageAttachment*>(tracking_pipe_attachment.get())
->TakeMojoHandle();
base::FileDescriptor descriptor;
if (!ReadParam(m, iter, &descriptor))
return false;
// NOTE: It is valid to deserialize an invalid FileDescriptor, so the success
// of |ReadParam()| above does not imply that |descriptor| is valid.
base::ScopedFD scoped_fd(descriptor.fd);
if (!scoped_fd.is_valid())
return false;
*r = base::android::ScopedHardwareBufferHandle::DeserializeFromFileDescriptor(
std::move(scoped_fd))
.Take();
return true;
}
void ParamTraits<base::SharedMemoryHandle::Type>::Log(const param_type& p,
std::string* l) {
l->append(base::IntToString(static_cast<int>(p)));
void ParamTraits<AHardwareBuffer*>::Log(const param_type& p, std::string* l) {
l->append(base::StringPrintf("AHardwareBuffer(%p)", p));
}
#endif
#endif // defined(OS_ANDROID)
void ParamTraits<base::SharedMemoryHandle>::Write(base::Pickle* m,
const param_type& p) {
......@@ -614,10 +666,6 @@ void ParamTraits<base::SharedMemoryHandle>::Write(base::Pickle* m,
WriteParam(m, handle_fuchsia);
#else
#if defined(OS_ANDROID)
// Android transfers both ashmem and AHardwareBuffer SharedMemoryHandle
// subtypes, both are transferred via file descriptor but need to be handled
// differently by the receiver. Write the type to distinguish.
WriteParam(m, p.GetType());
WriteParam(m, p.IsReadOnly());
// Ensure the region is read-only before sending it through IPC.
......@@ -676,14 +724,9 @@ bool ParamTraits<base::SharedMemoryHandle>::Read(const base::Pickle* m,
return false;
#else
#if defined(OS_ANDROID)
// Android uses both ashmen and AHardwareBuffer subtypes, get the actual type
// for use as a constructor argument alongside the file descriptor.
base::SharedMemoryHandle::Type android_subtype;
bool is_read_only = false;
if (!ReadParam(m, iter, &android_subtype) ||
!ReadParam(m, iter, &is_read_only)) {
if (!ReadParam(m, iter, &is_read_only))
return false;
}
#endif
scoped_refptr<base::Pickle::Attachment> attachment;
if (!m->ReadAttachment(iter, &attachment))
......@@ -711,23 +754,18 @@ bool ParamTraits<base::SharedMemoryHandle>::Read(const base::Pickle* m,
#elif defined(OS_FUCHSIA)
*r = base::SharedMemoryHandle(handle_fuchsia.get_handle(),
static_cast<size_t>(size), guid);
#elif defined(OS_ANDROID)
#else
*r = base::SharedMemoryHandle(
android_subtype,
base::FileDescriptor(
static_cast<internal::PlatformFileAttachment*>(attachment.get())
->TakePlatformFile(),
true),
static_cast<size_t>(size), guid);
#endif
#if defined(OS_ANDROID)
if (is_read_only)
r->SetReadOnly();
#else
*r = base::SharedMemoryHandle(
base::FileDescriptor(
static_cast<internal::PlatformFileAttachment*>(attachment.get())
->TakePlatformFile(),
true),
static_cast<size_t>(size), guid);
#endif
return true;
......
......@@ -39,6 +39,10 @@
#include "ipc/ipc_param_traits.h"
#include "ipc/ipc_sync_message.h"
#if defined(OS_ANDROID)
#include "base/android/scoped_hardware_buffer_handle.h"
#endif
namespace base {
class DictionaryValue;
class FilePath;
......@@ -562,8 +566,8 @@ struct COMPONENT_EXPORT(IPC) ParamTraits<base::SharedMemoryHandle> {
#if defined(OS_ANDROID)
template <>
struct COMPONENT_EXPORT(IPC) ParamTraits<base::SharedMemoryHandle::Type> {
typedef base::SharedMemoryHandle::Type param_type;
struct COMPONENT_EXPORT(IPC) ParamTraits<AHardwareBuffer*> {
typedef AHardwareBuffer* param_type;
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
......
......@@ -43,6 +43,8 @@ component("system") {
"message_pipe.h",
"platform_handle.cc",
"platform_handle.h",
"scope_to_message_pipe.cc",
"scope_to_message_pipe.h",
"simple_watcher.cc",
"simple_watcher.h",
"string_data_pipe_producer.cc",
......
// Copyright 2018 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 "mojo/public/cpp/system/scope_to_message_pipe.h"
namespace mojo {
namespace internal {
namespace {
void OnWatcherSignaled(std::unique_ptr<MessagePipeScoperBase> scoper,
MojoResult result,
const HandleSignalsState& state) {
DCHECK(scoper);
DCHECK_EQ(result, MOJO_RESULT_OK);
DCHECK(state.peer_closed());
// No work to do except for letting |scoper| go out of scope and be destroyed.
}
} // namespace
MessagePipeScoperBase::MessagePipeScoperBase(ScopedMessagePipeHandle pipe)
: pipe_(std::move(pipe)),
pipe_watcher_(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC) {}
MessagePipeScoperBase::~MessagePipeScoperBase() = default;
// static
void MessagePipeScoperBase::StartWatchingPipe(
std::unique_ptr<MessagePipeScoperBase> scoper) {
auto* unowned_scoper = scoper.get();
// NOTE: We intentionally use base::Passed here with the owned |scoper|. The
// way we use it here, there is no way for the watcher callback to be invoked
// more than once. If this expectation is ever violated,
// base::RepeatingCallback will CHECK-fail.
unowned_scoper->pipe_watcher_.Watch(
unowned_scoper->pipe_.get(), MOJO_HANDLE_SIGNAL_PEER_CLOSED,
MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
base::BindRepeating(&OnWatcherSignaled, base::Passed(&scoper)));
}
} // namespace internal
} // namespace mojo
// Copyright 2018 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.
#ifndef MOJO_PUBLIC_CPP_SYSTEM_SCOPE_TO_MESSAGE_PIPE_H_
#define MOJO_PUBLIC_CPP_SYSTEM_SCOPE_TO_MESSAGE_PIPE_H_
#include <memory>
#include "base/bind.h"
#include "base/callback.h"
#include "base/macros.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "mojo/public/cpp/system/simple_watcher.h"
#include "mojo/public/cpp/system/system_export.h"
namespace mojo {
namespace internal {
// Owns the state and details to implement ScopeToMessagePipe (see below).
class MOJO_CPP_SYSTEM_EXPORT MessagePipeScoperBase {
public:
explicit MessagePipeScoperBase(ScopedMessagePipeHandle pipe);
virtual ~MessagePipeScoperBase();
static void StartWatchingPipe(std::unique_ptr<MessagePipeScoperBase> scoper);
private:
ScopedMessagePipeHandle pipe_;
SimpleWatcher pipe_watcher_;
DISALLOW_COPY_AND_ASSIGN(MessagePipeScoperBase);
};
template <typename T>
class MessagePipeScoper : public MessagePipeScoperBase {
public:
explicit MessagePipeScoper(T scoped_object, ScopedMessagePipeHandle pipe)
: MessagePipeScoperBase(std::move(pipe)),
scoped_object_(std::move(scoped_object)) {}
~MessagePipeScoper() override = default;
private:
T scoped_object_;
DISALLOW_COPY_AND_ASSIGN(MessagePipeScoper);
};
} // namespace internal
// Binds the lifetime of |object| to that of |pipe|'s connection. When |pipe|'s
// peer is closed, |pipe| will be closed and |object| will be destroyed. This
// can be useful as a simple mechanism to track object lifetime across process
// boundaries.
template <typename T>
void ScopeToMessagePipe(T object, ScopedMessagePipeHandle pipe) {
internal::MessagePipeScoperBase::StartWatchingPipe(
std::make_unique<internal::MessagePipeScoper<T>>(std::move(object),
std::move(pipe)));
}
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_SYSTEM_SCOPE_TO_MESSAGE_PIPE_H_
......@@ -11,6 +11,7 @@ source_set("tests") {
"file_data_pipe_producer_unittest.cc",
"handle_signal_tracker_unittest.cc",
"handle_signals_state_unittest.cc",
"scope_to_message_pipe_unittest.cc",
"simple_watcher_unittest.cc",
"string_data_pipe_producer_unittest.cc",
"wait_set_unittest.cc",
......
// Copyright 2018 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 "mojo/public/cpp/system/scope_to_message_pipe.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/test/bind_test_util.h"
#include "base/test/scoped_task_environment.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "mojo/public/cpp/system/simple_watcher.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace mojo {
namespace {
class RunCallbackOnDestruction {
public:
explicit RunCallbackOnDestruction(base::OnceClosure destruction_callback)
: destruction_callback_(std::move(destruction_callback)) {}
~RunCallbackOnDestruction() { std::move(destruction_callback_).Run(); }
private:
base::OnceClosure destruction_callback_;
DISALLOW_COPY_AND_ASSIGN(RunCallbackOnDestruction);
};
class ScopeToMessagePipeTest : public testing::Test {
public:
ScopeToMessagePipeTest() = default;
~ScopeToMessagePipeTest() override = default;
private:
base::test::ScopedTaskEnvironment task_environment_;
DISALLOW_COPY_AND_ASSIGN(ScopeToMessagePipeTest);
};
TEST_F(ScopeToMessagePipeTest, ObjectDestroyedOnPeerClosure) {
base::RunLoop wait_for_destruction;
MessagePipe pipe;
ScopeToMessagePipe(std::make_unique<RunCallbackOnDestruction>(
wait_for_destruction.QuitClosure()),
std::move(pipe.handle0));
pipe.handle1.reset();
wait_for_destruction.Run();
}
TEST_F(ScopeToMessagePipeTest, PipeClosedOnPeerClosure) {
base::RunLoop wait_for_pipe_closure;
MessagePipe pipe;
SimpleWatcher watcher(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC);
watcher.Watch(pipe.handle1.get(), MOJO_HANDLE_SIGNAL_READABLE,
MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
base::BindLambdaForTesting(
[&](MojoResult result, const HandleSignalsState& state) {
EXPECT_EQ(result, MOJO_RESULT_CANCELLED);
wait_for_pipe_closure.Quit();
}));
ScopeToMessagePipe(42, std::move(pipe.handle0));
pipe.handle1.reset();
wait_for_pipe_closure.Run();
}
} // namespace
} // namespace mojo
......@@ -9,6 +9,8 @@
#if defined(OS_WIN)
#include <windows.h>
#elif defined(OS_ANDROID)
#include "base/android/android_hardware_buffer_compat.h"
#endif
namespace gfx {
......@@ -51,7 +53,11 @@ GpuMemoryBufferHandle CloneHandleForIPC(
gfx::GpuMemoryBufferHandle handle;
handle.type = gfx::ANDROID_HARDWARE_BUFFER;
handle.id = source_handle.id;
handle.handle = base::SharedMemory::DuplicateHandle(source_handle.handle);
#if defined(OS_ANDROID)
base::AndroidHardwareBufferCompat::GetInstance().Acquire(
source_handle.android_hardware_buffer);
handle.android_hardware_buffer = source_handle.android_hardware_buffer;
#endif
return handle;
}
case gfx::IO_SURFACE_BUFFER:
......
......@@ -26,6 +26,10 @@
extern "C" typedef struct _ClientBuffer* ClientBuffer;
#if defined(OS_ANDROID)
extern "C" typedef struct AHardwareBuffer AHardwareBuffer;
#endif
namespace gfx {
class ColorSpace;
......@@ -58,6 +62,8 @@ struct GFX_EXPORT GpuMemoryBufferHandle {
ScopedRefCountedIOSurfaceMachPort mach_port;
#elif defined(OS_WIN)
IPC::PlatformFileForTransit dxgi_handle;
#elif defined(OS_ANDROID)
AHardwareBuffer* android_hardware_buffer = nullptr;
#endif
};
......
......@@ -57,6 +57,8 @@ IPC_STRUCT_TRAITS_BEGIN(gfx::GpuMemoryBufferHandle)
IPC_STRUCT_TRAITS_MEMBER(mach_port)
#elif defined(OS_WIN)
IPC_STRUCT_TRAITS_MEMBER(dxgi_handle)
#elif defined(OS_ANDROID)
IPC_STRUCT_TRAITS_MEMBER(android_hardware_buffer)
#endif
IPC_STRUCT_TRAITS_END()
......
......@@ -79,6 +79,20 @@ struct NativePixmapHandle {
array<NativePixmapPlane> planes;
};
[EnableIf=is_android]
struct AHardwareBufferHandle {
// The actual file descriptor used to wrap the AHardwareBuffer object for
// serialization.
handle buffer_handle;
// A message pipe handle which tracks the lifetime of this
// AHardwareBufferHandle. The sender may use this to observe the lifetime
// remotely by watching the other end of this pipe. Useful for retaining a
// sender-side AHB ref until the receiver deserializes the AHB and acquires its
// own ref.
handle<message_pipe> tracking_pipe;
};
// gfx::GpuMemoryBufferHandle
struct GpuMemoryBufferHandle {
// TODO(676224): Use preprocessor to restrict platform-specific members to
......@@ -93,4 +107,7 @@ struct GpuMemoryBufferHandle {
[EnableIf=is_win]
handle? dxgi_handle;
[EnableIf=is_android]
AHardwareBufferHandle? android_hardware_buffer_handle;
};
......@@ -7,6 +7,12 @@
#include "build/build_config.h"
#include "mojo/public/cpp/system/platform_handle.h"
#if defined(OS_ANDROID)
#include "base/android/scoped_hardware_buffer_handle.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "mojo/public/cpp/system/scope_to_message_pipe.h"
#endif
namespace mojo {
// static
......@@ -54,8 +60,7 @@ mojo::ScopedSharedBufferHandle
StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView,
gfx::GpuMemoryBufferHandle>::
shared_memory_handle(const gfx::GpuMemoryBufferHandle& handle) {
if (handle.type != gfx::SHARED_MEMORY_BUFFER &&
handle.type != gfx::ANDROID_HARDWARE_BUFFER)
if (handle.type != gfx::SHARED_MEMORY_BUFFER)
return mojo::ScopedSharedBufferHandle();
return mojo::WrapSharedMemoryHandle(
handle.handle, handle.handle.GetSize(),
......@@ -98,6 +103,38 @@ mojo::ScopedHandle StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView,
}
#endif
#if defined(OS_ANDROID)
// static
gfx::mojom::AHardwareBufferHandlePtr
StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView,
gfx::GpuMemoryBufferHandle>::
android_hardware_buffer_handle(const gfx::GpuMemoryBufferHandle& handle) {
if (handle.type != gfx::ANDROID_HARDWARE_BUFFER)
return nullptr;
// Assume ownership of the input AHardwareBuffer.
auto scoped_handle = base::android::ScopedHardwareBufferHandle::Adopt(
handle.android_hardware_buffer);
// We must keep a ref to the AHardwareBuffer alive until the receiver has
// acquired its own reference. We do this by sending a message pipe handle
// along with the buffer. When the receiver deserializes (or even if they
// die without ever reading the message) their end of the pipe will be
// closed. We will eventually detect this and release the AHB reference.
mojo::MessagePipe tracking_pipe;
auto wrapped_handle = gfx::mojom::AHardwareBufferHandle::New(
mojo::WrapPlatformFile(
scoped_handle.SerializeAsFileDescriptor().release()),
std::move(tracking_pipe.handle0));
// Pass ownership of the input handle to our tracking pipe to keep the AHB
// alive until it's deserialized.
mojo::ScopeToMessagePipe(std::move(scoped_handle),
std::move(tracking_pipe.handle1));
return wrapped_handle;
}
#endif
bool StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView,
gfx::GpuMemoryBufferHandle>::
Read(gfx::mojom::GpuMemoryBufferHandleDataView data,
......@@ -105,8 +142,7 @@ bool StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView,
if (!data.ReadType(&out->type) || !data.ReadId(&out->id))
return false;
if (out->type == gfx::SHARED_MEMORY_BUFFER ||
out->type == gfx::ANDROID_HARDWARE_BUFFER) {
if (out->type == gfx::SHARED_MEMORY_BUFFER) {
mojo::ScopedSharedBufferHandle handle = data.TakeSharedMemoryHandle();
if (handle.is_valid()) {
MojoResult unwrap_result = mojo::UnwrapSharedMemoryHandle(
......@@ -144,6 +180,26 @@ bool StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView,
out->offset = data.offset();
out->stride = data.stride();
}
#endif
#if defined(OS_ANDROID)
if (out->type == gfx::ANDROID_HARDWARE_BUFFER) {
gfx::mojom::AHardwareBufferHandlePtr buffer_handle;
if (!data.ReadAndroidHardwareBufferHandle(&buffer_handle) || !buffer_handle)
return false;
base::PlatformFile fd;
MojoResult unwrap_result =
mojo::UnwrapPlatformFile(std::move(buffer_handle->buffer_handle), &fd);
base::ScopedFD scoped_fd(fd);
if (unwrap_result != MOJO_RESULT_OK || !scoped_fd.is_valid())
return false;
out->android_hardware_buffer =
base::android::ScopedHardwareBufferHandle ::
DeserializeFromFileDescriptor(std::move(scoped_fd))
.Take();
out->offset = data.offset();
out->stride = data.stride();
}
#endif
return true;
}
......
......@@ -332,6 +332,11 @@ struct StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView,
const gfx::GpuMemoryBufferHandle& handle);
#endif
#if defined(OS_ANDROID)
static gfx::mojom::AHardwareBufferHandlePtr android_hardware_buffer_handle(
const gfx::GpuMemoryBufferHandle& handle);
#endif
static bool Read(gfx::mojom::GpuMemoryBufferHandleDataView data,
gfx::GpuMemoryBufferHandle* handle);
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment