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") { ...@@ -209,6 +209,8 @@ jumbo_component("base") {
"android/path_utils.h", "android/path_utils.h",
"android/record_histogram.cc", "android/record_histogram.cc",
"android/record_user_action.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.cc",
"android/scoped_java_ref.h", "android/scoped_java_ref.h",
"android/statistics_recorder_android.cc", "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 @@ ...@@ -24,10 +24,6 @@
#include "base/file_descriptor_posix.h" #include "base/file_descriptor_posix.h"
#endif #endif
#if defined(OS_ANDROID)
extern "C" typedef struct AHardwareBuffer AHardwareBuffer;
#endif
namespace base { namespace base {
// SharedMemoryHandle is the smallest possible IPC-transportable "reference" to // SharedMemoryHandle is the smallest possible IPC-transportable "reference" to
...@@ -149,32 +145,6 @@ class BASE_EXPORT SharedMemoryHandle { ...@@ -149,32 +145,6 @@ class BASE_EXPORT SharedMemoryHandle {
#endif #endif
#if defined(OS_ANDROID) #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 // Marks the current file descriptor as read-only, for the purpose of
// mapping. This is independent of the region's read-only status. // mapping. This is independent of the region's read-only status.
void SetReadOnly() { read_only_ = true; } void SetReadOnly() { read_only_ = true; }
...@@ -237,13 +207,7 @@ class BASE_EXPORT SharedMemoryHandle { ...@@ -237,13 +207,7 @@ class BASE_EXPORT SharedMemoryHandle {
#elif defined(OS_ANDROID) #elif defined(OS_ANDROID)
friend class SharedMemory; 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_; FileDescriptor file_descriptor_;
AHardwareBuffer* memory_object_ = nullptr;
bool ownership_passes_to_ipc_ = false;
bool read_only_ = false; bool read_only_ = false;
#elif defined(OS_FUCHSIA) #elif defined(OS_FUCHSIA)
zx_handle_t handle_ = ZX_HANDLE_INVALID; zx_handle_t handle_ = ZX_HANDLE_INVALID;
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <unistd.h> #include <unistd.h>
#include "base/android/android_hardware_buffer_compat.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/posix/eintr_wrapper.h" #include "base/posix/eintr_wrapper.h"
#include "base/posix/unix_domain_socket.h" #include "base/posix/unix_domain_socket.h"
...@@ -25,77 +24,20 @@ static int GetAshmemRegionProtectionMask(int fd) { ...@@ -25,77 +24,20 @@ static int GetAshmemRegionProtectionMask(int fd) {
return prot; return prot;
} }
SharedMemoryHandle::SharedMemoryHandle() {} SharedMemoryHandle::SharedMemoryHandle() = default;
SharedMemoryHandle::SharedMemoryHandle( SharedMemoryHandle::SharedMemoryHandle(
const base::FileDescriptor& file_descriptor, const base::FileDescriptor& file_descriptor,
size_t size, size_t size,
const base::UnguessableToken& guid) const base::UnguessableToken& guid)
: SharedMemoryHandle(Type::ASHMEM, file_descriptor, size, guid) {} : guid_(guid), size_(size) {
DCHECK_GE(file_descriptor.fd, 0);
SharedMemoryHandle::SharedMemoryHandle( file_descriptor_ = file_descriptor;
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.
} }
// static // static
SharedMemoryHandle SharedMemoryHandle::ImportHandle(int fd, size_t size) { SharedMemoryHandle SharedMemoryHandle::ImportHandle(int fd, size_t size) {
SharedMemoryHandle handle; SharedMemoryHandle handle;
handle.type_ = Type::ASHMEM;
handle.file_descriptor_.fd = fd; handle.file_descriptor_.fd = fd;
handle.file_descriptor_.auto_close = false; handle.file_descriptor_.auto_close = false;
handle.guid_ = UnguessableToken::Create(); handle.guid_ = UnguessableToken::Create();
...@@ -104,122 +46,53 @@ SharedMemoryHandle SharedMemoryHandle::ImportHandle(int fd, size_t size) { ...@@ -104,122 +46,53 @@ SharedMemoryHandle SharedMemoryHandle::ImportHandle(int fd, size_t size) {
} }
int SharedMemoryHandle::GetHandle() const { int SharedMemoryHandle::GetHandle() const {
switch (type_) { DCHECK(IsValid());
case Type::INVALID: return file_descriptor_.fd;
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();
}
} }
bool SharedMemoryHandle::IsValid() const { bool SharedMemoryHandle::IsValid() const {
return type_ != Type::INVALID; return file_descriptor_.fd >= 0;
} }
void SharedMemoryHandle::Close() const { void SharedMemoryHandle::Close() const {
switch (type_) { DCHECK(IsValid());
case Type::INVALID: if (IGNORE_EINTR(close(file_descriptor_.fd)) < 0)
return; PLOG(ERROR) << "close";
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_);
}
} }
int SharedMemoryHandle::Release() { int SharedMemoryHandle::Release() {
DCHECK_EQ(type_, Type::ASHMEM);
int old_fd = file_descriptor_.fd; int old_fd = file_descriptor_.fd;
file_descriptor_.fd = -1; file_descriptor_.fd = -1;
return old_fd; return old_fd;
} }
SharedMemoryHandle SharedMemoryHandle::Duplicate() const { SharedMemoryHandle SharedMemoryHandle::Duplicate() const {
switch (type_) { DCHECK(IsValid());
case Type::INVALID: SharedMemoryHandle result;
return SharedMemoryHandle(); int duped_handle = HANDLE_EINTR(dup(file_descriptor_.fd));
case Type::ASHMEM: { if (duped_handle >= 0) {
DCHECK(IsValid()); result = SharedMemoryHandle(FileDescriptor(duped_handle, true), GetSize(),
SharedMemoryHandle result; GetGUID());
int duped_handle = HANDLE_EINTR(dup(file_descriptor_.fd)); if (IsReadOnly())
if (duped_handle >= 0) { result.SetReadOnly();
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;
} }
} return result;
AHardwareBuffer* SharedMemoryHandle::GetMemoryObject() const {
DCHECK_EQ(type_, Type::ANDROID_HARDWARE_BUFFER);
return memory_object_;
} }
void SharedMemoryHandle::SetOwnershipPassesToIPC(bool ownership_passes) { void SharedMemoryHandle::SetOwnershipPassesToIPC(bool ownership_passes) {
switch (type_) { file_descriptor_.auto_close = ownership_passes;
case Type::ASHMEM:
file_descriptor_.auto_close = ownership_passes;
break;
case Type::INVALID:
case Type::ANDROID_HARDWARE_BUFFER:
ownership_passes_to_ipc_ = ownership_passes;
}
} }
bool SharedMemoryHandle::OwnershipPassesToIPC() const { bool SharedMemoryHandle::OwnershipPassesToIPC() const {
switch (type_) { return file_descriptor_.auto_close;
case Type::ASHMEM:
return file_descriptor_.auto_close;
case Type::INVALID:
case Type::ANDROID_HARDWARE_BUFFER:
return ownership_passes_to_ipc_;
}
} }
bool SharedMemoryHandle::IsRegionReadOnly() const { bool SharedMemoryHandle::IsRegionReadOnly() const {
if (type_ != Type::ASHMEM)
return false;
int prot = GetAshmemRegionProtectionMask(file_descriptor_.fd); int prot = GetAshmemRegionProtectionMask(file_descriptor_.fd);
return (prot >= 0 && (prot & PROT_WRITE) == 0); return (prot >= 0 && (prot & PROT_WRITE) == 0);
} }
bool SharedMemoryHandle::SetRegionReadOnly() const { bool SharedMemoryHandle::SetRegionReadOnly() const {
DCHECK_EQ(type_, Type::ASHMEM);
int fd = file_descriptor_.fd; int fd = file_descriptor_.fd;
int prot = GetAshmemRegionProtectionMask(fd); int prot = GetAshmemRegionProtectionMask(fd);
if (prot < 0) if (prot < 0)
......
...@@ -360,7 +360,7 @@ void MailboxToSurfaceBridge::DestroyMailboxTexture(const gpu::Mailbox& mailbox, ...@@ -360,7 +360,7 @@ void MailboxToSurfaceBridge::DestroyMailboxTexture(const gpu::Mailbox& mailbox,
} }
uint32_t MailboxToSurfaceBridge::BindSharedBufferImage( uint32_t MailboxToSurfaceBridge::BindSharedBufferImage(
const gfx::GpuMemoryBufferHandle& handle, gfx::GpuMemoryBuffer* buffer,
const gfx::Size& size, const gfx::Size& size,
gfx::BufferFormat format, gfx::BufferFormat format,
gfx::BufferUsage usage, gfx::BufferUsage usage,
...@@ -368,10 +368,6 @@ uint32_t MailboxToSurfaceBridge::BindSharedBufferImage( ...@@ -368,10 +368,6 @@ uint32_t MailboxToSurfaceBridge::BindSharedBufferImage(
TRACE_EVENT0("gpu", __FUNCTION__); TRACE_EVENT0("gpu", __FUNCTION__);
DCHECK(IsConnected()); DCHECK(IsConnected());
auto buffer = gpu::GpuMemoryBufferImplAndroidHardwareBuffer::CreateFromHandle(
handle, size, format, usage,
gpu::GpuMemoryBufferImpl::DestructionCallback());
auto img = gl_->CreateImageCHROMIUM(buffer->AsClientBuffer(), size.width(), auto img = gl_->CreateImageCHROMIUM(buffer->AsClientBuffer(), size.width(),
size.height(), GL_RGBA); size.height(), GL_RGBA);
......
...@@ -20,7 +20,7 @@ class SurfaceTexture; ...@@ -20,7 +20,7 @@ class SurfaceTexture;
} // namespace gl } // namespace gl
namespace gfx { namespace gfx {
struct GpuMemoryBufferHandle; class GpuMemoryBuffer;
} }
namespace gpu { namespace gpu {
...@@ -90,10 +90,10 @@ class MailboxToSurfaceBridge { ...@@ -90,10 +90,10 @@ class MailboxToSurfaceBridge {
// Unbinds the texture from the mailbox and destroys it. // Unbinds the texture from the mailbox and destroys it.
void DestroyMailboxTexture(const gpu::Mailbox& mailbox, uint32_t texture_id); void DestroyMailboxTexture(const gpu::Mailbox& mailbox, uint32_t texture_id);
// Creates a GLImage from the handle's GpuMemoryBuffer and binds it to // Creates a GLImage from the |buffer| and binds it to the supplied texture_id
// the supplied texture_id in the GPU process. Returns the image ID in the // in the GPU process. Returns the image ID in the command buffer context.
// command buffer context. // Does not take ownership of |buffer| or retain any references to it.
uint32_t BindSharedBufferImage(const gfx::GpuMemoryBufferHandle&, uint32_t BindSharedBufferImage(gfx::GpuMemoryBuffer* buffer,
const gfx::Size& size, const gfx::Size& size,
gfx::BufferFormat format, gfx::BufferFormat format,
gfx::BufferUsage usage, gfx::BufferUsage usage,
......
...@@ -564,13 +564,13 @@ void VrShellGl::WebVrCreateOrResizeSharedBufferImage(WebXrSharedBuffer* buffer, ...@@ -564,13 +564,13 @@ void VrShellGl::WebVrCreateOrResizeSharedBufferImage(WebXrSharedBuffer* buffer,
gpu::GpuMemoryBufferImpl::DestructionCallback()); gpu::GpuMemoryBufferImpl::DestructionCallback());
buffer->remote_image = mailbox_bridge_->BindSharedBufferImage( 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; DVLOG(2) << ": BindSharedBufferImage, remote_image=" << buffer->remote_image;
scoped_refptr<gl::GLImageAHardwareBuffer> img( scoped_refptr<gl::GLImageAHardwareBuffer> img(
new gl::GLImageAHardwareBuffer(webvr_surface_size_)); 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 */); bool ret = img->Initialize(ahb, false /* preserved */);
if (!ret) { if (!ret) {
DLOG(WARNING) << __FUNCTION__ << ": ERROR: failed to initialize image!"; DLOG(WARNING) << __FUNCTION__ << ": ERROR: failed to initialize image!";
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include "base/bind_helpers.h" #include "base/bind_helpers.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/ptr_util.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_impl_android_hardware_buffer.h"
#include "gpu/ipc/common/gpu_memory_buffer_support.h" #include "gpu/ipc/common/gpu_memory_buffer_support.h"
#include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size.h"
...@@ -61,9 +60,9 @@ GpuMemoryBufferImplAndroidHardwareBuffer:: ...@@ -61,9 +60,9 @@ GpuMemoryBufferImplAndroidHardwareBuffer::
const gfx::Size& size, const gfx::Size& size,
gfx::BufferFormat format, gfx::BufferFormat format,
const DestructionCallback& callback, const DestructionCallback& callback,
const base::SharedMemoryHandle& handle) base::android::ScopedHardwareBufferHandle handle)
: GpuMemoryBufferImpl(id, size, format, callback), : GpuMemoryBufferImpl(id, size, format, callback),
shared_memory_(handle, false) {} hardware_buffer_handle_(std::move(handle)) {}
GpuMemoryBufferImplAndroidHardwareBuffer:: GpuMemoryBufferImplAndroidHardwareBuffer::
~GpuMemoryBufferImplAndroidHardwareBuffer() {} ~GpuMemoryBufferImplAndroidHardwareBuffer() {}
...@@ -88,7 +87,7 @@ GpuMemoryBufferImplAndroidHardwareBuffer::Create( ...@@ -88,7 +87,7 @@ GpuMemoryBufferImplAndroidHardwareBuffer::Create(
return base::WrapUnique(new GpuMemoryBufferImplAndroidHardwareBuffer( return base::WrapUnique(new GpuMemoryBufferImplAndroidHardwareBuffer(
id, size, format, callback, id, size, format, callback,
base::SharedMemoryHandle(buffer, 0, base::UnguessableToken::Create()))); base::android::ScopedHardwareBufferHandle::Adopt(buffer)));
} }
// static // static
...@@ -99,9 +98,11 @@ GpuMemoryBufferImplAndroidHardwareBuffer::CreateFromHandle( ...@@ -99,9 +98,11 @@ GpuMemoryBufferImplAndroidHardwareBuffer::CreateFromHandle(
gfx::BufferFormat format, gfx::BufferFormat format,
gfx::BufferUsage usage, gfx::BufferUsage usage,
const DestructionCallback& callback) { const DestructionCallback& callback) {
DCHECK(base::SharedMemory::IsHandleValid(handle.handle)); DCHECK(handle.android_hardware_buffer);
return base::WrapUnique(new GpuMemoryBufferImplAndroidHardwareBuffer( 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() { bool GpuMemoryBufferImplAndroidHardwareBuffer::Map() {
...@@ -123,8 +124,7 @@ gfx::GpuMemoryBufferHandle GpuMemoryBufferImplAndroidHardwareBuffer::GetHandle() ...@@ -123,8 +124,7 @@ gfx::GpuMemoryBufferHandle GpuMemoryBufferImplAndroidHardwareBuffer::GetHandle()
gfx::GpuMemoryBufferHandle handle; gfx::GpuMemoryBufferHandle handle;
handle.type = gfx::ANDROID_HARDWARE_BUFFER; handle.type = gfx::ANDROID_HARDWARE_BUFFER;
handle.id = id_; handle.id = id_;
handle.handle = shared_memory_.handle(); handle.android_hardware_buffer = hardware_buffer_handle_.get();
return handle; return handle;
} }
...@@ -141,8 +141,7 @@ base::Closure GpuMemoryBufferImplAndroidHardwareBuffer::AllocateForTesting( ...@@ -141,8 +141,7 @@ base::Closure GpuMemoryBufferImplAndroidHardwareBuffer::AllocateForTesting(
AHardwareBuffer_Desc desc = GetBufferDescription(size, format, usage); AHardwareBuffer_Desc desc = GetBufferDescription(size, format, usage);
base::AndroidHardwareBufferCompat::GetInstance().Allocate(&desc, &buffer); base::AndroidHardwareBufferCompat::GetInstance().Allocate(&desc, &buffer);
DCHECK(buffer); DCHECK(buffer);
handle->handle = handle->android_hardware_buffer = buffer;
base::SharedMemoryHandle(buffer, 0, base::UnguessableToken::Create());
return base::DoNothing(); return base::DoNothing();
} }
......
...@@ -5,12 +5,10 @@ ...@@ -5,12 +5,10 @@
#ifndef GPU_IPC_COMMON_GPU_MEMORY_BUFFER_IMPL_ANDROID_HARDWARE_BUFFER_H_ #ifndef GPU_IPC_COMMON_GPU_MEMORY_BUFFER_IMPL_ANDROID_HARDWARE_BUFFER_H_
#define 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/gpu_export.h"
#include "gpu/ipc/common/gpu_memory_buffer_impl.h" #include "gpu/ipc/common/gpu_memory_buffer_impl.h"
extern "C" typedef struct AHardwareBuffer AHardwareBuffer;
namespace gpu { namespace gpu {
// Implementation of GPU memory buffer based on AHardwareBuffer. // Implementation of GPU memory buffer based on AHardwareBuffer.
...@@ -54,9 +52,9 @@ class GPU_EXPORT GpuMemoryBufferImplAndroidHardwareBuffer ...@@ -54,9 +52,9 @@ class GPU_EXPORT GpuMemoryBufferImplAndroidHardwareBuffer
const gfx::Size& size, const gfx::Size& size,
gfx::BufferFormat format, gfx::BufferFormat format,
const DestructionCallback& callback, 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); DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferImplAndroidHardwareBuffer);
}; };
......
...@@ -49,10 +49,8 @@ GpuMemoryBufferFactoryAndroidHardwareBuffer::CreateImageForGpuMemoryBuffer( ...@@ -49,10 +49,8 @@ GpuMemoryBufferFactoryAndroidHardwareBuffer::CreateImageForGpuMemoryBuffer(
// We should only end up in this code path if the memory buffer has a valid // We should only end up in this code path if the memory buffer has a valid
// AHardwareBuffer. // AHardwareBuffer.
DCHECK_EQ(handle.type, gfx::ANDROID_HARDWARE_BUFFER); 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); DCHECK(buffer);
scoped_refptr<gl::GLImageAHardwareBuffer> image( scoped_refptr<gl::GLImageAHardwareBuffer> image(
......
...@@ -41,6 +41,13 @@ ...@@ -41,6 +41,13 @@
#include "ipc/handle_fuchsia.h" #include "ipc/handle_fuchsia.h"
#endif #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 IPC {
namespace { namespace {
...@@ -567,31 +574,76 @@ void ParamTraits<base::FileDescriptor>::Log(const param_type& p, ...@@ -567,31 +574,76 @@ void ParamTraits<base::FileDescriptor>::Log(const param_type& p,
#endif // defined(OS_POSIX) #endif // defined(OS_POSIX)
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
void ParamTraits<base::SharedMemoryHandle::Type>::Write(base::Pickle* m, void ParamTraits<AHardwareBuffer*>::Write(base::Pickle* m,
const param_type& p) { const param_type& p) {
DCHECK(static_cast<int>(p) >= 0 && p <= base::SharedMemoryHandle::Type::LAST); const bool is_valid = p != nullptr;
m->WriteInt(static_cast<int>(p)); 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( bool ParamTraits<AHardwareBuffer*>::Read(const base::Pickle* m,
const base::Pickle* m, base::PickleIterator* iter,
base::PickleIterator* iter, param_type* r) {
param_type* r) { *r = nullptr;
int value;
if (!iter->ReadInt(&value)) bool is_valid;
if (!ReadParam(m, iter, &is_valid))
return false; return false;
if (value < 0 || if (!is_valid)
value > static_cast<int>(base::SharedMemoryHandle::Type::LAST)) return true;
scoped_refptr<base::Pickle::Attachment> tracking_pipe_attachment;
if (!m->ReadAttachment(iter, &tracking_pipe_attachment))
return false; 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; return true;
} }
void ParamTraits<base::SharedMemoryHandle::Type>::Log(const param_type& p, void ParamTraits<AHardwareBuffer*>::Log(const param_type& p, std::string* l) {
std::string* l) { l->append(base::StringPrintf("AHardwareBuffer(%p)", p));
l->append(base::IntToString(static_cast<int>(p)));
} }
#endif #endif // defined(OS_ANDROID)
void ParamTraits<base::SharedMemoryHandle>::Write(base::Pickle* m, void ParamTraits<base::SharedMemoryHandle>::Write(base::Pickle* m,
const param_type& p) { const param_type& p) {
...@@ -614,10 +666,6 @@ void ParamTraits<base::SharedMemoryHandle>::Write(base::Pickle* m, ...@@ -614,10 +666,6 @@ void ParamTraits<base::SharedMemoryHandle>::Write(base::Pickle* m,
WriteParam(m, handle_fuchsia); WriteParam(m, handle_fuchsia);
#else #else
#if defined(OS_ANDROID) #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()); WriteParam(m, p.IsReadOnly());
// Ensure the region is read-only before sending it through IPC. // Ensure the region is read-only before sending it through IPC.
...@@ -676,14 +724,9 @@ bool ParamTraits<base::SharedMemoryHandle>::Read(const base::Pickle* m, ...@@ -676,14 +724,9 @@ bool ParamTraits<base::SharedMemoryHandle>::Read(const base::Pickle* m,
return false; return false;
#else #else
#if defined(OS_ANDROID) #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; bool is_read_only = false;
if (!ReadParam(m, iter, &android_subtype) || if (!ReadParam(m, iter, &is_read_only))
!ReadParam(m, iter, &is_read_only)) {
return false; return false;
}
#endif #endif
scoped_refptr<base::Pickle::Attachment> attachment; scoped_refptr<base::Pickle::Attachment> attachment;
if (!m->ReadAttachment(iter, &attachment)) if (!m->ReadAttachment(iter, &attachment))
...@@ -711,23 +754,18 @@ bool ParamTraits<base::SharedMemoryHandle>::Read(const base::Pickle* m, ...@@ -711,23 +754,18 @@ bool ParamTraits<base::SharedMemoryHandle>::Read(const base::Pickle* m,
#elif defined(OS_FUCHSIA) #elif defined(OS_FUCHSIA)
*r = base::SharedMemoryHandle(handle_fuchsia.get_handle(), *r = base::SharedMemoryHandle(handle_fuchsia.get_handle(),
static_cast<size_t>(size), guid); static_cast<size_t>(size), guid);
#elif defined(OS_ANDROID) #else
*r = base::SharedMemoryHandle( *r = base::SharedMemoryHandle(
android_subtype,
base::FileDescriptor( base::FileDescriptor(
static_cast<internal::PlatformFileAttachment*>(attachment.get()) static_cast<internal::PlatformFileAttachment*>(attachment.get())
->TakePlatformFile(), ->TakePlatformFile(),
true), true),
static_cast<size_t>(size), guid); static_cast<size_t>(size), guid);
#endif
#if defined(OS_ANDROID)
if (is_read_only) if (is_read_only)
r->SetReadOnly(); r->SetReadOnly();
#else
*r = base::SharedMemoryHandle(
base::FileDescriptor(
static_cast<internal::PlatformFileAttachment*>(attachment.get())
->TakePlatformFile(),
true),
static_cast<size_t>(size), guid);
#endif #endif
return true; return true;
......
...@@ -39,6 +39,10 @@ ...@@ -39,6 +39,10 @@
#include "ipc/ipc_param_traits.h" #include "ipc/ipc_param_traits.h"
#include "ipc/ipc_sync_message.h" #include "ipc/ipc_sync_message.h"
#if defined(OS_ANDROID)
#include "base/android/scoped_hardware_buffer_handle.h"
#endif
namespace base { namespace base {
class DictionaryValue; class DictionaryValue;
class FilePath; class FilePath;
...@@ -562,8 +566,8 @@ struct COMPONENT_EXPORT(IPC) ParamTraits<base::SharedMemoryHandle> { ...@@ -562,8 +566,8 @@ struct COMPONENT_EXPORT(IPC) ParamTraits<base::SharedMemoryHandle> {
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
template <> template <>
struct COMPONENT_EXPORT(IPC) ParamTraits<base::SharedMemoryHandle::Type> { struct COMPONENT_EXPORT(IPC) ParamTraits<AHardwareBuffer*> {
typedef base::SharedMemoryHandle::Type param_type; typedef AHardwareBuffer* param_type;
static void Write(base::Pickle* m, const param_type& p); static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m, static bool Read(const base::Pickle* m,
base::PickleIterator* iter, base::PickleIterator* iter,
......
...@@ -43,6 +43,8 @@ component("system") { ...@@ -43,6 +43,8 @@ component("system") {
"message_pipe.h", "message_pipe.h",
"platform_handle.cc", "platform_handle.cc",
"platform_handle.h", "platform_handle.h",
"scope_to_message_pipe.cc",
"scope_to_message_pipe.h",
"simple_watcher.cc", "simple_watcher.cc",
"simple_watcher.h", "simple_watcher.h",
"string_data_pipe_producer.cc", "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") { ...@@ -11,6 +11,7 @@ source_set("tests") {
"file_data_pipe_producer_unittest.cc", "file_data_pipe_producer_unittest.cc",
"handle_signal_tracker_unittest.cc", "handle_signal_tracker_unittest.cc",
"handle_signals_state_unittest.cc", "handle_signals_state_unittest.cc",
"scope_to_message_pipe_unittest.cc",
"simple_watcher_unittest.cc", "simple_watcher_unittest.cc",
"string_data_pipe_producer_unittest.cc", "string_data_pipe_producer_unittest.cc",
"wait_set_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 @@ ...@@ -9,6 +9,8 @@
#if defined(OS_WIN) #if defined(OS_WIN)
#include <windows.h> #include <windows.h>
#elif defined(OS_ANDROID)
#include "base/android/android_hardware_buffer_compat.h"
#endif #endif
namespace gfx { namespace gfx {
...@@ -51,7 +53,11 @@ GpuMemoryBufferHandle CloneHandleForIPC( ...@@ -51,7 +53,11 @@ GpuMemoryBufferHandle CloneHandleForIPC(
gfx::GpuMemoryBufferHandle handle; gfx::GpuMemoryBufferHandle handle;
handle.type = gfx::ANDROID_HARDWARE_BUFFER; handle.type = gfx::ANDROID_HARDWARE_BUFFER;
handle.id = source_handle.id; 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; return handle;
} }
case gfx::IO_SURFACE_BUFFER: case gfx::IO_SURFACE_BUFFER:
......
...@@ -26,6 +26,10 @@ ...@@ -26,6 +26,10 @@
extern "C" typedef struct _ClientBuffer* ClientBuffer; extern "C" typedef struct _ClientBuffer* ClientBuffer;
#if defined(OS_ANDROID)
extern "C" typedef struct AHardwareBuffer AHardwareBuffer;
#endif
namespace gfx { namespace gfx {
class ColorSpace; class ColorSpace;
...@@ -58,6 +62,8 @@ struct GFX_EXPORT GpuMemoryBufferHandle { ...@@ -58,6 +62,8 @@ struct GFX_EXPORT GpuMemoryBufferHandle {
ScopedRefCountedIOSurfaceMachPort mach_port; ScopedRefCountedIOSurfaceMachPort mach_port;
#elif defined(OS_WIN) #elif defined(OS_WIN)
IPC::PlatformFileForTransit dxgi_handle; IPC::PlatformFileForTransit dxgi_handle;
#elif defined(OS_ANDROID)
AHardwareBuffer* android_hardware_buffer = nullptr;
#endif #endif
}; };
......
...@@ -57,6 +57,8 @@ IPC_STRUCT_TRAITS_BEGIN(gfx::GpuMemoryBufferHandle) ...@@ -57,6 +57,8 @@ IPC_STRUCT_TRAITS_BEGIN(gfx::GpuMemoryBufferHandle)
IPC_STRUCT_TRAITS_MEMBER(mach_port) IPC_STRUCT_TRAITS_MEMBER(mach_port)
#elif defined(OS_WIN) #elif defined(OS_WIN)
IPC_STRUCT_TRAITS_MEMBER(dxgi_handle) IPC_STRUCT_TRAITS_MEMBER(dxgi_handle)
#elif defined(OS_ANDROID)
IPC_STRUCT_TRAITS_MEMBER(android_hardware_buffer)
#endif #endif
IPC_STRUCT_TRAITS_END() IPC_STRUCT_TRAITS_END()
......
...@@ -79,6 +79,20 @@ struct NativePixmapHandle { ...@@ -79,6 +79,20 @@ struct NativePixmapHandle {
array<NativePixmapPlane> planes; 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 // gfx::GpuMemoryBufferHandle
struct GpuMemoryBufferHandle { struct GpuMemoryBufferHandle {
// TODO(676224): Use preprocessor to restrict platform-specific members to // TODO(676224): Use preprocessor to restrict platform-specific members to
...@@ -93,4 +107,7 @@ struct GpuMemoryBufferHandle { ...@@ -93,4 +107,7 @@ struct GpuMemoryBufferHandle {
[EnableIf=is_win] [EnableIf=is_win]
handle? dxgi_handle; handle? dxgi_handle;
[EnableIf=is_android]
AHardwareBufferHandle? android_hardware_buffer_handle;
}; };
...@@ -7,6 +7,12 @@ ...@@ -7,6 +7,12 @@
#include "build/build_config.h" #include "build/build_config.h"
#include "mojo/public/cpp/system/platform_handle.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 { namespace mojo {
// static // static
...@@ -54,8 +60,7 @@ mojo::ScopedSharedBufferHandle ...@@ -54,8 +60,7 @@ mojo::ScopedSharedBufferHandle
StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView, StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView,
gfx::GpuMemoryBufferHandle>:: gfx::GpuMemoryBufferHandle>::
shared_memory_handle(const gfx::GpuMemoryBufferHandle& handle) { shared_memory_handle(const gfx::GpuMemoryBufferHandle& handle) {
if (handle.type != gfx::SHARED_MEMORY_BUFFER && if (handle.type != gfx::SHARED_MEMORY_BUFFER)
handle.type != gfx::ANDROID_HARDWARE_BUFFER)
return mojo::ScopedSharedBufferHandle(); return mojo::ScopedSharedBufferHandle();
return mojo::WrapSharedMemoryHandle( return mojo::WrapSharedMemoryHandle(
handle.handle, handle.handle.GetSize(), handle.handle, handle.handle.GetSize(),
...@@ -98,6 +103,38 @@ mojo::ScopedHandle StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView, ...@@ -98,6 +103,38 @@ mojo::ScopedHandle StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView,
} }
#endif #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, bool StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView,
gfx::GpuMemoryBufferHandle>:: gfx::GpuMemoryBufferHandle>::
Read(gfx::mojom::GpuMemoryBufferHandleDataView data, Read(gfx::mojom::GpuMemoryBufferHandleDataView data,
...@@ -105,8 +142,7 @@ bool StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView, ...@@ -105,8 +142,7 @@ bool StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView,
if (!data.ReadType(&out->type) || !data.ReadId(&out->id)) if (!data.ReadType(&out->type) || !data.ReadId(&out->id))
return false; return false;
if (out->type == gfx::SHARED_MEMORY_BUFFER || if (out->type == gfx::SHARED_MEMORY_BUFFER) {
out->type == gfx::ANDROID_HARDWARE_BUFFER) {
mojo::ScopedSharedBufferHandle handle = data.TakeSharedMemoryHandle(); mojo::ScopedSharedBufferHandle handle = data.TakeSharedMemoryHandle();
if (handle.is_valid()) { if (handle.is_valid()) {
MojoResult unwrap_result = mojo::UnwrapSharedMemoryHandle( MojoResult unwrap_result = mojo::UnwrapSharedMemoryHandle(
...@@ -144,6 +180,26 @@ bool StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView, ...@@ -144,6 +180,26 @@ bool StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView,
out->offset = data.offset(); out->offset = data.offset();
out->stride = data.stride(); 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 #endif
return true; return true;
} }
......
...@@ -332,6 +332,11 @@ struct StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView, ...@@ -332,6 +332,11 @@ struct StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView,
const gfx::GpuMemoryBufferHandle& handle); const gfx::GpuMemoryBufferHandle& handle);
#endif #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, static bool Read(gfx::mojom::GpuMemoryBufferHandleDataView data,
gfx::GpuMemoryBufferHandle* handle); 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