Add importBuffer to BufferHubBinderService
Now you can create a new IBufferClient using token generated by
duplicate(). The new client will be linked to the same node in the
backend.
Import an unexisting token will return PERMISSION_DENIED, while import a
gone buffer will get DEAD_OBJECT.
Test: atest buffer_hub_binder_service-test
Bug: 116681016
Change-Id: Ib07fd160dad98bcaed017b3efa648863b70aa142
diff --git a/services/vr/bufferhubd/IBufferHub.cpp b/services/vr/bufferhubd/IBufferHub.cpp
index a2c0a4a..022a9cc 100644
--- a/services/vr/bufferhubd/IBufferHub.cpp
+++ b/services/vr/bufferhubd/IBufferHub.cpp
@@ -13,6 +13,8 @@
uint32_t layer_count, uint32_t format,
uint64_t usage,
uint64_t user_metadata_size) override;
+
+ status_t importBuffer(uint64_t token, sp<IBufferClient>* outClient) override;
};
IMPLEMENT_META_INTERFACE(BufferHub, "android.dvr.IBufferHub");
@@ -20,6 +22,7 @@
// Transaction code
enum {
CREATE_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
+ IMPORT_BUFFER,
};
sp<IBufferClient> BpBufferHub::createBuffer(uint32_t width, uint32_t height,
@@ -50,6 +53,27 @@
}
}
+status_t BpBufferHub::importBuffer(uint64_t token,
+ sp<IBufferClient>* outClient) {
+ Parcel data, reply;
+ status_t ret = NO_ERROR;
+ ret |= data.writeInterfaceToken(IBufferHub::getInterfaceDescriptor());
+ ret |= data.writeUint64(token);
+ if (ret != NO_ERROR) {
+ ALOGE("BpBufferHub::importBuffer: failed to write into parcel");
+ return ret;
+ }
+
+ ret = remote()->transact(IMPORT_BUFFER, data, &reply);
+ if (ret == NO_ERROR) {
+ *outClient = interface_cast<IBufferClient>(reply.readStrongBinder());
+ return NO_ERROR;
+ } else {
+ ALOGE("BpBufferHub::importBuffer: failed to transact; errno=%d", ret);
+ return ret;
+ }
+}
+
status_t BnBufferHub::onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags) {
switch (code) {
@@ -65,6 +89,17 @@
usage, user_metadata_size);
return reply->writeStrongBinder(IInterface::asBinder(ret));
}
+ case IMPORT_BUFFER: {
+ CHECK_INTERFACE(IBufferHub, data, reply);
+ uint64_t token = data.readUint64();
+ sp<IBufferClient> client;
+ status_t ret = importBuffer(token, &client);
+ if (ret == NO_ERROR) {
+ return reply->writeStrongBinder(IInterface::asBinder(client));
+ } else {
+ return ret;
+ }
+ }
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_hub_binder.cpp b/services/vr/bufferhubd/buffer_hub_binder.cpp
index 7b0dc9a..afd34aa 100644
--- a/services/vr/bufferhubd/buffer_hub_binder.cpp
+++ b/services/vr/bufferhubd/buffer_hub_binder.cpp
@@ -88,5 +88,42 @@
return client;
}
+status_t BufferHubBinderService::importBuffer(uint64_t token,
+ sp<IBufferClient>* outClient) {
+ auto iter = token_map_.find(token);
+
+ if (iter == token_map_.end()) { // Not found
+ ALOGE("BufferHubBinderService::importBuffer: token %" PRIu64
+ "does not exist.",
+ token);
+ return PERMISSION_DENIED;
+ }
+
+ if (iter->second.expired()) { // Gone
+ ALOGW(
+ "BufferHubBinderService::importBuffer: the original node of token "
+ "%" PRIu64 "has gone.",
+ token);
+ token_map_.erase(iter);
+ return DEAD_OBJECT;
+ }
+
+ // Promote the weak_ptr
+ std::shared_ptr<BufferNode> node(iter->second);
+ if (!node) {
+ ALOGE("BufferHubBinderService::importBuffer: promote weak_ptr failed.");
+ token_map_.erase(iter);
+ return DEAD_OBJECT;
+ }
+
+ sp<BufferClient> client = new BufferClient(node, this);
+ *outClient = client;
+
+ token_map_.erase(iter);
+ client_list_.push_back(client);
+
+ return NO_ERROR;
+}
+
} // namespace dvr
} // namespace android
diff --git a/services/vr/bufferhubd/include/private/dvr/IBufferHub.h b/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
index bd5f9cf..502c6d6 100644
--- a/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
+++ b/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
@@ -17,6 +17,9 @@
uint32_t layer_count, uint32_t format,
uint64_t usage,
uint64_t user_metadata_size) = 0;
+
+ virtual status_t importBuffer(uint64_t token,
+ sp<IBufferClient>* outClient) = 0;
};
class BnBufferHub : public BnInterface<IBufferHub> {
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 6c74cc4..cf6124b 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
@@ -33,6 +33,8 @@
uint64_t usage,
uint64_t user_metadata_size) override;
+ status_t importBuffer(uint64_t token, sp<IBufferClient>* outClient) override;
+
private:
std::shared_ptr<BufferHubService> pdx_service_;
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 393f13e..7c00fa6 100644
--- a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
+++ b/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
@@ -10,6 +10,7 @@
namespace {
+using testing::IsNull;
using testing::NotNull;
const int kWidth = 640;
@@ -38,21 +39,44 @@
EXPECT_TRUE(bufferClient->isValid());
}
-TEST_F(BufferHubBinderServiceTest, TestDuplicateBuffer) {
+TEST_F(BufferHubBinderServiceTest, TestDuplicateAndImportBuffer) {
sp<IBufferClient> bufferClient = service->createBuffer(
kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize);
- EXPECT_THAT(bufferClient, NotNull());
+ ASSERT_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
+ // Tokens should be unique even corresponding to the same buffer
uint64_t token2 = 0ULL;
ret = bufferClient->duplicate(&token2);
EXPECT_EQ(ret, NO_ERROR);
EXPECT_NE(token2, token1);
+
+ sp<IBufferClient> bufferClient1;
+ ret = service->importBuffer(token1, &bufferClient1);
+ EXPECT_EQ(ret, NO_ERROR);
+ ASSERT_THAT(bufferClient1, NotNull());
+ EXPECT_TRUE(bufferClient1->isValid());
+
+ // Consumes the token to keep the service clean
+ sp<IBufferClient> bufferClient2;
+ ret = service->importBuffer(token2, &bufferClient2);
+ EXPECT_EQ(ret, NO_ERROR);
+ ASSERT_THAT(bufferClient2, NotNull());
+ EXPECT_TRUE(bufferClient2->isValid());
+}
+
+TEST_F(BufferHubBinderServiceTest, TestImportUnexistingToken) {
+ // There is very little chance that this test fails if there is a token = 0
+ // in the service.
+ uint64_t unexistingToken = 0ULL;
+ sp<IBufferClient> bufferClient;
+ status_t ret = service->importBuffer(unexistingToken, &bufferClient);
+ EXPECT_EQ(ret, PERMISSION_DENIED);
+ EXPECT_THAT(bufferClient, IsNull());
}
} // namespace