actually write matrix logs to the log file
diff --git a/aos/linux_code/logging/binary_log_file.h b/aos/linux_code/logging/binary_log_file.h
index 72aac09..f25482c 100644
--- a/aos/linux_code/logging/binary_log_file.h
+++ b/aos/linux_code/logging/binary_log_file.h
@@ -39,6 +39,7 @@
     kString,
     kStructType,
     kStruct,
+    kMatrix,
   };
 
   // Gets futex_set once this one has been written
diff --git a/aos/linux_code/logging/binary_log_writer.cc b/aos/linux_code/logging/binary_log_writer.cc
index 76b53ef..d689109 100644
--- a/aos/linux_code/logging/binary_log_writer.cc
+++ b/aos/linux_code/logging/binary_log_writer.cc
@@ -154,12 +154,17 @@
     const LogMessage *const msg = ReadNext();
     if (msg == NULL) continue;
 
-    size_t output_length =
+    const size_t raw_output_length =
         sizeof(LogFileMessageHeader) + msg->name_length + msg->message_length;
+    size_t output_length = raw_output_length;
     if (msg->type == LogMessage::Type::kStruct) {
       output_length += sizeof(msg->structure.type_id) + sizeof(uint32_t) +
                        msg->structure.string_length;
       CheckTypeWritten(msg->structure.type_id, writer);
+    } else if (msg->type == LogMessage::Type::kMatrix) {
+      output_length +=
+          sizeof(msg->matrix.type) + sizeof(uint32_t) + sizeof(uint16_t) +
+          sizeof(uint16_t) + msg->matrix.string_length;
     }
     LogFileMessageHeader *const output = writer.GetWritePosition(output_length);;
     char *output_strings = reinterpret_cast<char *>(output) + sizeof(*output);
@@ -209,9 +214,7 @@
         uint32_t length = msg->matrix.string_length;
         memcpy(position, &length, sizeof(length));
         position += sizeof(length);
-        memcpy(position, msg->matrix.data, length);
-        position += length;
-        output->message_size += sizeof(length) + length;
+        output->message_size += sizeof(length);
 
         uint16_t rows = msg->matrix.rows, cols = msg->matrix.cols;
         memcpy(position, &rows, sizeof(rows));
@@ -222,12 +225,19 @@
         CHECK_EQ(msg->message_length,
                  MessageType::Sizeof(msg->matrix.type) * rows * cols);
 
-        memcpy(position,
-               msg->matrix.data + msg->matrix.string_length,
-               msg->message_length);
+        memcpy(position, msg->matrix.data, msg->message_length + length);
+        output->message_size += length;
+
+        output->type = LogFileMessageHeader::MessageType::kMatrix;
       } break;
     }
 
+    if (output->message_size - msg->message_length !=
+        output_length - raw_output_length) {
+      LOG(FATAL, "%zu != %zu\n", output->message_size - msg->message_length,
+          output_length - raw_output_length);
+    }
+
     futex_set(&output->marker);
 
     logging::linux_code::Free(msg);
diff --git a/aos/linux_code/logging/linux_logging.cc b/aos/linux_code/logging/linux_logging.cc
index dc322ed..aed8697 100644
--- a/aos/linux_code/logging/linux_logging.cc
+++ b/aos/linux_code/logging/linux_logging.cc
@@ -52,6 +52,15 @@
                                      serialize, message);
     Write(message);
   }
+
+  virtual void LogMatrix(log_level level, const ::std::string &message_string,
+                         uint32_t type_id, int rows, int cols, const void *data)
+      override {
+    LogMessage *message = GetMessageOrDie();
+    internal::FillInMessageMatrix(level, message_string, type_id, rows, cols,
+                                  data, message);
+    Write(message);
+  }
 };
 
 }  // namespace
diff --git a/aos/linux_code/logging/log_displayer.cc b/aos/linux_code/logging/log_displayer.cc
index 98021b5..1cc5f43 100644
--- a/aos/linux_code/logging/log_displayer.cc
+++ b/aos/linux_code/logging/log_displayer.cc
@@ -227,7 +227,39 @@
         log_message.type = ::aos::logging::LogMessage::Type::kStruct;
         break;
       }
-      case LogFileMessageHeader::MessageType::kString:
+      case LogFileMessageHeader::MessageType::kMatrix: {
+        const char *position =
+            reinterpret_cast<const char *>(msg + 1) + msg->name_size;
+        memcpy(&log_message.matrix.type, position,
+               sizeof(log_message.matrix.type));
+        position += sizeof(log_message.matrix.type);
+
+        uint32_t length;
+        memcpy(&length, position, sizeof(length));
+        log_message.matrix.string_length = length;
+        position += sizeof(length);
+
+        uint16_t rows;
+        memcpy(&rows, position, sizeof(rows));
+        log_message.matrix.rows = rows;
+        position += sizeof(rows);
+        uint16_t cols;
+        memcpy(&cols, position, sizeof(cols));
+        log_message.matrix.cols = cols;
+        position += sizeof(cols);
+
+        log_message.message_length -=
+            sizeof(log_message.matrix.type) + sizeof(uint32_t) +
+            sizeof(uint16_t) + sizeof(uint16_t) + length;
+        CHECK_EQ(
+            log_message.message_length,
+            ::aos::MessageType::Sizeof(log_message.matrix.type) * rows * cols);
+        memcpy(log_message.matrix.data, position,
+               log_message.message_length + length);
+
+        log_message.type = ::aos::logging::LogMessage::Type::kMatrix;
+        break;
+      } case LogFileMessageHeader::MessageType::kString:
         memcpy(
             log_message.message,
             reinterpret_cast<const char *>(msg) + sizeof(*msg) + msg->name_size,