Add a PackRemoteMessage method which doesn't malloc

This lets us pack directly into the buffer to write to disk, removing
mallocs and allowing us to fix heap fragmentation by reducing memory
churn.  A future patch will use it.

Change-Id: I05b312a4e4bf87f6da22f1d9a84ab71ec3ebab3d
Signed-off-by: Austin Schuh <austin.linux@gmail.com>
diff --git a/aos/events/logging/logfile_utils.cc b/aos/events/logging/logfile_utils.cc
index 2eeab52..7f32f44 100644
--- a/aos/events/logging/logfile_utils.cc
+++ b/aos/events/logging/logfile_utils.cc
@@ -285,6 +285,128 @@
   }
 }
 
+// Do the magic dance to convert the endianness of the data and append it to the
+// buffer.
+namespace {
+
+// TODO(austin): Look at the generated code to see if building the header is
+// efficient or not.
+template <typename T>
+uint8_t *Push(uint8_t *buffer, const T data) {
+  const T endian_data = flatbuffers::EndianScalar<T>(data);
+  std::memcpy(buffer, &endian_data, sizeof(T));
+  return buffer + sizeof(T);
+}
+
+uint8_t *PushBytes(uint8_t *buffer, const void *data, size_t size) {
+  std::memcpy(buffer, data, size);
+  return buffer + size;
+}
+
+uint8_t *Pad(uint8_t *buffer, size_t padding) {
+  std::memset(buffer, 0, padding);
+  return buffer + padding;
+}
+}  // namespace
+
+flatbuffers::Offset<MessageHeader> PackRemoteMessage(
+    flatbuffers::FlatBufferBuilder *fbb,
+    const message_bridge::RemoteMessage *msg, int channel_index,
+    const aos::monotonic_clock::time_point monotonic_timestamp_time) {
+  logger::MessageHeader::Builder message_header_builder(*fbb);
+  // Note: this must match the same order as MessageBridgeServer and
+  // PackMessage.  We want identical headers to have identical
+  // on-the-wire formats to make comparing them easier.
+
+  message_header_builder.add_channel_index(channel_index);
+
+  message_header_builder.add_queue_index(msg->queue_index());
+  message_header_builder.add_monotonic_sent_time(msg->monotonic_sent_time());
+  message_header_builder.add_realtime_sent_time(msg->realtime_sent_time());
+
+  message_header_builder.add_monotonic_remote_time(
+      msg->monotonic_remote_time());
+  message_header_builder.add_realtime_remote_time(msg->realtime_remote_time());
+  message_header_builder.add_remote_queue_index(msg->remote_queue_index());
+
+  message_header_builder.add_monotonic_timestamp_time(
+      monotonic_timestamp_time.time_since_epoch().count());
+
+  return message_header_builder.Finish();
+}
+
+size_t PackRemoteMessageInline(
+    uint8_t *buffer, const message_bridge::RemoteMessage *msg,
+    int channel_index,
+    const aos::monotonic_clock::time_point monotonic_timestamp_time) {
+  const flatbuffers::uoffset_t message_size = PackRemoteMessageSize();
+
+  // clang-format off
+  // header:
+  //   +0x00 | 5C 00 00 00             | UOffset32  | 0x0000005C (92) Loc: +0x5C                | size prefix
+  buffer = Push<flatbuffers::uoffset_t>(
+      buffer, message_size - sizeof(flatbuffers::uoffset_t));
+  //   +0x04 | 20 00 00 00             | UOffset32  | 0x00000020 (32) Loc: +0x24                | offset to root table `aos.logger.MessageHeader`
+  buffer = Push<flatbuffers::uoffset_t>(buffer, 0x20);
+  //
+  // padding:
+  //   +0x08 | 00 00 00 00 00 00       | uint8_t[6] | ......                                    | padding
+  buffer = Pad(buffer, 6);
+  //
+  // vtable (aos.logger.MessageHeader):
+  //   +0x0E | 16 00                   | uint16_t   | 0x0016 (22)                               | size of this vtable
+  buffer = Push<flatbuffers::voffset_t>(buffer, 0x16);
+  //   +0x10 | 3C 00                   | uint16_t   | 0x003C (60)                               | size of referring table
+  buffer = Push<flatbuffers::voffset_t>(buffer, 0x3c);
+  //   +0x12 | 38 00                   | VOffset16  | 0x0038 (56)                               | offset to field `channel_index` (id: 0)
+  buffer = Push<flatbuffers::voffset_t>(buffer, 0x38);
+  //   +0x14 | 2C 00                   | VOffset16  | 0x002C (44)                               | offset to field `monotonic_sent_time` (id: 1)
+  buffer = Push<flatbuffers::voffset_t>(buffer, 0x2c);
+  //   +0x16 | 24 00                   | VOffset16  | 0x0024 (36)                               | offset to field `realtime_sent_time` (id: 2)
+  buffer = Push<flatbuffers::voffset_t>(buffer, 0x24);
+  //   +0x18 | 34 00                   | VOffset16  | 0x0034 (52)                               | offset to field `queue_index` (id: 3)
+  buffer = Push<flatbuffers::voffset_t>(buffer, 0x34);
+  //   +0x1A | 00 00                   | VOffset16  | 0x0000 (0)                                | offset to field `data` (id: 4) <null> (Vector)
+  buffer = Push<flatbuffers::voffset_t>(buffer, 0x00);
+  //   +0x1C | 1C 00                   | VOffset16  | 0x001C (28)                               | offset to field `monotonic_remote_time` (id: 5)
+  buffer = Push<flatbuffers::voffset_t>(buffer, 0x1c);
+  //   +0x1E | 14 00                   | VOffset16  | 0x0014 (20)                               | offset to field `realtime_remote_time` (id: 6)
+  buffer = Push<flatbuffers::voffset_t>(buffer, 0x14);
+  //   +0x20 | 10 00                   | VOffset16  | 0x0010 (16)                               | offset to field `remote_queue_index` (id: 7)
+  buffer = Push<flatbuffers::voffset_t>(buffer, 0x10);
+  //   +0x22 | 04 00                   | VOffset16  | 0x0004 (4)                                | offset to field `monotonic_timestamp_time` (id: 8)
+  buffer = Push<flatbuffers::voffset_t>(buffer, 0x04);
+  //
+  // root_table (aos.logger.MessageHeader):
+  //   +0x24 | 16 00 00 00             | SOffset32  | 0x00000016 (22) Loc: +0x0E                | offset to vtable
+  buffer = Push<flatbuffers::uoffset_t>(buffer, 0x16);
+  //   +0x28 | F6 0B D8 11 A4 A8 B1 71 | int64_t    | 0x71B1A8A411D80BF6 (8192514619791117302)  | table field `monotonic_timestamp_time` (Long)
+  buffer = Push<int64_t>(buffer,
+                         monotonic_timestamp_time.time_since_epoch().count());
+  //   +0x30 | 00 00 00 00             | uint8_t[4] | ....                                      | padding
+  // TODO(austin): Can we re-arrange the order to ditch the padding?
+  // (Answer is yes, but what is the impact elsewhere?  It will change the
+  // binary format)
+  buffer = Pad(buffer, 4);
+  //   +0x34 | 75 00 00 00             | uint32_t   | 0x00000075 (117)                          | table field `remote_queue_index` (UInt)
+  buffer = Push<uint32_t>(buffer, msg->remote_queue_index());
+  //   +0x38 | AA B0 43 0A 35 BE FA D2 | int64_t    | 0xD2FABE350A43B0AA (-3244071446552268630) | table field `realtime_remote_time` (Long)
+  buffer = Push<int64_t>(buffer, msg->realtime_remote_time());
+  //   +0x40 | D5 40 30 F3 C1 A7 26 1D | int64_t    | 0x1D26A7C1F33040D5 (2100550727665467605)  | table field `monotonic_remote_time` (Long)
+  buffer = Push<int64_t>(buffer, msg->monotonic_remote_time());
+  //   +0x48 | 5B 25 32 A1 4A E8 46 CA | int64_t    | 0xCA46E84AA132255B (-3871151422448720549) | table field `realtime_sent_time` (Long)
+  buffer = Push<int64_t>(buffer, msg->realtime_sent_time());
+  //   +0x50 | 49 7D 45 1F 8C 36 6B A3 | int64_t    | 0xA36B368C1F457D49 (-6671178447571288759) | table field `monotonic_sent_time` (Long)
+  buffer = Push<int64_t>(buffer, msg->monotonic_sent_time());
+  //   +0x58 | 33 00 00 00             | uint32_t   | 0x00000033 (51)                           | table field `queue_index` (UInt)
+  buffer = Push<uint32_t>(buffer, msg->queue_index());
+  //   +0x5C | 76 00 00 00             | uint32_t   | 0x00000076 (118)                          | table field `channel_index` (UInt)
+  buffer = Push<uint32_t>(buffer, channel_index);
+  // clang-format on
+
+  return message_size;
+}
+
 flatbuffers::Offset<MessageHeader> PackMessage(
     flatbuffers::FlatBufferBuilder *fbb, const Context &context,
     int channel_index, LogType log_type) {
@@ -472,30 +594,6 @@
   LOG(FATAL);
 }
 
-// Do the magic dance to convert the endianness of the data and append it to the
-// buffer.
-namespace {
-
-// TODO(austin): Look at the generated code to see if building the header is
-// efficient or not.
-template <typename T>
-uint8_t *Push(uint8_t *buffer, const T data) {
-  const T endian_data = flatbuffers::EndianScalar<T>(data);
-  std::memcpy(buffer, &endian_data, sizeof(T));
-  return buffer + sizeof(T);
-}
-
-uint8_t *PushBytes(uint8_t *buffer, const void *data, size_t size) {
-  std::memcpy(buffer, data, size);
-  return buffer + size;
-}
-
-uint8_t *Pad(uint8_t *buffer, size_t padding) {
-  std::memset(buffer, 0, padding);
-  return buffer + padding;
-}
-}  // namespace
-
 size_t PackMessageInline(uint8_t *buffer, const Context &context,
                          int channel_index, LogType log_type) {
   const flatbuffers::uoffset_t message_size =