diff options
| -rw-r--r-- | libs/vr/libbufferhub/buffer_client_impl.cpp | 34 | ||||
| -rw-r--r-- | libs/vr/libbufferhub/include/private/dvr/IBufferClient.h | 4 | ||||
| -rw-r--r-- | services/vr/bufferhubd/Android.bp | 1 | ||||
| -rw-r--r-- | services/vr/bufferhubd/IBufferHub.cpp | 2 | ||||
| -rw-r--r-- | services/vr/bufferhubd/buffer_client.cpp | 18 | ||||
| -rw-r--r-- | services/vr/bufferhubd/buffer_hub_binder.cpp | 12 | ||||
| -rw-r--r-- | services/vr/bufferhubd/include/private/dvr/buffer_client.h | 16 | ||||
| -rw-r--r-- | services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h | 16 | ||||
| -rw-r--r-- | services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp | 17 |
9 files changed, 114 insertions, 6 deletions
diff --git a/libs/vr/libbufferhub/buffer_client_impl.cpp b/libs/vr/libbufferhub/buffer_client_impl.cpp index 6bef98a37a..30cbb9fdd7 100644 --- a/libs/vr/libbufferhub/buffer_client_impl.cpp +++ b/libs/vr/libbufferhub/buffer_client_impl.cpp @@ -10,6 +10,8 @@ class BpBufferClient : public BpInterface<IBufferClient> { : BpInterface<IBufferClient>(impl) {} bool isValid() override; + + status_t duplicate(uint64_t* outToken) override; }; IMPLEMENT_META_INTERFACE(BufferClient, "android.dvr.IBufferClient"); @@ -17,6 +19,7 @@ IMPLEMENT_META_INTERFACE(BufferClient, "android.dvr.IBufferClient"); // Transaction code enum { IS_VALID = IBinder::FIRST_CALL_TRANSACTION, + DUPLICATE, }; bool BpBufferClient::isValid() { @@ -38,13 +41,42 @@ bool BpBufferClient::isValid() { } } +status_t BpBufferClient::duplicate(uint64_t* outToken) { + Parcel data, reply; + status_t ret = + data.writeInterfaceToken(IBufferClient::getInterfaceDescriptor()); + if (ret != NO_ERROR) { + ALOGE("BpBufferClient::duplicate: failed to write into parcel; errno=%d", + ret); + return ret; + } + + ret = remote()->transact(DUPLICATE, data, &reply); + if (ret == NO_ERROR) { + *outToken = reply.readUint64(); + return NO_ERROR; + } else { + ALOGE("BpBufferClient::duplicate: failed to transact; errno=%d", ret); + return ret; + } +} + status_t BnBufferClient::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch (code) { case IS_VALID: { CHECK_INTERFACE(IBufferClient, data, reply); return reply->writeBool(isValid()); - } break; + } + case DUPLICATE: { + CHECK_INTERFACE(IBufferClient, data, reply); + uint64_t token = 0; + status_t ret = duplicate(&token); + if (ret != NO_ERROR) { + return ret; + } + return reply->writeUint64(token); + } default: // Should not reach except binder defined transactions such as dumpsys return BBinder::onTransact(code, data, reply, flags); diff --git a/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h b/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h index 03f2d95b28..31bf79dae3 100644 --- a/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h +++ b/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h @@ -14,6 +14,10 @@ class IBufferClient : public IInterface { // Checks if the buffer node is valid. virtual bool isValid() = 0; + + // Duplicates the client. Token_out will be set to a new token when succeed, + // and not changed when failed. + virtual status_t duplicate(uint64_t* outToken) = 0; }; // BnInterface for IBufferClient. Should only be created in bufferhub service. diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp index c35ddd42e2..ea9bb1fe43 100644 --- a/services/vr/bufferhubd/Android.bp +++ b/services/vr/bufferhubd/Android.bp @@ -29,6 +29,7 @@ cc_library_static { name: "libbufferhubd", srcs: [ "buffer_channel.cpp", + "buffer_client.cpp", "buffer_hub.cpp", "buffer_hub_binder.cpp", "buffer_node.cpp", diff --git a/services/vr/bufferhubd/IBufferHub.cpp b/services/vr/bufferhubd/IBufferHub.cpp index 2f39e4176a..a2c0a4a579 100644 --- a/services/vr/bufferhubd/IBufferHub.cpp +++ b/services/vr/bufferhubd/IBufferHub.cpp @@ -64,7 +64,7 @@ status_t BnBufferHub::onTransact(uint32_t code, const Parcel& data, sp<IBufferClient> ret = createBuffer(width, height, layer_count, format, usage, user_metadata_size); return reply->writeStrongBinder(IInterface::asBinder(ret)); - } break; + } default: // Should not reach except binder defined transactions such as dumpsys return BBinder::onTransact(code, data, reply, flags); diff --git a/services/vr/bufferhubd/buffer_client.cpp b/services/vr/bufferhubd/buffer_client.cpp new file mode 100644 index 0000000000..f14faf73c0 --- /dev/null +++ b/services/vr/bufferhubd/buffer_client.cpp @@ -0,0 +1,18 @@ +#include <private/dvr/buffer_client.h> +#include <private/dvr/buffer_hub_binder.h> + +namespace android { +namespace dvr { + +status_t BufferClient::duplicate(uint64_t* outToken) { + if (!buffer_node_) { + // Should never happen + ALOGE("BufferClient::duplicate: node is missing."); + return UNEXPECTED_NULL; + } + return service_->registerToken(std::weak_ptr<BufferNode>(buffer_node_), + outToken); +} + +} // namespace dvr +} // namespace android
\ No newline at end of file diff --git a/services/vr/bufferhubd/buffer_hub_binder.cpp b/services/vr/bufferhubd/buffer_hub_binder.cpp index f8a9758de4..7b0dc9a74d 100644 --- a/services/vr/bufferhubd/buffer_hub_binder.cpp +++ b/services/vr/bufferhubd/buffer_hub_binder.cpp @@ -65,13 +65,23 @@ status_t BufferHubBinderService::dump(int fd, const Vector<String16>& args) { return NO_ERROR; } +status_t BufferHubBinderService::registerToken( + const std::weak_ptr<BufferNode> node, uint64_t* outToken) { + do { + *outToken = token_engine_(); + } while (token_map_.find(*outToken) != token_map_.end()); + + token_map_.emplace(*outToken, node); + return NO_ERROR; +} + sp<IBufferClient> BufferHubBinderService::createBuffer( uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format, uint64_t usage, uint64_t user_metadata_size) { std::shared_ptr<BufferNode> node = std::make_shared<BufferNode>( width, height, layer_count, format, usage, user_metadata_size); - sp<BufferClient> client = new BufferClient(node); + sp<BufferClient> client = new BufferClient(node, this); // Add it to list for bookkeeping and dumpsys. client_list_.push_back(client); diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_client.h b/services/vr/bufferhubd/include/private/dvr/buffer_client.h index 20d51ee0ee..d79ec0a38d 100644 --- a/services/vr/bufferhubd/include/private/dvr/buffer_client.h +++ b/services/vr/bufferhubd/include/private/dvr/buffer_client.h @@ -7,19 +7,31 @@ namespace android { namespace dvr { +// Forward declaration to avoid circular dependency +class BufferHubBinderService; + class BufferClient : public BnBufferClient { public: // Creates a server-side buffer client from an existing BufferNode. Note that // this funciton takes ownership of the shared_ptr. - explicit BufferClient(std::shared_ptr<BufferNode> node) - : buffer_node_(std::move(node)){}; + explicit BufferClient(std::shared_ptr<BufferNode> node, + BufferHubBinderService* service) + : service_(service), buffer_node_(std::move(node)){}; // Binder IPC functions bool isValid() override { return buffer_node_ ? buffer_node_->IsValid() : false; }; + status_t duplicate(uint64_t* outToken) override; + private: + // Hold a pointer to the service to bypass binder interface, as BufferClient + // and the service will be in the same process. Also, since service owns + // Client, if service dead the clients will be destroyed, so this pointer is + // guaranteed to be valid. + BufferHubBinderService* service_; + std::shared_ptr<BufferNode> buffer_node_; }; diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h b/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h index 9064d87dd3..6c74cc4e61 100644 --- a/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h +++ b/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h @@ -1,12 +1,15 @@ #ifndef ANDROID_DVR_BUFFER_HUB_BINDER_H #define ANDROID_DVR_BUFFER_HUB_BINDER_H +#include <random> +#include <unordered_map> #include <vector> #include <binder/BinderService.h> #include <private/dvr/IBufferHub.h> #include <private/dvr/buffer_client.h> #include <private/dvr/buffer_hub.h> +#include <private/dvr/buffer_node.h> namespace android { namespace dvr { @@ -15,10 +18,15 @@ class BufferHubBinderService : public BinderService<BufferHubBinderService>, public BnBufferHub { public: static status_t start(const std::shared_ptr<BufferHubService>& pdx_service); - // Dump bufferhub related information to given fd (usually stdout) + // Dumps bufferhub related information to given fd (usually stdout) // usage: adb shell dumpsys bufferhubd virtual status_t dump(int fd, const Vector<String16>& args) override; + // Marks a BufferNode to be duplicated. + // TODO(b/116681016): add importToken(int64_t) + status_t registerToken(const std::weak_ptr<BufferNode> node, + uint64_t* outToken); + // Binder IPC functions sp<IBufferClient> createBuffer(uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format, @@ -29,6 +37,12 @@ class BufferHubBinderService : public BinderService<BufferHubBinderService>, std::shared_ptr<BufferHubService> pdx_service_; std::vector<sp<BufferClient>> client_list_; + + // TODO(b/118180214): use a more secure implementation + std::mt19937_64 token_engine_; + // The mapping from token to a specific node. This is a many-to-one mapping. + // One node could be refered by 0 to multiple tokens. + std::unordered_map<uint64_t, std::weak_ptr<BufferNode>> token_map_; }; } // namespace dvr diff --git a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp b/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp index 7fa2226bf5..393f13ec26 100644 --- a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp +++ b/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp @@ -38,6 +38,23 @@ TEST_F(BufferHubBinderServiceTest, TestCreateBuffer) { EXPECT_TRUE(bufferClient->isValid()); } +TEST_F(BufferHubBinderServiceTest, TestDuplicateBuffer) { + sp<IBufferClient> bufferClient = service->createBuffer( + kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize); + EXPECT_THAT(bufferClient, NotNull()); + EXPECT_TRUE(bufferClient->isValid()); + + uint64_t token1 = 0ULL; + status_t ret = bufferClient->duplicate(&token1); + EXPECT_EQ(ret, NO_ERROR); + + // Should be different + uint64_t token2 = 0ULL; + ret = bufferClient->duplicate(&token2); + EXPECT_EQ(ret, NO_ERROR); + EXPECT_NE(token2, token1); +} + } // namespace } // namespace dvr |