diff options
author | 2018-11-06 15:46:44 -0800 | |
---|---|---|
committer | 2018-11-14 10:30:23 -0800 | |
commit | 18d90eaf05d8b3a21a68d84ebf23ea2326067aad (patch) | |
tree | 38758cab65d3d634dd2c7fba1c2eb15c81a36fc3 | |
parent | 1029443fa64b7f66c06188431c81745d7a14bacb (diff) |
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
-rw-r--r-- | libs/ui/tests/BufferHubBuffer_test.cpp | 28 | ||||
-rw-r--r-- | services/bufferhub/Android.bp | 2 | ||||
-rw-r--r-- | services/bufferhub/BufferClient.cpp | 30 | ||||
-rw-r--r-- | services/bufferhub/BufferHubService.cpp | 22 | ||||
-rw-r--r-- | services/bufferhub/include/bufferhub/BufferClient.h | 10 | ||||
-rw-r--r-- | services/bufferhub/include/bufferhub/BufferHubService.h | 17 |
6 files changed, 102 insertions, 7 deletions
diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp index 143335a091..6af8033e76 100644 --- a/libs/ui/tests/BufferHubBuffer_test.cpp +++ b/libs/ui/tests/BufferHubBuffer_test.cpp @@ -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 diff --git a/services/bufferhub/Android.bp b/services/bufferhub/Android.bp index 871561f171..8b4333342d 100644 --- a/services/bufferhub/Android.bp +++ b/services/bufferhub/Android.bp @@ -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", diff --git a/services/bufferhub/BufferClient.cpp b/services/bufferhub/BufferClient.cpp index b3662b265b..37fd75fe80 100644 --- a/services/bufferhub/BufferClient.cpp +++ b/services/bufferhub/BufferClient.cpp @@ -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(); } diff --git a/services/bufferhub/BufferHubService.cpp b/services/bufferhub/BufferHubService.cpp index b72b556c6e..3bfd9cbe7e 100644 --- a/services/bufferhub/BufferHubService.cpp +++ b/services/bufferhub/BufferHubService.cpp @@ -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 diff --git a/services/bufferhub/include/bufferhub/BufferClient.h b/services/bufferhub/include/bufferhub/BufferClient.h index c6eb791b1f..5456ec33f0 100644 --- a/services/bufferhub/include/bufferhub/BufferClient.h +++ b/services/bufferhub/include/bufferhub/BufferClient.h @@ -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; }; diff --git a/services/bufferhub/include/bufferhub/BufferHubService.h b/services/bufferhub/include/bufferhub/BufferHubService.h index 1bbd807069..dbbee8fccf 100644 --- a/services/bufferhub/include/bufferhub/BufferHubService.h +++ b/services/bufferhub/include/bufferhub/BufferHubService.h @@ -18,6 +18,7 @@ #define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H #include <mutex> +#include <random> #include <android/frameworks/bufferhub/1.0/IBufferHub.h> #include <bufferhub/BufferClient.h> @@ -29,9 +30,9 @@ namespace bufferhub { namespace V1_0 { namespace implementation { -using ::android::hardware::hidl_handle; -using ::android::hardware::Return; -using ::android::hardware::graphics::common::V1_2::HardwareBufferDescription; +using hardware::hidl_handle; +using hardware::Return; +using hardware::graphics::common::V1_2::HardwareBufferDescription; class BufferHubService : public IBufferHub { public: @@ -40,10 +41,20 @@ public: allocateBuffer_cb _hidl_cb) override; Return<void> importBuffer(const hidl_handle& nativeHandle, importBuffer_cb _hidl_cb) override; + // Non-binder functions + // Internal help function for IBufferClient::duplicate. + hidl_handle registerToken(const BufferClient* client); + private: // List of active BufferClient for bookkeeping. std::mutex mClientListMutex; std::vector<sp<BufferClient>> mClientList GUARDED_BY(mClientListMutex); + + // TODO(b/118180214): use a more secure implementation + std::mt19937 mTokenEngine; + // The mapping from token to the client creates it. + std::mutex mTokenMapMutex; + std::map<uint32_t, const BufferClient*> mTokenMap GUARDED_BY(mTokenMapMutex); }; } // namespace implementation |