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

Commit 3a96ccd1 authored by Fan Xu's avatar Fan Xu
Browse files

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
parent d94e2ee6
Loading
Loading
Loading
Loading
+35 −0
Original line number Diff line number Diff line
@@ -13,6 +13,8 @@ class BpBufferHub : public BpInterface<IBufferHub> {
                                 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 @@ IMPLEMENT_META_INTERFACE(BufferHub, "android.dvr.IBufferHub");
// 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 @@ sp<IBufferClient> BpBufferHub::createBuffer(uint32_t width, uint32_t height,
  }
}

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 @@ status_t BnBufferHub::onTransact(uint32_t code, const Parcel& data,
                                           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);
+37 −0
Original line number Diff line number Diff line
@@ -88,5 +88,42 @@ sp<IBufferClient> BufferHubBinderService::createBuffer(
  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
+3 −0
Original line number Diff line number Diff line
@@ -17,6 +17,9 @@ class IBufferHub : public IInterface {
                                         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> {
+2 −0
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@ class BufferHubBinderService : public BinderService<BufferHubBinderService>,
                                 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_;

+27 −3
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ namespace dvr {

namespace {

using testing::IsNull;
using testing::NotNull;

const int kWidth = 640;
@@ -38,21 +39,44 @@ TEST_F(BufferHubBinderServiceTest, TestCreateBuffer) {
  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