1#include "detached_buffer_channel.h"
2#include "producer_channel.h"
3
4using android::pdx::BorrowedHandle;
5using android::pdx::ErrorStatus;
6using android::pdx::Message;
7using android::pdx::RemoteChannelHandle;
8using android::pdx::Status;
9using android::pdx::rpc::DispatchRemoteMethod;
10
11namespace android {
12namespace dvr {
13
14DetachedBufferChannel::DetachedBufferChannel(BufferHubService* service,
15                                             int buffer_id, int channel_id,
16                                             IonBuffer buffer,
17                                             IonBuffer metadata_buffer,
18                                             size_t user_metadata_size)
19    : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
20      buffer_(std::move(buffer)),
21      metadata_buffer_(std::move(metadata_buffer)),
22      user_metadata_size_(user_metadata_size) {
23}
24
25DetachedBufferChannel::DetachedBufferChannel(BufferHubService* service,
26                                             int buffer_id, uint32_t width,
27                                             uint32_t height,
28                                             uint32_t layer_count,
29                                             uint32_t format, uint64_t usage,
30                                             size_t user_metadata_size)
31    : BufferHubChannel(service, buffer_id, buffer_id, kDetachedBufferType),
32      user_metadata_size_(user_metadata_size) {
33  // The size the of metadata buffer is used as the "width" parameter during
34  // allocation. Thus it cannot overflow uint32_t.
35  if (user_metadata_size_ >= (std::numeric_limits<uint32_t>::max() -
36                              BufferHubDefs::kMetadataHeaderSize)) {
37    ALOGE(
38        "DetachedBufferChannel::DetachedBufferChannel: metadata size too big.");
39    return;
40  }
41
42  if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
43    ALOGE(
44        "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
45        "buffer: %s",
46        strerror(-ret));
47    return;
48  }
49
50  // Buffer metadata has two parts: 1) a fixed sized metadata header; and 2)
51  // user requested metadata.
52  const size_t size = BufferHubDefs::kMetadataHeaderSize + user_metadata_size_;
53  if (int ret = metadata_buffer_.Alloc(size,
54                                       /*height=*/1,
55                                       /*layer_count=*/1,
56                                       BufferHubDefs::kMetadataFormat,
57                                       BufferHubDefs::kMetadataUsage)) {
58    ALOGE(
59        "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
60        "metadata: %s",
61        strerror(-ret));
62    return;
63  }
64}
65
66DetachedBufferChannel::~DetachedBufferChannel() {
67  ALOGD_IF(TRACE,
68           "DetachedBufferChannel::~DetachedBufferChannel: channel_id=%d "
69           "buffer_id=%d.",
70           channel_id(), buffer_id());
71  Hangup();
72}
73
74BufferHubChannel::BufferInfo DetachedBufferChannel::GetBufferInfo() const {
75  return BufferInfo(buffer_id(), /*consumer_count=*/0, buffer_.width(),
76                    buffer_.height(), buffer_.layer_count(), buffer_.format(),
77                    buffer_.usage(), /*pending_count=*/0, /*state=*/0,
78                    /*signaled_mask=*/0, /*index=*/0);
79}
80
81void DetachedBufferChannel::HandleImpulse(Message& /*message*/) {
82  ATRACE_NAME("DetachedBufferChannel::HandleImpulse");
83}
84
85bool DetachedBufferChannel::HandleMessage(Message& message) {
86  ATRACE_NAME("DetachedBufferChannel::HandleMessage");
87  switch (message.GetOp()) {
88    case DetachedBufferRPC::Import::Opcode:
89      DispatchRemoteMethod<DetachedBufferRPC::Import>(
90          *this, &DetachedBufferChannel::OnImport, message);
91      return true;
92
93    case DetachedBufferRPC::Promote::Opcode:
94      DispatchRemoteMethod<DetachedBufferRPC::Promote>(
95          *this, &DetachedBufferChannel::OnPromote, message);
96      return true;
97
98    default:
99      return false;
100  }
101}
102
103Status<BufferDescription<BorrowedHandle>> DetachedBufferChannel::OnImport(
104    Message& /*message*/) {
105  ATRACE_NAME("DetachedBufferChannel::OnGetBuffer");
106  ALOGD_IF(TRACE, "DetachedBufferChannel::OnGetBuffer: buffer=%d.",
107           buffer_id());
108
109  return BufferDescription<BorrowedHandle>{buffer_,
110                                           metadata_buffer_,
111                                           buffer_id(),
112                                           /*buffer_state_bit=*/0,
113                                           BorrowedHandle{},
114                                           BorrowedHandle{}};
115}
116
117Status<RemoteChannelHandle> DetachedBufferChannel::OnPromote(
118    Message& message) {
119  ATRACE_NAME("DetachedBufferChannel::OnPromote");
120  ALOGD_IF(TRACE, "DetachedBufferChannel::OnPromote: buffer_id=%d",
121           buffer_id());
122
123  // Note that the new ProducerChannel will have different channel_id, but
124  // inherits the buffer_id from the DetachedBuffer.
125  int channel_id;
126  auto status = message.PushChannel(0, nullptr, &channel_id);
127  if (!status) {
128    ALOGE(
129        "DetachedBufferChannel::OnPromote: Failed to push ProducerChannel: %s.",
130        status.GetErrorMessage().c_str());
131    return ErrorStatus(ENOMEM);
132  }
133
134  std::unique_ptr<ProducerChannel> channel = ProducerChannel::Create(
135      service(), buffer_id(), channel_id, std::move(buffer_),
136      std::move(metadata_buffer_), user_metadata_size_);
137  if (!channel) {
138    ALOGE(
139        "DetachedBufferChannel::OnPromote: Failed to create ProducerChannel "
140        "from a DetachedBufferChannel, buffer_id=%d.",
141        buffer_id());
142  }
143
144  const auto channel_status =
145      service()->SetChannel(channel_id, std::move(channel));
146  if (!channel_status) {
147    // Technically, this should never fail, as we just pushed the channel. Note
148    // that LOG_FATAL will be stripped out in non-debug build.
149    LOG_FATAL(
150        "DetachedBufferChannel::OnPromote: Failed to set new producer buffer "
151        "channel: %s.",
152        channel_status.GetErrorMessage().c_str());
153  }
154
155  return status;
156}
157
158}  // namespace dvr
159}  // namespace android
160