Merge "Make BufferHubQueue binder parcelable"
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index e3cb494..a550ba5 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -29,6 +29,7 @@
sharedLibraries = [
"libbase",
+ "libbinder",
"libcutils",
"libhardware",
"liblog",
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
index 93ccd0f..feefe74 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -14,6 +14,7 @@
sourceFiles = [
"buffer_hub_queue_client.cpp",
+ "buffer_hub_queue_parcelable.cpp",
"buffer_hub_queue_producer.cpp",
]
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index 8bea0cd..a5cefd9 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -137,6 +137,28 @@
return status;
}
+pdx::Status<ConsumerQueueParcelable>
+BufferHubQueue::CreateConsumerQueueParcelable(bool silent) {
+ auto status = CreateConsumerQueueHandle(silent);
+ if (!status)
+ return status.error_status();
+
+ // A temporary consumer queue client to pull its channel parcelable.
+ auto consumer_queue =
+ std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take()));
+ ConsumerQueueParcelable queue_parcelable(
+ consumer_queue->GetChannel()->TakeChannelParcelable());
+
+ if (!queue_parcelable.IsValid()) {
+ ALOGE(
+ "BufferHubQueue::CreateConsumerQueueParcelable: Failed to create "
+ "consumer queue parcelable.");
+ return ErrorStatus(EINVAL);
+ }
+
+ return {std::move(queue_parcelable)};
+}
+
bool BufferHubQueue::WaitForBuffers(int timeout) {
ATRACE_NAME("BufferHubQueue::WaitForBuffers");
std::array<epoll_event, kMaxEvents> events;
@@ -555,6 +577,25 @@
return {std::move(buffer)};
}
+pdx::Status<ProducerQueueParcelable> ProducerQueue::TakeAsParcelable() {
+ if (capacity() != 0) {
+ ALOGE(
+ "ProducerQueue::TakeAsParcelable: producer queue can only be taken out"
+ " as a parcelable when empty. Current queue capacity: %zu",
+ capacity());
+ return ErrorStatus(EINVAL);
+ }
+
+ std::unique_ptr<pdx::ClientChannel> channel = TakeChannel();
+ ProducerQueueParcelable queue_parcelable(channel->TakeChannelParcelable());
+
+ // Here the queue parcelable is returned and holds the underlying system
+ // resources backing the queue; while the original client channel of this
+ // producer queue is destroyed in place so that this client can no longer
+ // provide producer operations.
+ return {std::move(queue_parcelable)};
+}
+
ConsumerQueue::ConsumerQueue(LocalChannelHandle handle)
: BufferHubQueue(std::move(handle)) {
auto status = ImportQueue();
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_parcelable.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_parcelable.cpp
new file mode 100644
index 0000000..2cd7c45
--- /dev/null
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_parcelable.cpp
@@ -0,0 +1,82 @@
+#include "include/private/dvr/buffer_hub_queue_parcelable.h"
+
+#include <binder/Parcel.h>
+#include <pdx/default_transport/channel_parcelable.h>
+
+namespace android {
+namespace dvr {
+
+template <BufferHubQueueParcelableMagic Magic>
+bool BufferHubQueueParcelable<Magic>::IsValid() const {
+ return !!channel_parcelable_ && channel_parcelable_->IsValid();
+}
+
+template <BufferHubQueueParcelableMagic Magic>
+pdx::LocalChannelHandle BufferHubQueueParcelable<Magic>::TakeChannelHandle() {
+ if (!IsValid()) {
+ ALOGE(
+ "BufferHubQueueParcelable::TakeChannelHandle: Invalid channel parcel.");
+ return {}; // Returns an empty channel handle.
+ }
+
+ // Take channel handle out of the parcelable and reset the parcelable.
+ pdx::LocalChannelHandle handle = channel_parcelable_->TakeChannelHandle();
+ // Now channel_parcelable_ should already be invalid, but reset it to release
+ // the invalid parcelable object from unique_ptr.
+ channel_parcelable_ = nullptr;
+ return handle;
+}
+
+template <BufferHubQueueParcelableMagic Magic>
+status_t BufferHubQueueParcelable<Magic>::writeToParcel(Parcel* parcel) const {
+ if (!IsValid()) {
+ ALOGE("BufferHubQueueParcelable::writeToParcel: Invalid channel.");
+ return -EINVAL;
+ }
+
+ status_t res = parcel->writeUint32(Magic);
+ if (res != NO_ERROR) {
+ ALOGE("BufferHubQueueParcelable::writeToParcel: Cannot write magic.");
+ return res;
+ }
+
+ return channel_parcelable_->writeToParcel(parcel);
+}
+
+template <BufferHubQueueParcelableMagic Magic>
+status_t BufferHubQueueParcelable<Magic>::readFromParcel(const Parcel* parcel) {
+ if (IsValid()) {
+ ALOGE(
+ "BufferHubQueueParcelable::readFromParcel: This parcelable object has "
+ "been initialized already.");
+ return -EINVAL;
+ }
+
+ uint32_t out_magic = 0;
+ status_t res = NO_ERROR;
+
+ res = parcel->readUint32(&out_magic);
+ if (res != NO_ERROR)
+ return res;
+
+ if (out_magic != Magic) {
+ ALOGE(
+ "BufferHubQueueParcelable::readFromParcel: Unexpected magic: 0x%x, "
+ "epxected: 0x%x",
+ out_magic, Magic);
+ return -EINVAL;
+ }
+
+ // (Re)Alocate channel parcelable object.
+ channel_parcelable_ =
+ std::make_unique<pdx::default_transport::ChannelParcelable>();
+ return channel_parcelable_->readFromParcel(parcel);
+}
+
+template class BufferHubQueueParcelable<
+ BufferHubQueueParcelableMagic::Producer>;
+template class BufferHubQueueParcelable<
+ BufferHubQueueParcelableMagic::Consumer>;
+
+} // namespace dvr
+} // namespace android
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
index 6962d6c..c8e31c7 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
@@ -6,6 +6,7 @@
#include <pdx/client.h>
#include <pdx/status.h>
#include <private/dvr/buffer_hub_client.h>
+#include <private/dvr/buffer_hub_queue_parcelable.h>
#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/epoll_file_descriptor.h>
#include <private/dvr/ring_buffer.h>
@@ -54,6 +55,11 @@
pdx::Status<pdx::LocalChannelHandle> CreateConsumerQueueHandle(
bool silent = false);
+ // Creates a new consumer in parcelable form for immediate transport over
+ // Binder.
+ pdx::Status<ConsumerQueueParcelable> CreateConsumerQueueParcelable(
+ bool silent = false);
+
// Returns the number of buffers avaiable for dequeue.
size_t count() const { return available_buffers_.size(); }
@@ -337,6 +343,11 @@
return BufferHubQueue::Enqueue({buffer, slot, index});
}
+ // Takes out the current producer queue as a binder parcelable object. Note
+ // that the queue must be empty to be exportable. After successful export, the
+ // producer queue client should no longer be used.
+ pdx::Status<ProducerQueueParcelable> TakeAsParcelable();
+
private:
friend BASE;
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h
new file mode 100644
index 0000000..89baf92
--- /dev/null
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h
@@ -0,0 +1,60 @@
+#ifndef ANDROID_DVR_BUFFER_HUB_QUEUE_PARCELABLE_H_
+#define ANDROID_DVR_BUFFER_HUB_QUEUE_PARCELABLE_H_
+
+#include <pdx/channel_parcelable.h>
+
+namespace android {
+namespace dvr {
+
+enum BufferHubQueueParcelableMagic : uint32_t {
+ Producer = 0x62687170, // 'bhqp'
+ Consumer = 0x62687163, // 'bhqc'
+};
+
+template <BufferHubQueueParcelableMagic Magic>
+class BufferHubQueueParcelable : public Parcelable {
+ public:
+ BufferHubQueueParcelable() = default;
+
+ BufferHubQueueParcelable(BufferHubQueueParcelable&& other) = default;
+ BufferHubQueueParcelable& operator=(BufferHubQueueParcelable&& other) =
+ default;
+
+ // Constructs an parcelable contains the channel parcelable.
+ BufferHubQueueParcelable(
+ std::unique_ptr<pdx::ChannelParcelable> channel_parcelable)
+ : channel_parcelable_(std::move(channel_parcelable)) {}
+
+ BufferHubQueueParcelable(const BufferHubQueueParcelable&) = delete;
+ void operator=(const BufferHubQueueParcelable&) = delete;
+
+ bool IsValid() const;
+
+ // Returns a channel handle constructed from this parcelable object and takes
+ // the ownership of all resources from the parcelable object.
+ pdx::LocalChannelHandle TakeChannelHandle();
+
+ // Serializes the queue parcelable into the given parcel. Note that no system
+ // resources are getting duplicated, nor did the parcel takes ownership of the
+ // queue parcelable. Thus, the parcelable object must remain valid for the
+ // lifetime of the parcel.
+ status_t writeToParcel(Parcel* parcel) const override;
+
+ // Deserialize the queue parcelable from the given parcel. Note that system
+ // resources are duplicated from the parcel into the queue parcelable. Returns
+ // error if the targeting parcelable object is already valid.
+ status_t readFromParcel(const Parcel* parcel) override;
+
+ private:
+ std::unique_ptr<pdx::ChannelParcelable> channel_parcelable_;
+};
+
+using ProducerQueueParcelable =
+ BufferHubQueueParcelable<BufferHubQueueParcelableMagic::Producer>;
+using ConsumerQueueParcelable =
+ BufferHubQueueParcelable<BufferHubQueueParcelableMagic::Consumer>;
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_BUFFER_HUB_QUEUE_PARCELABLE_H_
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
index 8a72531..f67ef37 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
@@ -1,4 +1,5 @@
#include <base/logging.h>
+#include <binder/Parcel.h>
#include <private/dvr/buffer_hub_client.h>
#include <private/dvr/buffer_hub_queue_client.h>
@@ -14,6 +15,7 @@
namespace android {
namespace dvr {
+using pdx::LocalChannelHandle;
using pdx::LocalHandle;
namespace {
@@ -680,6 +682,156 @@
#undef CHECK_NO_BUFFER_THEN_ALLOCATE
}
+TEST_F(BufferHubQueueTest, TestProducerToParcelableNotEmpty) {
+ ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<uint64_t>().Build(),
+ UsagePolicy{}));
+
+ // Allocate only one buffer.
+ AllocateBuffer();
+
+ // Export should fail as the queue is not empty.
+ auto status = producer_queue_->TakeAsParcelable();
+ EXPECT_FALSE(status.ok());
+}
+
+TEST_F(BufferHubQueueTest, TestProducerExportToParcelable) {
+ ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
+
+ auto s1 = producer_queue_->TakeAsParcelable();
+ EXPECT_TRUE(s1.ok());
+
+ ProducerQueueParcelable output_parcelable = s1.take();
+ EXPECT_TRUE(output_parcelable.IsValid());
+
+ Parcel parcel;
+ status_t res;
+ res = output_parcelable.writeToParcel(&parcel);
+ EXPECT_EQ(res, NO_ERROR);
+
+ // After written into parcelable, the output_parcelable is still valid has
+ // keeps the producer channel alive.
+ EXPECT_TRUE(output_parcelable.IsValid());
+
+ // Creating producer buffer should fail.
+ auto s2 = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
+ kBufferLayerCount, kBufferFormat,
+ kBufferUsage);
+ ASSERT_FALSE(s2.ok());
+
+ // Reset the data position so that we can read back from the same parcel
+ // without doing actually Binder IPC.
+ parcel.setDataPosition(0);
+ producer_queue_ = nullptr;
+
+ // Recreate the producer queue from the parcel.
+ ProducerQueueParcelable input_parcelable;
+ EXPECT_FALSE(input_parcelable.IsValid());
+
+ res = input_parcelable.readFromParcel(&parcel);
+ EXPECT_EQ(res, NO_ERROR);
+ EXPECT_TRUE(input_parcelable.IsValid());
+
+ EXPECT_EQ(producer_queue_, nullptr);
+ producer_queue_ = ProducerQueue::Import(input_parcelable.TakeChannelHandle());
+ EXPECT_FALSE(input_parcelable.IsValid());
+ ASSERT_NE(producer_queue_, nullptr);
+
+ // Newly created queue from the parcel can allocate buffer, post buffer to
+ // consumer.
+ EXPECT_NO_FATAL_FAILURE(AllocateBuffer());
+ EXPECT_EQ(producer_queue_->count(), 1U);
+ EXPECT_EQ(producer_queue_->capacity(), 1U);
+
+ size_t slot;
+ DvrNativeBufferMetadata producer_meta;
+ DvrNativeBufferMetadata consumer_meta;
+ LocalHandle fence;
+ auto s3 = producer_queue_->Dequeue(0, &slot, &producer_meta, &fence);
+ EXPECT_TRUE(s3.ok());
+
+ std::shared_ptr<BufferProducer> p1 = s3.take();
+ EXPECT_NE(p1, nullptr);
+
+ producer_meta.timestamp = 42;
+ EXPECT_EQ(p1->PostAsync(&producer_meta, LocalHandle()), 0);
+
+ // Make sure the buffer can be dequeued from consumer side.
+ auto s4 = consumer_queue_->Dequeue(100, &slot, &consumer_meta, &fence);
+ EXPECT_TRUE(s4.ok());
+ EXPECT_EQ(consumer_queue_->capacity(), 1U);
+
+ auto consumer = s4.take();
+ EXPECT_NE(consumer, nullptr);
+ EXPECT_EQ(producer_meta.timestamp, consumer_meta.timestamp);
+}
+
+TEST_F(BufferHubQueueTest, TestCreateConsumerParcelable) {
+ ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{}));
+
+ auto s1 = producer_queue_->CreateConsumerQueueParcelable();
+ EXPECT_TRUE(s1.ok());
+ ConsumerQueueParcelable output_parcelable = s1.take();
+ EXPECT_TRUE(output_parcelable.IsValid());
+
+ // Write to a Parcel new object.
+ Parcel parcel;
+ status_t res;
+ res = output_parcelable.writeToParcel(&parcel);
+
+ // Reset the data position so that we can read back from the same parcel
+ // without doing actually Binder IPC.
+ parcel.setDataPosition(0);
+
+ // No consumer queue created yet.
+ EXPECT_EQ(consumer_queue_, nullptr);
+
+ // If the parcel contains a consumer queue, read into a
+ // ProducerQueueParcelable should fail.
+ ProducerQueueParcelable wrongly_typed_parcelable;
+ EXPECT_FALSE(wrongly_typed_parcelable.IsValid());
+ res = wrongly_typed_parcelable.readFromParcel(&parcel);
+ EXPECT_EQ(res, -EINVAL);
+ parcel.setDataPosition(0);
+
+ // Create the consumer queue from the parcel.
+ ConsumerQueueParcelable input_parcelable;
+ EXPECT_FALSE(input_parcelable.IsValid());
+
+ res = input_parcelable.readFromParcel(&parcel);
+ EXPECT_EQ(res, NO_ERROR);
+ EXPECT_TRUE(input_parcelable.IsValid());
+
+ consumer_queue_ = ConsumerQueue::Import(input_parcelable.TakeChannelHandle());
+ EXPECT_FALSE(input_parcelable.IsValid());
+ ASSERT_NE(consumer_queue_, nullptr);
+
+ EXPECT_NO_FATAL_FAILURE(AllocateBuffer());
+ EXPECT_EQ(producer_queue_->count(), 1U);
+ EXPECT_EQ(producer_queue_->capacity(), 1U);
+
+ size_t slot;
+ DvrNativeBufferMetadata producer_meta;
+ DvrNativeBufferMetadata consumer_meta;
+ LocalHandle fence;
+ auto s2 = producer_queue_->Dequeue(0, &slot, &producer_meta, &fence);
+ EXPECT_TRUE(s2.ok());
+
+ std::shared_ptr<BufferProducer> p1 = s2.take();
+ EXPECT_NE(p1, nullptr);
+
+ producer_meta.timestamp = 42;
+ EXPECT_EQ(p1->PostAsync(&producer_meta, LocalHandle()), 0);
+
+ // Make sure the buffer can be dequeued from consumer side.
+ auto s3 = consumer_queue_->Dequeue(100, &slot, &consumer_meta, &fence);
+ EXPECT_TRUE(s3.ok());
+ EXPECT_EQ(consumer_queue_->capacity(), 1U);
+
+ auto consumer = s3.take();
+ EXPECT_NE(consumer, nullptr);
+ EXPECT_EQ(producer_meta.timestamp, consumer_meta.timestamp);
+}
+
} // namespace
} // namespace dvr
diff --git a/libs/vr/libdisplay/Android.bp b/libs/vr/libdisplay/Android.bp
index e3ab7fa..684dff1 100644
--- a/libs/vr/libdisplay/Android.bp
+++ b/libs/vr/libdisplay/Android.bp
@@ -26,6 +26,7 @@
sharedLibraries = [
"libbase",
+ "libbinder",
"libcutils",
"liblog",
"libutils",
diff --git a/libs/vr/libpdx/private/pdx/channel_parcelable.h b/libs/vr/libpdx/private/pdx/channel_parcelable.h
new file mode 100644
index 0000000..59ef9d3
--- /dev/null
+++ b/libs/vr/libpdx/private/pdx/channel_parcelable.h
@@ -0,0 +1,31 @@
+#ifndef ANDROID_PDX_CHANNEL_PARCELABLE_H_
+#define ANDROID_PDX_CHANNEL_PARCELABLE_H_
+
+#include <binder/Parcelable.h>
+#include <pdx/channel_handle.h>
+
+namespace android {
+namespace pdx {
+
+/**
+ * A parcelable object holds all necessary objects to recreate a ClientChannel.
+ * In addition to the android::Parcelable interface, this interface exposees
+ * more PDX-related interface.
+ */
+class ChannelParcelable : public Parcelable {
+ public:
+ virtual ~ChannelParcelable() = default;
+
+ // Returns whether the parcelable object holds a valid client channel.
+ virtual bool IsValid() const = 0;
+
+ // Returns a channel handle constructed from this parcelable object and takes
+ // the ownership of all resources from the parcelable object. In another word,
+ // the parcelable object will become invalid after TakeChannelHandle returns.
+ virtual LocalChannelHandle TakeChannelHandle() = 0;
+};
+
+} // namespace pdx
+} // namespace android
+
+#endif // ANDROID_PDX_CHANNEL_PARCELABLE_H_
diff --git a/libs/vr/libpdx/private/pdx/client_channel.h b/libs/vr/libpdx/private/pdx/client_channel.h
index 10a49bb..8f5fdfe 100644
--- a/libs/vr/libpdx/private/pdx/client_channel.h
+++ b/libs/vr/libpdx/private/pdx/client_channel.h
@@ -4,6 +4,7 @@
#include <vector>
#include <pdx/channel_handle.h>
+#include <pdx/channel_parcelable.h>
#include <pdx/file_handle.h>
#include <pdx/status.h>
@@ -61,6 +62,11 @@
LocalHandle* handle) const = 0;
virtual bool GetChannelHandle(void* transaction_state, ChannelReference ref,
LocalChannelHandle* handle) const = 0;
+
+ // Returns the internal state of the channel as a parcelable object. The
+ // ClientChannel is invalidated however, the channel is kept alive by the
+ // parcelable object and may be transferred to another process.
+ virtual std::unique_ptr<ChannelParcelable> TakeChannelParcelable() = 0;
};
} // namespace pdx
diff --git a/libs/vr/libpdx/private/pdx/mock_client_channel.h b/libs/vr/libpdx/private/pdx/mock_client_channel.h
index 49e0682..ecc20b3 100644
--- a/libs/vr/libpdx/private/pdx/mock_client_channel.h
+++ b/libs/vr/libpdx/private/pdx/mock_client_channel.h
@@ -49,6 +49,7 @@
MOCK_CONST_METHOD3(GetChannelHandle,
bool(void* transaction_state, ChannelReference ref,
LocalChannelHandle* handle));
+ MOCK_METHOD0(TakeChannelParcelable, std::unique_ptr<ChannelParcelable>());
};
} // namespace pdx
diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp
index f891c59..cda3c95 100644
--- a/libs/vr/libpdx_default_transport/Android.bp
+++ b/libs/vr/libpdx_default_transport/Android.bp
@@ -42,6 +42,7 @@
"pdx_tool.cpp",
],
shared_libs: [
+ "libbinder",
"libcutils",
"liblog",
],
@@ -59,6 +60,7 @@
],
shared_libs: [
"libbase",
+ "libbinder",
"libchrome",
"libcutils",
"liblog",
diff --git a/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/channel_parcelable.h b/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/channel_parcelable.h
new file mode 100644
index 0000000..a8623b2
--- /dev/null
+++ b/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/channel_parcelable.h
@@ -0,0 +1,17 @@
+#ifndef ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_CHANNEL_PARCELABLE_H_
+#define ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_CHANNEL_PARCELABLE_H_
+
+#include <servicefs/channel_parcelable.h>
+
+namespace android {
+namespace pdx {
+namespace default_transport {
+
+using ChannelParcelable = ::android::pdx::servicefs::ChannelParcelable;
+
+} // namespace default_transport
+} // namespace pdx
+} // namespace android
+
+
+#endif // ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_CHANNEL_PARCELABLE_H_
diff --git a/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/channel_parcelable.h b/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/channel_parcelable.h
new file mode 100644
index 0000000..bcd74e6
--- /dev/null
+++ b/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/channel_parcelable.h
@@ -0,0 +1,17 @@
+#ifndef ANDROID_PDX_DEFAULT_TRANSPORT_UDS_CHANNEL_PARCELABLE_H_
+#define ANDROID_PDX_DEFAULT_TRANSPORT_UDS_CHANNEL_PARCELABLE_H_
+
+#include <uds/channel_parcelable.h>
+
+namespace android {
+namespace pdx {
+namespace default_transport {
+
+using ChannelParcelable = ::android::pdx::uds::ChannelParcelable;
+
+} // namespace default_transport
+} // namespace pdx
+} // namespace android
+
+
+#endif // ANDROID_PDX_DEFAULT_TRANSPORT_UDS_CHANNEL_PARCELABLE_H_
diff --git a/libs/vr/libpdx_uds/Android.bp b/libs/vr/libpdx_uds/Android.bp
index d0b7cab..d640950 100644
--- a/libs/vr/libpdx_uds/Android.bp
+++ b/libs/vr/libpdx_uds/Android.bp
@@ -13,6 +13,7 @@
srcs: [
"channel_event_set.cpp",
"channel_manager.cpp",
+ "channel_parcelable.cpp",
"client_channel_factory.cpp",
"client_channel.cpp",
"ipc_helper.cpp",
@@ -23,6 +24,9 @@
"libbase",
"libpdx",
],
+ shared_libs: [
+ "libbinder",
+ ],
whole_static_libs: [
"libselinux",
],
@@ -52,5 +56,6 @@
"libcutils",
"liblog",
"libutils",
+ "libbinder",
],
}
diff --git a/libs/vr/libpdx_uds/channel_parcelable.cpp b/libs/vr/libpdx_uds/channel_parcelable.cpp
new file mode 100644
index 0000000..e7bce27
--- /dev/null
+++ b/libs/vr/libpdx_uds/channel_parcelable.cpp
@@ -0,0 +1,125 @@
+#include "uds/channel_parcelable.h"
+
+#include <binder/Parcel.h>
+#include <uds/channel_manager.h>
+
+namespace android {
+namespace pdx {
+namespace uds {
+
+namespace {
+
+static constexpr uint32_t kUdsMagicParcelHeader = 0x7564736d; // 'udsm'.
+
+} // namespace
+
+ChannelParcelable::ChannelParcelable(LocalHandle data_fd,
+ LocalHandle pollin_event_fd,
+ LocalHandle pollhup_event_fd)
+ : data_fd_{std::move(data_fd)},
+ pollin_event_fd_{std::move(pollin_event_fd)},
+ pollhup_event_fd_{std::move(pollhup_event_fd)} {}
+
+bool ChannelParcelable::IsValid() const {
+ return !!data_fd_ && !!pollin_event_fd_ && !!pollhup_event_fd_;
+}
+
+LocalChannelHandle ChannelParcelable::TakeChannelHandle() {
+ if (!IsValid()) {
+ ALOGE("ChannelParcelable::TakeChannelHandle: Invalid channel parcel.");
+ return {}; // Returns an empty channel handle.
+ }
+
+ return ChannelManager::Get().CreateHandle(std::move(data_fd_),
+ std::move(pollin_event_fd_),
+ std::move(pollhup_event_fd_));
+}
+
+status_t ChannelParcelable::writeToParcel(Parcel* parcel) const {
+ status_t res = NO_ERROR;
+
+ if (!IsValid()) {
+ ALOGE("ChannelParcelable::writeToParcel: Invalid channel parcel.");
+ return BAD_VALUE;
+ }
+
+ res = parcel->writeUint32(kUdsMagicParcelHeader);
+ if (res != NO_ERROR) {
+ ALOGE("ChannelParcelable::writeToParcel: Cannot write magic: res=%d.", res);
+ return res;
+ }
+
+ res = parcel->writeFileDescriptor(data_fd_.Get());
+ if (res != NO_ERROR) {
+ ALOGE("ChannelParcelable::writeToParcel: Cannot write data fd: res=%d.",
+ res);
+ return res;
+ }
+
+ res = parcel->writeFileDescriptor(pollin_event_fd_.Get());
+ if (res != NO_ERROR) {
+ ALOGE(
+ "ChannelParcelable::writeToParcel: Cannot write pollin event fd: "
+ "res=%d.",
+ res);
+ return res;
+ }
+
+ res = parcel->writeFileDescriptor(pollhup_event_fd_.Get());
+ if (res != NO_ERROR) {
+ ALOGE(
+ "ChannelParcelable::writeToParcel: Cannot write pollhup event fd: "
+ "res=%d.",
+ res);
+ return res;
+ }
+
+ return res;
+}
+
+status_t ChannelParcelable::readFromParcel(const Parcel* parcel) {
+ uint32_t magic = 0;
+ status_t res = NO_ERROR;
+
+ if (IsValid()) {
+ ALOGE(
+ "ChannelParcelable::readFromParcel: This channel parcel is already "
+ "initailzied.");
+ return ALREADY_EXISTS;
+ }
+
+ res = parcel->readUint32(&magic);
+ if (res != NO_ERROR) {
+ ALOGE("ChannelParcelable::readFromParcel: Failed to read magic: res=%d.",
+ res);
+ return res;
+ }
+
+ if (magic != kUdsMagicParcelHeader) {
+ ALOGE(
+ "ChannelParcelable::readFromParcel: Unknown magic: 0x%x, epxected: "
+ "0x%x",
+ magic, kUdsMagicParcelHeader);
+ return BAD_VALUE;
+ }
+
+ // TODO(b/69010509): We have to dup() the FD from android::Parcel as it
+ // doesn't support taking out the FD's ownership. We can remove the dup() here
+ // once android::Parcel support such operation.
+ data_fd_.Reset(dup(parcel->readFileDescriptor()));
+ pollin_event_fd_.Reset(dup(parcel->readFileDescriptor()));
+ pollhup_event_fd_.Reset(dup(parcel->readFileDescriptor()));
+ if (!IsValid()) {
+ ALOGE(
+ "ChannelParcelable::readFromParcel: Cannot read fd from parcel: "
+ "data_fd=%d, pollin_event_fd=%d, pollhup_event_fd=%d.",
+ data_fd_.Get(), pollin_event_fd_.Get(), pollhup_event_fd_.Get());
+ return DEAD_OBJECT;
+ }
+
+ return res;
+}
+
+} // namespace uds
+} // namespace pdx
+} // namespace android
diff --git a/libs/vr/libpdx_uds/client_channel.cpp b/libs/vr/libpdx_uds/client_channel.cpp
index 2e9c1de..6073c3c 100644
--- a/libs/vr/libpdx_uds/client_channel.cpp
+++ b/libs/vr/libpdx_uds/client_channel.cpp
@@ -1,3 +1,4 @@
+#include "uds/channel_parcelable.h"
#include "uds/client_channel.h"
#include <errno.h>
@@ -292,6 +293,29 @@
return state->GetLocalChannelHandle(ref, handle);
}
+std::unique_ptr<pdx::ChannelParcelable> ClientChannel::TakeChannelParcelable()
+ {
+ if (!channel_handle_)
+ return nullptr;
+
+ if (auto* channel_data =
+ ChannelManager::Get().GetChannelData(channel_handle_.value())) {
+ auto fds = channel_data->TakeFds();
+ auto parcelable = std::make_unique<ChannelParcelable>(
+ std::move(std::get<0>(fds)), std::move(std::get<1>(fds)),
+ std::move(std::get<2>(fds)));
+
+ // Here we need to explicitly close the channel handle so that the channel
+ // won't get shutdown in the destructor, while the FDs in ChannelParcelable
+ // can keep the channel alive so that new client can be created from it
+ // later.
+ channel_handle_.Close();
+ return parcelable;
+ } else {
+ return nullptr;
+ }
+}
+
} // namespace uds
} // namespace pdx
} // namespace android
diff --git a/libs/vr/libpdx_uds/private/uds/channel_parcelable.h b/libs/vr/libpdx_uds/private/uds/channel_parcelable.h
new file mode 100644
index 0000000..1c3fae9
--- /dev/null
+++ b/libs/vr/libpdx_uds/private/uds/channel_parcelable.h
@@ -0,0 +1,35 @@
+#ifndef ANDROID_PDX_UDS_CHANNEL_PARCELABLE_H_
+#define ANDROID_PDX_UDS_CHANNEL_PARCELABLE_H_
+
+#include <pdx/channel_parcelable.h>
+#include <pdx/file_handle.h>
+
+namespace android {
+namespace pdx {
+namespace uds {
+
+class ChannelParcelable : public pdx::ChannelParcelable {
+ public:
+ ChannelParcelable() = default;
+ ChannelParcelable(LocalHandle data_fd, LocalHandle pollin_event_fd,
+ LocalHandle pollhup_event_fd);
+
+ // Implements pdx::ChannelParcelable interface.
+ bool IsValid() const override;
+ LocalChannelHandle TakeChannelHandle() override;
+
+ // Implements android::Parcelable interface.
+ status_t writeToParcel(Parcel* parcel) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
+
+ private:
+ LocalHandle data_fd_;
+ LocalHandle pollin_event_fd_;
+ LocalHandle pollhup_event_fd_;
+};
+
+} // namespace uds
+} // namespace pdx
+} // namespace android
+
+#endif // ANDROID_PDX_UDS_CHANNEL_PARCELABLE_H_
diff --git a/libs/vr/libpdx_uds/private/uds/client_channel.h b/libs/vr/libpdx_uds/private/uds/client_channel.h
index 7a5ddf4..b5524d8 100644
--- a/libs/vr/libpdx_uds/private/uds/client_channel.h
+++ b/libs/vr/libpdx_uds/private/uds/client_channel.h
@@ -74,6 +74,8 @@
bool GetChannelHandle(void* transaction_state, ChannelReference ref,
LocalChannelHandle* handle) const override;
+ std::unique_ptr<pdx::ChannelParcelable> TakeChannelParcelable() override;
+
private:
explicit ClientChannel(LocalChannelHandle channel_handle);
diff --git a/libs/vr/libperformance/Android.bp b/libs/vr/libperformance/Android.bp
index 364873d..278a425 100644
--- a/libs/vr/libperformance/Android.bp
+++ b/libs/vr/libperformance/Android.bp
@@ -23,6 +23,7 @@
sharedLibraries = [
"libbase",
+ "libbinder",
"libcutils",
"liblog",
"libutils",
diff --git a/libs/vr/libvrsensor/Android.bp b/libs/vr/libvrsensor/Android.bp
index d022adf..cc1803b 100644
--- a/libs/vr/libvrsensor/Android.bp
+++ b/libs/vr/libvrsensor/Android.bp
@@ -33,6 +33,7 @@
sharedLibraries = [
"libbase",
+ "libbinder",
"libcutils",
"libhardware",
"liblog",
diff --git a/services/vr/bufferhubd/Android.mk b/services/vr/bufferhubd/Android.mk
index 28cf53d..e1997d7 100644
--- a/services/vr/bufferhubd/Android.mk
+++ b/services/vr/bufferhubd/Android.mk
@@ -32,6 +32,7 @@
sharedLibraries := \
libbase \
+ libbinder \
libcutils \
liblog \
libsync \
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index e92b8d8..76ec42d 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -20,6 +20,7 @@
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.mapper@2.0",
"libbase",
+ "libbinder",
"libcutils",
"libfmq",
"libhardware",