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

Commit e64d79e3 authored by Fan Xu's avatar Fan Xu Committed by Android (Google) Code Review
Browse files

Merge "Move BufferNode to libbufferhubservice"

parents 9f15728b 574a6852
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -23,6 +23,13 @@ cc_library_shared {
    ],
    srcs: [
        "BufferHubService.cpp",
        "BufferNode.cpp",
    ],
    header_libs: [
        "libbufferhub_headers",
        "libdvr_headers",
        "libnativewindow_headers",
        "libpdx_headers",
    ],
    shared_libs: [
        "android.frameworks.bufferhub@1.0",
@@ -30,6 +37,7 @@ cc_library_shared {
        "libhidltransport",
        "libhwbinder",
        "liblog",
        "libui",
        "libutils",
    ],
    export_include_dirs: [
@@ -49,6 +57,7 @@ cc_binary {
        "libhidltransport",
        "libhwbinder",
        "liblog",
        "libui",
        "libutils",
    ],
    cflags: [
+100 −0
Original line number Diff line number Diff line
#include <errno.h>

#include <bufferhub/BufferNode.h>
#include <private/dvr/buffer_hub_defs.h>
#include <ui/GraphicBufferAllocator.h>

namespace android {
namespace frameworks {
namespace bufferhub {
namespace V1_0 {
namespace implementation {

void BufferNode::InitializeMetadata() {
    // Using placement new here to reuse shared memory instead of new allocation
    // Initialize the atomic variables to zero.
    dvr::BufferHubDefs::MetadataHeader* metadata_header = metadata_.metadata_header();
    buffer_state_ = new (&metadata_header->buffer_state) std::atomic<uint64_t>(0);
    fence_state_ = new (&metadata_header->fence_state) std::atomic<uint64_t>(0);
    active_clients_bit_mask_ =
            new (&metadata_header->active_clients_bit_mask) std::atomic<uint64_t>(0);
}

// Allocates a new BufferNode.
BufferNode::BufferNode(uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
                       uint64_t usage, size_t user_metadata_size) {
    uint32_t out_stride = 0;
    // graphicBufferId is not used in GraphicBufferAllocator::allocate
    // TODO(b/112338294) After move to the service folder, stop using the
    // hardcoded service name "bufferhub".
    int ret = GraphicBufferAllocator::get().allocate(width, height, format, layer_count, usage,
                                                     const_cast<const native_handle_t**>(
                                                             &buffer_handle_),
                                                     &out_stride,
                                                     /*graphicBufferId=*/0,
                                                     /*requestor=*/"bufferhub");

    if (ret != OK || buffer_handle_ == nullptr) {
        ALOGE("BufferNode::BufferNode: Failed to allocate buffer: %s", strerror(-ret));
        return;
    }

    buffer_desc_.width = width;
    buffer_desc_.height = height;
    buffer_desc_.layers = layer_count;
    buffer_desc_.format = format;
    buffer_desc_.usage = usage;
    buffer_desc_.stride = out_stride;

    metadata_ = BufferHubMetadata::Create(user_metadata_size);
    if (!metadata_.IsValid()) {
        ALOGE("BufferNode::BufferNode: Failed to allocate metadata.");
        return;
    }
    InitializeMetadata();
}

// Free the handle
BufferNode::~BufferNode() {
    if (buffer_handle_ != nullptr) {
        status_t ret = GraphicBufferAllocator::get().free(buffer_handle_);
        if (ret != OK) {
            ALOGE("BufferNode::~BufferNode: Failed to free handle; Got error: %d", ret);
        }
    }
}

uint64_t BufferNode::GetActiveClientsBitMask() const {
    return active_clients_bit_mask_->load(std::memory_order_acquire);
}

uint64_t BufferNode::AddNewActiveClientsBitToMask() {
    uint64_t current_active_clients_bit_mask = GetActiveClientsBitMask();
    uint64_t client_state_mask = 0ULL;
    uint64_t updated_active_clients_bit_mask = 0ULL;
    do {
        client_state_mask = dvr::BufferHubDefs::FindNextAvailableClientStateMask(
                current_active_clients_bit_mask);
        if (client_state_mask == 0ULL) {
            ALOGE("BufferNode::AddNewActiveClientsBitToMask: reached the maximum "
                  "mumber of channels per buffer node: 32.");
            errno = E2BIG;
            return 0ULL;
        }
        updated_active_clients_bit_mask = current_active_clients_bit_mask | client_state_mask;
    } while (!(active_clients_bit_mask_->compare_exchange_weak(current_active_clients_bit_mask,
                                                               updated_active_clients_bit_mask,
                                                               std::memory_order_acq_rel,
                                                               std::memory_order_acquire)));
    return client_state_mask;
}

void BufferNode::RemoveClientsBitFromMask(const uint64_t& value) {
    active_clients_bit_mask_->fetch_and(~value);
}

} // namespace implementation
} // namespace V1_0
} // namespace bufferhub
} // namespace frameworks
} // namespace android
+84 −0
Original line number Diff line number Diff line
#ifndef ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_NODE_H_
#define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_NODE_H_

#include <android/hardware_buffer.h>
#include <ui/BufferHubMetadata.h>

namespace android {
namespace frameworks {
namespace bufferhub {
namespace V1_0 {
namespace implementation {

class BufferNode {
public:
    // Allocates a new BufferNode.
    BufferNode(uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
               uint64_t usage, size_t user_metadata_size);

    ~BufferNode();

    // Returns whether the object holds a valid metadata.
    bool IsValid() const { return metadata_.IsValid(); }

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

    // Accessors of the buffer description and handle
    const native_handle_t* buffer_handle() const { return buffer_handle_; }
    const AHardwareBuffer_Desc& buffer_desc() const { return buffer_desc_; }

    // Accessors of metadata.
    const BufferHubMetadata& metadata() const { return metadata_; }

    // Gets the current value of active_clients_bit_mask in metadata_ with
    // std::memory_order_acquire, so that all previous releases of
    // active_clients_bit_mask from all threads will be returned here.
    uint64_t GetActiveClientsBitMask() const;

    // Find and add a new client_state_mask to active_clients_bit_mask in
    // metadata_.
    // Return the new client_state_mask that is added to active_clients_bit_mask.
    // Return 0ULL if there are already 32 bp clients of the buffer.
    uint64_t AddNewActiveClientsBitToMask();

    // Removes the value from active_clients_bit_mask in metadata_ with
    // std::memory_order_release, so that the change will be visible to any
    // acquire of active_clients_bit_mask_ in any threads after the succeed of
    // this operation.
    void RemoveClientsBitFromMask(const uint64_t& value);

private:
    // Helper method for constructors to initialize atomic metadata header
    // variables in shared memory.
    void InitializeMetadata();

    // Gralloc buffer handles.
    native_handle_t* buffer_handle_;
    AHardwareBuffer_Desc buffer_desc_;

    // Metadata in shared memory.
    BufferHubMetadata metadata_;

    // The following variables are atomic variables in metadata_ that are visible
    // to Bn object and Bp objects. Please find more info in
    // BufferHubDefs::MetadataHeader.

    // buffer_state_ tracks the state of the buffer. Buffer can be in one of these
    // four states: gained, posted, acquired, released.
    std::atomic<uint64_t>* buffer_state_ = nullptr;

    // TODO(b/112012161): add comments to fence_state_.
    std::atomic<uint64_t>* fence_state_ = nullptr;

    // active_clients_bit_mask_ tracks all the bp clients of the buffer. It is the
    // union of all client_state_mask of all bp clients.
    std::atomic<uint64_t>* active_clients_bit_mask_ = nullptr;
};

} // namespace implementation
} // namespace V1_0
} // namespace bufferhub
} // namespace frameworks
} // namespace android

#endif // ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_NODE_H_
+24 −0
Original line number Diff line number Diff line
cc_test {
    name: "BufferNode_test",
    srcs: ["BufferNode_test.cpp"],
    cflags: [
        "-DLOG_TAG=\"BufferNode_test\"",
        "-DTRACE=0",
        "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
    ],
    header_libs: [
        "libbufferhub_headers",
        "libdvr_headers",
        "libnativewindow_headers",
        "libpdx_headers",
    ],
    shared_libs: [
        "libbufferhubservice",
        "libui",
    ],
    static_libs: [
        "libgmock",
    ],
    // TODO(b/117568153): Temporarily opt out using libcrt.
    no_libcrt: true,
}
 No newline at end of file
+110 −0
Original line number Diff line number Diff line
#include <bufferhub/BufferNode.h>
#include <errno.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <ui/GraphicBufferMapper.h>

namespace android {
namespace frameworks {
namespace bufferhub {
namespace V1_0 {
namespace implementation {

namespace {

using testing::NotNull;

const uint32_t kWidth = 640;
const uint32_t kHeight = 480;
const uint32_t kLayerCount = 1;
const uint32_t kFormat = 1;
const uint64_t kUsage = 0;
const size_t kUserMetadataSize = 0;
const size_t kMaxClientsCount = dvr::BufferHubDefs::kMaxNumberOfClients;

class BufferNodeTest : public ::testing::Test {
protected:
    void SetUp() override {
        buffer_node =
                new BufferNode(kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize);
        ASSERT_TRUE(buffer_node->IsValid());
    }

    void TearDown() override {
        if (buffer_node != nullptr) {
            delete buffer_node;
        }
    }

    BufferNode* buffer_node = nullptr;
};

TEST_F(BufferNodeTest, TestCreateBufferNode) {
    EXPECT_EQ(buffer_node->user_metadata_size(), kUserMetadataSize);
    // Test the handle just allocated is good (i.e. able to be imported)
    GraphicBufferMapper& mapper = GraphicBufferMapper::get();
    const native_handle_t* outHandle;
    status_t ret =
            mapper.importBuffer(buffer_node->buffer_handle(), buffer_node->buffer_desc().width,
                                buffer_node->buffer_desc().height,
                                buffer_node->buffer_desc().layers,
                                buffer_node->buffer_desc().format, buffer_node->buffer_desc().usage,
                                buffer_node->buffer_desc().stride, &outHandle);
    EXPECT_EQ(ret, OK);
    EXPECT_THAT(outHandle, NotNull());
}

TEST_F(BufferNodeTest, TestAddNewActiveClientsBitToMask_twoNewClients) {
    uint64_t new_client_state_mask_1 = buffer_node->AddNewActiveClientsBitToMask();
    EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), new_client_state_mask_1);

    // Request and add a new client_state_mask again.
    // Active clients bit mask should be the union of the two new
    // client_state_masks.
    uint64_t new_client_state_mask_2 = buffer_node->AddNewActiveClientsBitToMask();
    EXPECT_EQ(buffer_node->GetActiveClientsBitMask(),
              new_client_state_mask_1 | new_client_state_mask_2);
}

TEST_F(BufferNodeTest, TestAddNewActiveClientsBitToMask_32NewClients) {
    uint64_t new_client_state_mask = 0ULL;
    uint64_t current_mask = 0ULL;
    uint64_t expected_mask = 0ULL;

    for (int i = 0; i < kMaxClientsCount; ++i) {
        new_client_state_mask = buffer_node->AddNewActiveClientsBitToMask();
        EXPECT_NE(new_client_state_mask, 0);
        EXPECT_FALSE(new_client_state_mask & current_mask);
        expected_mask = current_mask | new_client_state_mask;
        current_mask = buffer_node->GetActiveClientsBitMask();
        EXPECT_EQ(current_mask, expected_mask);
    }

    // Method should fail upon requesting for more than maximum allowable clients.
    new_client_state_mask = buffer_node->AddNewActiveClientsBitToMask();
    EXPECT_EQ(new_client_state_mask, 0ULL);
    EXPECT_EQ(errno, E2BIG);
}

TEST_F(BufferNodeTest, TestRemoveActiveClientsBitFromMask) {
    buffer_node->AddNewActiveClientsBitToMask();
    uint64_t current_mask = buffer_node->GetActiveClientsBitMask();
    uint64_t new_client_state_mask = buffer_node->AddNewActiveClientsBitToMask();
    EXPECT_NE(buffer_node->GetActiveClientsBitMask(), current_mask);

    buffer_node->RemoveClientsBitFromMask(new_client_state_mask);
    EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), current_mask);

    // Remove the test_mask again to the active client bit mask should not modify
    // the value of active clients bit mask.
    buffer_node->RemoveClientsBitFromMask(new_client_state_mask);
    EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), current_mask);
}

} // namespace

} // namespace implementation
} // namespace V1_0
} // namespace bufferhub
} // namespace frameworks
} // namespace android
Loading