summaryrefslogtreecommitdiffstats
path: root/src/perfetto/rx_producer.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/perfetto/rx_producer.h')
-rw-r--r--src/perfetto/rx_producer.h53
1 files changed, 50 insertions, 3 deletions
diff --git a/src/perfetto/rx_producer.h b/src/perfetto/rx_producer.h
index f4c40b4..4e93f0d 100644
--- a/src/perfetto/rx_producer.h
+++ b/src/perfetto/rx_producer.h
@@ -51,10 +51,39 @@ struct PerfettoDependencies {
uint32_t buffer_size = 4096);
};
+namespace detail {
+ template <typename T>
+ struct concept_message_lite_base {
+ static_assert(std::is_base_of_v<::google::protobuf::MessageLite, T>,
+ "T must inherit from MessageLite");
+ using type = T;
+ };
+
+ template <typename T>
+ using concept_message_lite_base_t = typename concept_message_lite_base<T>::type;
+} // namespace detail
+
+/*
+ * In Android's version of libprotobuf, move-constructors are not generated.
+ * This results in a legitimate (~10sec per TracePacket being compiled) slowdown,
+ * so we need to avoid it everywhere.
+ *
+ * 1) Don't copy the protos, move them instead.
+ * 2) Use 'shared_ptr' because rxcpp won't compile with unique_ptr.
+ */
+template <typename T>
+using ProtobufPtr = std::shared_ptr<detail::concept_message_lite_base_t<const T>>;
+
+template <typename T>
+using ProtobufMutablePtr = std::shared_ptr<detail::concept_message_lite_base_t<T>>;
+
// This acts as a lightweight type marker so that we know what data has actually
// encoded under the hood.
template <typename T>
struct BinaryWireProtobuf {
+ static_assert(std::is_base_of_v<::google::protobuf::MessageLite, T>,
+ "T should be a base class of MessageLite");
+
std::vector<std::byte>& data() {
return data_;
}
@@ -78,13 +107,21 @@ struct BinaryWireProtobuf {
data_.data());
}
+ explicit BinaryWireProtobuf(std::vector<std::byte> data) : data_{std::move(data)} {
+ }
+
+ // You wouldn't want to accidentally copy a giant multi-megabyte chunk would you?
+ // BinaryWireProtobuf(const BinaryWireProtobuf& other) = delete; // FIXME: rx likes to copy.
+ BinaryWireProtobuf(const BinaryWireProtobuf& other) = default;
+ BinaryWireProtobuf(BinaryWireProtobuf&& other) = default;
+
// Important: Deserialization could fail, for example data is truncated or
// some minor disc corruption occurred.
template <typename U>
- std::optional<U> MaybeUnserialize() {
- U unencoded;
+ std::optional<ProtobufPtr<U>> MaybeUnserialize() {
+ ProtobufMutablePtr<U> unencoded{new U{}};
- if (!unencoded.ParseFromArray(data_.data(), data_.size())) {
+ if (!unencoded->ParseFromArray(data_.data(), data_.size())) {
return std::nullopt;
}
@@ -94,10 +131,20 @@ struct BinaryWireProtobuf {
bool WriteFullyToFile(const std::string& path,
bool follow_symlinks = false) const;
+ static std::optional<BinaryWireProtobuf<T>> ReadFullyFromFile(const std::string& path,
+ bool follow_symlinks = false);
+
+ bool operator==(const BinaryWireProtobuf<T>& other) const;
+ bool operator!=(const BinaryWireProtobuf<T>& other) const {
+ return !(*this == other);
+ }
+
private:
static bool CleanUpAfterFailedWrite(const std::string& path);
bool WriteStringToFd(int fd) const;
+ static bool ReadFdToString(int fd, /*out*/std::vector<std::byte>* data);
+
std::vector<std::byte> data_;
};