Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7371fedb authored by Jiwen Cai's avatar Jiwen Cai Committed by Android (Google) Code Review
Browse files

Merge changes from topic "buffer_hub_to_libui"

* changes:
  Format BufferHub{Buffer,Metadata}.{h,cpp} to match libui style
  Move detached buffer to libui
parents 37972d4c ff675b71
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -18,8 +18,8 @@
#include <gui/BufferHubProducer.h>
#include <inttypes.h>
#include <log/log.h>
#include <private/dvr/detached_buffer.h>
#include <system/window.h>
#include <ui/BufferHubBuffer.h>
#include <ui/DetachedBufferHandle.h>

namespace android {
@@ -400,14 +400,14 @@ status_t BufferHubProducer::attachBuffer(int* out_slot, const sp<GraphicBuffer>&
        ALOGE("attachBuffer: DetachedBufferHandle cannot be NULL.");
        return BAD_VALUE;
    }
    auto detached_buffer = DetachedBuffer::Import(std::move(detached_handle->handle()));
    auto detached_buffer = BufferHubBuffer::Import(std::move(detached_handle->handle()));
    if (detached_buffer == nullptr) {
        ALOGE("attachBuffer: DetachedBuffer cannot be NULL.");
        ALOGE("attachBuffer: BufferHubBuffer cannot be NULL.");
        return BAD_VALUE;
    }
    auto status_or_handle = detached_buffer->Promote();
    if (!status_or_handle.ok()) {
        ALOGE("attachBuffer: Failed to promote a DetachedBuffer into a BufferProducer, error=%d.",
        ALOGE("attachBuffer: Failed to promote a BufferHubBuffer into a BufferProducer, error=%d.",
              status_or_handle.error());
        return BAD_VALUE;
    }
+22 −0
Original line number Diff line number Diff line
@@ -54,6 +54,8 @@ cc_library_shared {

    srcs: [
        "ColorSpace.cpp",
        "BufferHubBuffer.cpp",
        "BufferHubMetadata.cpp",
        "DebugUtils.cpp",
        "Fence.cpp",
        "FenceTime.cpp",
@@ -91,6 +93,7 @@ cc_library_shared {
        "libutils",
        "libutilscallstack",
        "liblog",
        "libpdx_default_transport",  // TODO(b/112338294): Remove this once BufferHub moved to use Binder.
    ],

    export_shared_lib_headers: [
@@ -103,8 +106,27 @@ cc_library_shared {
        "libmath",
    ],

    // bufferhub is not used when building libgui for vendors
    target: {
        vendor: {
            exclude_srcs: [
                "BufferHubBuffer.cpp",
                "BufferHubMetadata.cpp",
            ],
            exclude_header_libs: [
                "libbufferhub_headers",
                "libdvr_headers",
            ],
            exclude_shared_libs: [
                "libpdx_default_transport",
            ],
        },
    },

    header_libs: [
        "libbase_headers",
        "libbufferhub_headers",
        "libdvr_headers",
        "libnativebase_headers",
        "libhardware_headers",
        "libui_headers",
+211 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// We would eliminate the clang warnings introduced by libdpx.
// TODO(b/112338294): Remove those once BufferHub moved to use Binder
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wdouble-promotion"
#pragma clang diagnostic ignored "-Wgnu-case-range"
#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
#pragma clang diagnostic ignored "-Winconsistent-missing-destructor-override"
#pragma clang diagnostic ignored "-Wnested-anon-types"
#pragma clang diagnostic ignored "-Wpacked"
#pragma clang diagnostic ignored "-Wshadow"
#pragma clang diagnostic ignored "-Wsign-conversion"
#pragma clang diagnostic ignored "-Wswitch-enum"
#pragma clang diagnostic ignored "-Wundefined-func-template"
#pragma clang diagnostic ignored "-Wunused-template"
#pragma clang diagnostic ignored "-Wweak-vtables"
#include <pdx/default_transport/client_channel.h>
#include <pdx/default_transport/client_channel_factory.h>
#include <pdx/file_handle.h>
#include <private/dvr/bufferhub_rpc.h>
#pragma clang diagnostic pop

#include <ui/BufferHubBuffer.h>
#include <ui/DetachedBufferHandle.h>

#include <poll.h>

using android::dvr::BufferHubMetadata;
using android::dvr::BufferTraits;
using android::dvr::DetachedBufferRPC;
using android::dvr::NativeHandleWrapper;

// TODO(b/112338294): Remove PDX dependencies from libui.
using android::pdx::LocalChannelHandle;
using android::pdx::LocalHandle;
using android::pdx::Status;
using android::pdx::default_transport::ClientChannel;
using android::pdx::default_transport::ClientChannelFactory;

namespace android {

namespace {

// TODO(b/112338294): Remove this string literal after refactoring BufferHub
// to use Binder.
static constexpr char kBufferHubClientPath[] = "system/buffer_hub/client";

} // namespace

BufferHubClient::BufferHubClient() : Client(ClientChannelFactory::Create(kBufferHubClientPath)) {}

BufferHubClient::BufferHubClient(LocalChannelHandle mChannelHandle)
      : Client(ClientChannel::Create(std::move(mChannelHandle))) {}

BufferHubClient::~BufferHubClient() {}

bool BufferHubClient::IsValid() const {
  return IsConnected() && GetChannelHandle().valid();
}

LocalChannelHandle BufferHubClient::TakeChannelHandle() {
    if (IsConnected()) {
        return std::move(GetChannelHandle());
    } else {
        return {};
    }
}

BufferHubBuffer::BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount,
                                 uint32_t format, uint64_t usage, size_t mUserMetadataSize) {
    ATRACE_CALL();
    ALOGD("BufferHubBuffer::BufferHubBuffer: width=%u height=%u layerCount=%u, format=%u "
          "usage=%" PRIx64 " mUserMetadataSize=%zu",
          width, height, layerCount, format, usage, mUserMetadataSize);

    auto status =
            mClient.InvokeRemoteMethod<DetachedBufferRPC::Create>(width, height, layerCount, format,
                                                                  usage, mUserMetadataSize);
    if (!status) {
        ALOGE("BufferHubBuffer::BufferHubBuffer: Failed to create detached buffer: %s",
              status.GetErrorMessage().c_str());
        mClient.Close(-status.error());
    }

    const int ret = ImportGraphicBuffer();
    if (ret < 0) {
        ALOGE("BufferHubBuffer::BufferHubBuffer: Failed to import buffer: %s", strerror(-ret));
        mClient.Close(ret);
    }
}

BufferHubBuffer::BufferHubBuffer(LocalChannelHandle mChannelHandle)
      : mClient(std::move(mChannelHandle)) {
    const int ret = ImportGraphicBuffer();
    if (ret < 0) {
        ALOGE("BufferHubBuffer::BufferHubBuffer: Failed to import buffer: %s", strerror(-ret));
        mClient.Close(ret);
    }
}

int BufferHubBuffer::ImportGraphicBuffer() {
    ATRACE_CALL();

    auto status = mClient.InvokeRemoteMethod<DetachedBufferRPC::Import>();
    if (!status) {
        ALOGE("BufferHubBuffer::BufferHubBuffer: Failed to import GraphicBuffer: %s",
              status.GetErrorMessage().c_str());
        return -status.error();
    }

    BufferTraits<LocalHandle> bufferTraits = status.take();
    if (bufferTraits.id() < 0) {
        ALOGE("BufferHubBuffer::BufferHubBuffer: Received an invalid id!");
        return -EIO;
    }

    // Stash the buffer id to replace the value in mId.
    const int bufferId = bufferTraits.id();

    // Import the metadata.
    mMetadata = BufferHubMetadata::Import(bufferTraits.take_metadata_handle());

    if (!mMetadata.IsValid()) {
        ALOGE("BufferHubBuffer::ImportGraphicBuffer: invalid metadata.");
        return -ENOMEM;
    }

    if (mMetadata.metadata_size() != bufferTraits.metadata_size()) {
        ALOGE("BufferHubBuffer::ImportGraphicBuffer: metadata buffer too small: "
              "%zu, expected: %" PRIu64 ".",
              mMetadata.metadata_size(), bufferTraits.metadata_size());
        return -ENOMEM;
    }

    size_t metadataSize = static_cast<size_t>(bufferTraits.metadata_size());
    if (metadataSize < dvr::BufferHubDefs::kMetadataHeaderSize) {
        ALOGE("BufferHubBuffer::ImportGraphicBuffer: metadata too small: %zu", metadataSize);
        return -EINVAL;
    }

    // Import the buffer: We only need to hold on the native_handle_t here so that
    // GraphicBuffer instance can be created in future.
    mBufferHandle = bufferTraits.take_buffer_handle();

    // If all imports succeed, replace the previous buffer and id.
    mId = bufferId;
    mBfferStateBit = bufferTraits.buffer_state_bit();

    // TODO(b/112012161) Set up shared fences.
    ALOGD("BufferHubBuffer::ImportGraphicBuffer: id=%d, buffer_state=%" PRIx64 ".", id(),
          mMetadata.metadata_header()->buffer_state.load(std::memory_order_acquire));
    return 0;
}

int BufferHubBuffer::Poll(int timeoutMs) {
    ATRACE_CALL();

    pollfd p = {mClient.event_fd(), POLLIN, 0};
    return poll(&p, 1, timeoutMs);
}

Status<LocalChannelHandle> BufferHubBuffer::Promote() {
    ATRACE_CALL();

    // TODO(b/112338294) remove after migrate producer buffer to binder
    ALOGW("BufferHubBuffer::Promote: not supported operation during migration");
    return {};

    ALOGD("BufferHubBuffer::Promote: id=%d.", mId);

    auto statusOrHandle = mClient.InvokeRemoteMethod<DetachedBufferRPC::Promote>();
    if (statusOrHandle.ok()) {
        // Invalidate the buffer.
        mBufferHandle = {};
    } else {
        ALOGE("BufferHubBuffer::Promote: Failed to promote buffer (id=%d): %s.", mId,
              statusOrHandle.GetErrorMessage().c_str());
    }
    return statusOrHandle;
}

Status<LocalChannelHandle> BufferHubBuffer::Duplicate() {
    ATRACE_CALL();
    ALOGD("BufferHubBuffer::Duplicate: id=%d.", mId);

    auto statusOrHandle = mClient.InvokeRemoteMethod<DetachedBufferRPC::Duplicate>();

    if (!statusOrHandle.ok()) {
        ALOGE("BufferHubBuffer::Duplicate: Failed to duplicate buffer (id=%d): %s.", mId,
              statusOrHandle.GetErrorMessage().c_str());
    }
    return statusOrHandle;
}

} // namespace android
+105 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <errno.h>
#include <sys/mman.h>

#include <cutils/ashmem.h>
#include <log/log.h>
#include <ui/BufferHubMetadata.h>

namespace android {
namespace dvr {

namespace {

static const int kAshmemProt = PROT_READ | PROT_WRITE;

} // namespace

using BufferHubDefs::kMetadataHeaderSize;
using BufferHubDefs::MetadataHeader;

/* static */
BufferHubMetadata BufferHubMetadata::Create(size_t userMetadataSize) {
    // The size the of metadata buffer is used as the "width" parameter during allocation. Thus it
    // cannot overflow uint32_t.
    if (userMetadataSize >= (std::numeric_limits<uint32_t>::max() - kMetadataHeaderSize)) {
        ALOGE("BufferHubMetadata::Create: metadata size too big: %zu.", userMetadataSize);
        return {};
    }

    const size_t metadataSize = userMetadataSize + kMetadataHeaderSize;
    int fd = ashmem_create_region(/*name=*/"BufferHubMetadata", metadataSize);
    if (fd < 0) {
        ALOGE("BufferHubMetadata::Create: failed to create ashmem region.");
        return {};
    }

    // Hand over the ownership of the fd to a pdx::LocalHandle immediately after the successful
    // return of ashmem_create_region. The ashmemHandle is going to own the fd and to prevent fd
    // leaks during error handling.
    pdx::LocalHandle ashmemHandle{fd};

    if (ashmem_set_prot_region(ashmemHandle.Get(), kAshmemProt) != 0) {
        ALOGE("BufferHubMetadata::Create: failed to set protect region.");
        return {};
    }

    return BufferHubMetadata::Import(std::move(ashmemHandle));
}

/* static */
BufferHubMetadata BufferHubMetadata::Import(pdx::LocalHandle ashmemHandle) {
    if (!ashmem_valid(ashmemHandle.Get())) {
        ALOGE("BufferHubMetadata::Import: invalid ashmem fd.");
        return {};
    }

    size_t metadataSize = static_cast<size_t>(ashmem_get_size_region(ashmemHandle.Get()));
    size_t userMetadataSize = metadataSize - kMetadataHeaderSize;

    // Note that here the buffer state is mapped from shared memory as an atomic object. The
    // std::atomic's constructor will not be called so that the original value stored in the memory
    // region can be preserved.
    auto metadataHeader = static_cast<MetadataHeader*>(mmap(nullptr, metadataSize, kAshmemProt,
                                                            MAP_SHARED, ashmemHandle.Get(),
                                                            /*offset=*/0));
    if (metadataHeader == nullptr) {
        ALOGE("BufferHubMetadata::Import: failed to map region.");
        return {};
    }

    return BufferHubMetadata(userMetadataSize, std::move(ashmemHandle), metadataHeader);
}

BufferHubMetadata::BufferHubMetadata(size_t userMetadataSize, pdx::LocalHandle ashmemHandle,
                                     MetadataHeader* metadataHeader)
      : mUserMetadataSize(userMetadataSize),
        mAshmemHandle(std::move(ashmemHandle)),
        mMetadataHeader(metadataHeader) {}

BufferHubMetadata::~BufferHubMetadata() {
    if (mMetadataHeader != nullptr) {
        int ret = munmap(mMetadataHeader, metadata_size());
        ALOGE_IF(ret != 0,
                 "BufferHubMetadata::~BufferHubMetadata: failed to unmap ashmem, error=%d.", errno);
        mMetadataHeader = nullptr;
    }
}

} // namespace dvr
} // namespace android
+149 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ANDROID_BUFFER_HUB_BUFFER_H_
#define ANDROID_BUFFER_HUB_BUFFER_H_

// We would eliminate the clang warnings introduced by libdpx.
// TODO(b/112338294): Remove those once BufferHub moved to use Binder
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wdouble-promotion"
#pragma clang diagnostic ignored "-Wgnu-case-range"
#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
#pragma clang diagnostic ignored "-Winconsistent-missing-destructor-override"
#pragma clang diagnostic ignored "-Wnested-anon-types"
#pragma clang diagnostic ignored "-Wpacked"
#pragma clang diagnostic ignored "-Wshadow"
#pragma clang diagnostic ignored "-Wsign-conversion"
#pragma clang diagnostic ignored "-Wswitch-enum"
#pragma clang diagnostic ignored "-Wundefined-func-template"
#pragma clang diagnostic ignored "-Wunused-template"
#pragma clang diagnostic ignored "-Wweak-vtables"
#include <pdx/client.h>
#include <private/dvr/buffer_hub_defs.h>
#include <private/dvr/native_handle_wrapper.h>
#pragma clang diagnostic pop

#include <ui/BufferHubMetadata.h>

namespace android {

class BufferHubClient : public pdx::Client {
public:
    BufferHubClient();
    virtual ~BufferHubClient();
    explicit BufferHubClient(pdx::LocalChannelHandle mChannelHandle);

    bool IsValid() const;
    pdx::LocalChannelHandle TakeChannelHandle();

    using pdx::Client::Close;
    using pdx::Client::event_fd;
    using pdx::Client::GetChannel;
    using pdx::Client::InvokeRemoteMethod;
};

class BufferHubBuffer {
public:
    // Allocates a standalone BufferHubBuffer not associated with any producer consumer set.
    static std::unique_ptr<BufferHubBuffer> Create(uint32_t width, uint32_t height,
                                                   uint32_t layerCount, uint32_t format,
                                                   uint64_t usage, size_t mUserMetadataSize) {
        return std::unique_ptr<BufferHubBuffer>(
                new BufferHubBuffer(width, height, layerCount, format, usage, mUserMetadataSize));
    }

    // Imports the given channel handle to a BufferHubBuffer, taking ownership.
    static std::unique_ptr<BufferHubBuffer> Import(pdx::LocalChannelHandle mChannelHandle) {
        return std::unique_ptr<BufferHubBuffer>(new BufferHubBuffer(std::move(mChannelHandle)));
    }

    BufferHubBuffer(const BufferHubBuffer&) = delete;
    void operator=(const BufferHubBuffer&) = delete;

    // Gets ID of the buffer client. All BufferHubBuffer clients derived from the same buffer in
    // bufferhubd share the same buffer id.
    int id() const { return mId; }

    const native_handle_t* DuplicateHandle() { return mBufferHandle.DuplicateHandle(); }

    // Returns the current value of MetadataHeader::buffer_state.
    uint64_t buffer_state() {
        return mMetadata.metadata_header()->buffer_state.load(std::memory_order_acquire);
    }

    // A state mask which is unique to a buffer hub client among all its siblings sharing the same
    // concrete graphic buffer.
    uint64_t buffer_state_bit() const { return mBfferStateBit; }

    size_t user_metadata_size() const { return mMetadata.user_metadata_size(); }

    // Returns true if the buffer holds an open PDX channels towards bufferhubd.
    bool IsConnected() const { return mClient.IsValid(); }

    // Returns true if the buffer holds an valid native buffer handle that's availble for the client
    // to read from and/or write into.
    bool IsValid() const { return mBufferHandle.IsValid(); }

    // Returns the event mask for all the events that are pending on this buffer (see sys/poll.h for
    // all possible bits).
    pdx::Status<int> GetEventMask(int events) {
        if (auto* channel = mClient.GetChannel()) {
            return channel->GetEventMask(events);
        } else {
            return pdx::ErrorStatus(EINVAL);
        }
    }

    // Polls the fd for |timeoutMs| milliseconds (-1 for infinity).
    int Poll(int timeoutMs);

    // Promotes a BufferHubBuffer to become a ProducerBuffer. Once promoted the BufferHubBuffer
    // channel will be closed automatically on successful IPC return. Further IPCs towards this
    // channel will return error.
    pdx::Status<pdx::LocalChannelHandle> Promote();

    // Creates a BufferHubBuffer client from an existing one. The new client will
    // share the same underlying gralloc buffer and ashmem region for metadata.
    pdx::Status<pdx::LocalChannelHandle> Duplicate();

private:
    BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount, uint32_t format,
                    uint64_t usage, size_t mUserMetadataSize);

    BufferHubBuffer(pdx::LocalChannelHandle mChannelHandle);

    int ImportGraphicBuffer();

    // Global id for the buffer that is consistent across processes.
    int mId;
    uint64_t mBfferStateBit;

    // Wrapps the gralloc buffer handle of this buffer.
    dvr::NativeHandleWrapper<pdx::LocalHandle> mBufferHandle;

    // An ashmem-based metadata object. The same shared memory are mapped to the
    // bufferhubd daemon and all buffer clients.
    dvr::BufferHubMetadata mMetadata;

    // PDX backend.
    BufferHubClient mClient;
};

} // namespace android

#endif // ANDROID_BUFFER_HUB_BUFFER_H_
Loading