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

Commit 574a6852 authored by Fan Xu's avatar Fan Xu
Browse files

Move BufferNode to libbufferhubservice

BufferNode is a server-side class and should be located in the service
folder. Also, making the old bufferhubd service depending on
libbufferhubservice could solve the dependency problem.

Test: "atest buffer_node-test", "atest buffer_hub-test" passed.
Bug: 118893702
Change-Id: I5fad37d3c0475d6cd4f4e0ed17f911b6777a6868
parent 6894160b
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