wrote the stuff for putting MessageTypes in shm (untested)
diff --git a/aos/common/common.gyp b/aos/common/common.gyp
index 00697b4..d7ec2d2 100644
--- a/aos/common/common.gyp
+++ b/aos/common/common.gyp
@@ -47,6 +47,11 @@
       'sources': [
         'queue_types.cc',
       ],
+      'dependencies': [
+        '<(AOS)/build/aos.gyp:logging_interface',
+        '<(AOS)/linux_code/ipc_lib/ipc_lib.gyp:shared_mem',
+        '<(AOS)/linux_code/ipc_lib/ipc_lib.gyp:core_lib',
+      ],
     },
     {
       'target_name': 'queue_types_test',
diff --git a/aos/common/logging/logging.gyp b/aos/common/logging/logging.gyp
index b6b339a..ad20166 100644
--- a/aos/common/logging/logging.gyp
+++ b/aos/common/logging/logging.gyp
@@ -11,5 +11,15 @@
         '<(AOS)/build/aos.gyp:logging',
       ],
     },
+    {
+      'target_name': 'queue_logging',
+      'type': 'static_library',
+      'sources': [
+        'queue_logging.cc',
+      ],
+      'dependencies': [
+        '<(AOS)/common/common.gyp:queue_types',
+      ],
+    },
   ],
 }
diff --git a/aos/common/queue_types.cc b/aos/common/queue_types.cc
index 03d048a..a1925e9 100644
--- a/aos/common/queue_types.cc
+++ b/aos/common/queue_types.cc
@@ -1,10 +1,14 @@
 #include "aos/common/queue_types.h"
 
-#include <errno.h>
+#include <inttypes.h>
 
 #include <memory>
+#include <unordered_map>
 
 #include "aos/common/byteorder.h"
+#include "aos/linux_code/ipc_lib/shared_mem.h"
+#include "aos/common/logging/logging.h"
+#include "aos/linux_code/ipc_lib/core_lib.h"
 
 namespace aos {
 
@@ -20,7 +24,6 @@
   }
   if (max_bytes < sizeof(id) + sizeof(name_length) + sizeof(number_fields) +
                       name_length + fields_size) {
-    errno = EOVERFLOW;
     return -1;
   }
   to_network(&id, buffer);
@@ -49,7 +52,6 @@
   decltype(MessageType::id) id;
   decltype(MessageType::number_fields) number_fields;
   if (*bytes < sizeof(id) + sizeof(name_length) + sizeof(number_fields)) {
-    errno = EOVERFLOW;
     return nullptr;
   }
   *bytes -= sizeof(id) + sizeof(name_length) + sizeof(number_fields);
@@ -62,7 +64,6 @@
   buffer += sizeof(number_fields);
 
   if (*bytes < name_length) {
-    errno = EOVERFLOW;
     return nullptr;
   }
   *bytes -= name_length;
@@ -79,7 +80,6 @@
   for (int i = 0; i < number_fields; ++i) {
     size_t field_name_length;
     if (*bytes < sizeof(fields[i]->type) + sizeof(field_name_length)) {
-      errno = EOVERFLOW;
       return nullptr;
     }
     *bytes -= sizeof(fields[i]->type) + sizeof(field_name_length);
@@ -90,7 +90,6 @@
     buffer += sizeof(field_name_length);
 
     if (*bytes < field_name_length) {
-      errno = EOVERFLOW;
       return nullptr;
     }
     *bytes -= field_name_length;
@@ -104,4 +103,95 @@
   return r.release();
 }
 
+namespace type_cache {
+namespace {
+
+struct CacheEntry {
+  const MessageType &type;
+  bool in_shm;
+
+  CacheEntry(const MessageType &type) : type(type), in_shm(false) {}
+};
+
+struct ShmType {
+  uint32_t id;
+  volatile ShmType *next;
+
+  size_t serialized_size;
+  char serialized[];
+};
+
+::std::unordered_map<uint32_t, CacheEntry> cache;
+
+}  // namespace
+
+void Add(const MessageType &type) {
+  if (cache.count(type.id) == 0) {
+    cache.emplace(type.id, type);
+  }
+}
+
+const MessageType &Get(uint32_t type_id) {
+  if (cache.count(type_id) > 0) {
+    return cache.at(type_id).type;
+  }
+
+  const volatile ShmType *c = static_cast<volatile ShmType *>(
+      global_core->mem_struct->queue_types.pointer);
+  while (c != nullptr) {
+    if (c->id == type_id) {
+      size_t bytes = c->serialized_size;
+      MessageType *type = MessageType::Deserialize(
+          const_cast<const char *>(c->serialized), &bytes);
+      cache.emplace(type_id, *type);
+      return *type;
+    }
+    c = c->next;
+  }
+  LOG(FATAL, "MessageType for id 0x%" PRIx32 " not found\n", type_id);
+}
+
+void AddShm(uint32_t type_id) {
+  CacheEntry &cached = cache.at(type_id);
+  if (cached.in_shm) return;
+
+  if (mutex_lock(&global_core->mem_struct->queue_types.lock) != 0) {
+    LOG(FATAL, "locking queue_types lock failed\n");
+  }
+  volatile ShmType *current = static_cast<volatile ShmType *>(
+      global_core->mem_struct->queue_types.pointer);
+  if (current != nullptr) {
+    while (true) {
+      if (current->id == type_id) {
+        cached.in_shm = true;
+        mutex_unlock(&global_core->mem_struct->queue_types.lock);
+        return;
+      }
+      if (current->next == nullptr) break;
+      current = current->next;
+    }
+  }
+  char buffer[512];
+  ssize_t size = cached.type.Serialize(buffer, sizeof(buffer));
+  if (size == -1) {
+    LOG(FATAL, "type %s is too big to fit into %zd bytes\n",
+        cached.type.name, sizeof(buffer));
+  }
+
+  volatile ShmType *shm =
+      static_cast<volatile ShmType *>(shm_malloc(sizeof(ShmType) + size));
+  shm->id = type_id;
+  shm->next = nullptr;
+  shm->serialized_size = size;
+  memcpy(const_cast<char *>(shm->serialized), buffer, size);
+
+  if (current == NULL) {
+    global_core->mem_struct->queue_types.pointer = const_cast<ShmType *>(shm);
+  } else {
+    current->next = shm;
+  }
+  mutex_unlock(&global_core->mem_struct->queue_types.lock);
+}
+
+}  // namespace type_cache
 }  // namespace aos
diff --git a/aos/common/queue_types.h b/aos/common/queue_types.h
index ddc6aea..ba1d7fb 100644
--- a/aos/common/queue_types.h
+++ b/aos/common/queue_types.h
@@ -39,7 +39,7 @@
   // Constructs a MessageType that doesn't own the storage for any of its
   // names.
   MessageType(uint32_t id, const char *name,
-              ::std::initializer_list<Field *> fields_initializer)
+              ::std::initializer_list<const Field *> fields_initializer)
       : id(id), name(name), owns_names(false) {
     number_fields = fields_initializer.size();
     fields = new const Field *[number_fields];
@@ -61,11 +61,11 @@
     }
   }
 
-  // Returns -1 for error (in errno).
+  // Returns -1 if max_bytes is too small.
   ssize_t Serialize(char *buffer, size_t max_bytes) const;
   // bytes should start out as the number of bytes available in buffer and gets
   // reduced by the number actually read before returning.
-  // Returns a new instance allocated with new or NULL for error (in errno).
+  // Returns a new instance allocated with new or nullptr for error.
   static MessageType *Deserialize(const char *buffer, size_t *bytes);
 
   static bool IsPrimitive(uint32_t type_id) {
diff --git a/aos/common/queue_types_test.cc b/aos/common/queue_types_test.cc
index 38334df..bd95e3a 100644
--- a/aos/common/queue_types_test.cc
+++ b/aos/common/queue_types_test.cc
@@ -13,15 +13,59 @@
                                      new Field{0, "field2"},
                                      new Field{0, "field3"}});
 
-TEST(QueueTypesTest, Serialization) {
+class QueueTypesTest : public ::testing::Test {
+ public:
+  ::testing::AssertionResult Equal(const MessageType &l, const MessageType &r) {
+    using ::testing::AssertionFailure;
+    if (l.id != r.id) {
+      return AssertionFailure() << "id " << l.id << " != " << r.id;
+    }
+    if (strcmp(l.name, r.name) != 0) {
+      return AssertionFailure() << "name '" << l.name << "' != '" << r.name
+                                << "'";
+    }
+    if (l.number_fields != r.number_fields) {
+      return AssertionFailure() << "number_fields " << l.number_fields
+                                << " != " << r.number_fields;
+    }
+    for (int i = 0; i < l.number_fields; ++i) {
+      SCOPED_TRACE("field " + ::std::to_string(i));
+      if (l.fields[i]->type != r.fields[i]->type) {
+        return AssertionFailure() << "type " << l.fields[i]->type
+                                  << " != " << r.fields[i]->type;
+      }
+      if (strcmp(l.fields[i]->name, r.fields[i]->name) != 0) {
+        return AssertionFailure() << "name '" << l.fields[i]->name << "' != '"
+                                  << r.fields[i]->name << "'";
+      }
+    }
+    return ::testing::AssertionSuccess();
+  }
+};
+
+TEST_F(QueueTypesTest, Serialization) {
   char buffer[512];
   ssize_t size;
+  size_t out_size;
+  ::std::unique_ptr<MessageType> deserialized;
 
   size = kTestType1.Serialize(buffer, sizeof(buffer));
   EXPECT_GT(size, 1);
-  size_t out_size = size;
-  ::std::unique_ptr<MessageType> deserialized(MessageType::Deserialize(buffer, &out_size));
+
+  out_size = size;
+  deserialized.reset(MessageType::Deserialize(buffer, &out_size));
   EXPECT_EQ(0u, out_size);
+  EXPECT_TRUE(Equal(kTestType1, *deserialized));
+
+  out_size = size - 1;
+  deserialized.reset(MessageType::Deserialize(buffer, &out_size));
+  EXPECT_EQ(nullptr, deserialized.get());
+
+  out_size = size + 1;
+  ASSERT_LE(out_size, sizeof(buffer));
+  deserialized.reset(MessageType::Deserialize(buffer, &out_size));
+  EXPECT_EQ(1u, out_size);
+  EXPECT_TRUE(Equal(kTestType1, *deserialized));
 }
 
 }  // namespace aos