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

Commit 18d90eaf authored by Fan Xu's avatar Fan Xu
Browse files

Implement duplicate buffer

Allow BufferClient to generate a opaque token in hidl_handle (i.e.
native_handle_t) format that could be used for IBufferHub::import.

The service will keep a mapping from token to client. Token comparison
is handled in BufferHubService.cpp, as it's opaque to the users.

Test: BufferHubBuffer_test (passed)
Bug: 118614157
Change-Id: Ie2b0b650dba90fe2ed2f8091dd88acb9768f261f
parent 1029443f
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -144,5 +144,33 @@ TEST_F(BufferHubBufferTest, AllocateBuffer) {
    EXPECT_TRUE(bufferHub->allocateBuffer(desc, kUserMetadataSize, callback).isOk());
}

TEST_F(BufferHubBufferTest, DuplicateBuffer) {
    // TODO(b/116681016): directly test on BufferHubBuffer instead of the service.
    sp<IBufferHub> bufferhub = IBufferHub::getService();
    ASSERT_NE(nullptr, bufferhub.get());

    // Stride is an output, rfu0 and rfu1 are reserved data slot for future use.
    AHardwareBuffer_Desc aDesc = {kWidth, kHeight,        kLayerCount,  kFormat,
                                  kUsage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL};
    HardwareBufferDescription desc;
    memcpy(&desc, &aDesc, sizeof(HardwareBufferDescription));

    sp<IBufferClient> client;
    IBufferHub::allocateBuffer_cb alloc_cb = [&](const auto& outClient, const auto& status) {
        ASSERT_EQ(status, BufferHubStatus::NO_ERROR);
        ASSERT_NE(nullptr, outClient.get());
        client = outClient;
    };
    ASSERT_TRUE(bufferhub->allocateBuffer(desc, kUserMetadataSize, alloc_cb).isOk());

    IBufferClient::duplicate_cb dup_cb = [](const auto& token, const auto& status) {
        ASSERT_EQ(status, BufferHubStatus::NO_ERROR);
        ASSERT_NE(token.getNativeHandle(), nullptr);
        EXPECT_EQ(token->numInts, 1);
        EXPECT_EQ(token->numFds, 0);
    };
    EXPECT_TRUE(client->duplicate(dup_cb).isOk());
}

} // namespace
} // namespace android
+2 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ cc_library_shared {
    ],
    shared_libs: [
        "android.frameworks.bufferhub@1.0",
        "libcutils",
        "libhidlbase",
        "libhidltransport",
        "libhwbinder",
@@ -61,6 +62,7 @@ cc_binary {
    shared_libs: [
        "android.frameworks.bufferhub@1.0",
        "libbufferhubservice",
        "libcutils",
        "libhidltransport",
        "libhwbinder",
        "liblog",
+28 −2
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */

#include <bufferhub/BufferClient.h>
#include <bufferhub/BufferHubService.h>
#include <hidl/HidlSupport.h>

namespace android {
@@ -26,9 +27,34 @@ namespace implementation {
using hardware::hidl_handle;
using hardware::Void;

BufferClient* BufferClient::create(BufferHubService* service,
                                   const std::shared_ptr<BufferNode>& node) {
    if (!service) {
        ALOGE("%s: service cannot be nullptr.", __FUNCTION__);
        return nullptr;
    } else if (!node) {
        ALOGE("%s: node cannot be nullptr.", __FUNCTION__);
        return nullptr;
    }
    return new BufferClient(service, node);
}

Return<void> BufferClient::duplicate(duplicate_cb _hidl_cb) {
    // TODO(b/118614157): implement token generation and registration
    _hidl_cb(/*token=*/hidl_handle(), /*status=*/BufferHubStatus::NO_ERROR);
    if (!mBufferNode) {
        // Should never happen
        ALOGE("%s: node is missing.", __FUNCTION__);
        _hidl_cb(/*token=*/hidl_handle(), /*status=*/BufferHubStatus::BUFFER_FREED);
        return Void();
    }

    sp<BufferHubService> service = mService.promote();
    if (service == nullptr) {
        // Should never happen. Kill the process.
        LOG_FATAL("%s: service died.", __FUNCTION__);
    }

    const hidl_handle token = service->registerToken(this);
    _hidl_cb(/*token=*/token, /*status=*/BufferHubStatus::NO_ERROR);
    return Void();
}

+21 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#include <android/hardware_buffer.h>
#include <bufferhub/BufferHubService.h>
#include <cutils/native_handle.h>
#include <log/log.h>

namespace android {
@@ -41,7 +42,7 @@ Return<void> BufferHubService::allocateBuffer(const HardwareBufferDescription& d
        return Void();
    }

    sp<BufferClient> client = new BufferClient(node);
    sp<BufferClient> client = BufferClient::create(this, node);
    // Add it to list for bookkeeping and dumpsys.
    std::lock_guard<std::mutex> lock(mClientListMutex);
    mClientList.push_back(client);
@@ -57,6 +58,25 @@ Return<void> BufferHubService::importBuffer(const hidl_handle& /*nativeHandle*/,
    return Void();
}

hidl_handle BufferHubService::registerToken(const BufferClient* client) {
    uint32_t token;
    std::lock_guard<std::mutex> lock(mTokenMapMutex);
    do {
        token = mTokenEngine();
    } while (mTokenMap.find(token) != mTokenMap.end());

    // native_handle_t use int[], so here need one slots to fit in uint32_t
    native_handle_t* handle = native_handle_create(/*numFds=*/0, /*numInts=*/1);
    handle->data[0] = token;

    // returnToken owns the native_handle_t* thus doing lifecycle management
    hidl_handle returnToken;
    returnToken.setTo(handle, /*shoudOwn=*/true);

    mTokenMap.emplace(token, client);
    return returnToken;
}

} // namespace implementation
} // namespace V1_0
} // namespace bufferhub
+9 −1
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
#ifndef ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_CLIENT_H
#define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_CLIENT_H

#include <mutex>

#include <android/frameworks/bufferhub/1.0/IBufferClient.h>
#include <bufferhub/BufferNode.h>

@@ -26,6 +28,7 @@ namespace bufferhub {
namespace V1_0 {
namespace implementation {

using hardware::hidl_handle;
using hardware::Return;

// Forward declaration to avoid circular dependency
@@ -35,11 +38,16 @@ class BufferClient : public IBufferClient {
public:
    // Creates a server-side buffer client from an existing BufferNode. Note that
    // this funciton takes ownership of the shared_ptr.
    explicit BufferClient(const std::shared_ptr<BufferNode>& node) : mBufferNode(node){};
    // Returns a raw pointer to the BufferClient on success, nullptr on failure.
    static BufferClient* create(BufferHubService* service, const std::shared_ptr<BufferNode>& node);

    Return<void> duplicate(duplicate_cb _hidl_cb) override;

private:
    BufferClient(wp<BufferHubService> service, const std::shared_ptr<BufferNode>& node)
          : mService(service), mBufferNode(node){};

    wp<BufferHubService> mService;
    std::shared_ptr<BufferNode> mBufferNode;
};

Loading