Snap for 4796401 from 9947cc79447f3ee36ddb8c64f429eb96f11c6304 to pi-release

Change-Id: I24a328dc5b6228cf3a8bce638d9acff79480e005
diff --git a/common/vsoc/lib/vsoc_memory.cpp b/common/vsoc/lib/vsoc_memory.cpp
index f05b0b8..04f90bd 100644
--- a/common/vsoc/lib/vsoc_memory.cpp
+++ b/common/vsoc/lib/vsoc_memory.cpp
@@ -16,84 +16,361 @@
 
 #include "common/vsoc/lib/vsoc_memory.h"
 
+#include <string.h>
+#include <unistd.h>
+
+#include <map>
 #include <string>
 #include <type_traits>
 
+#include "common/libs/glog/logging.h"
 #include "common/vsoc/shm/audio_data_layout.h"
+#include "common/vsoc/shm/base.h"
 #include "common/vsoc/shm/e2e_test_region_layout.h"
 #include "common/vsoc/shm/gralloc_layout.h"
 #include "common/vsoc/shm/input_events_layout.h"
 #include "common/vsoc/shm/ril_layout.h"
 #include "common/vsoc/shm/screen_layout.h"
 #include "common/vsoc/shm/socket_forward_layout.h"
-#include "common/vsoc/shm/version.h"
 #include "common/vsoc/shm/wifi_exchange_layout.h"
 
+#include "uapi/vsoc_shm.h"
+
+namespace {
+
+uint32_t AlignToPageSize(uint32_t val) {
+  static uint32_t page_size = sysconf(_SC_PAGESIZE);
+  return ((val + (page_size - 1)) / page_size) * page_size;
+}
+
+uint32_t AlignToPowerOf2(uint32_t val) {
+  uint32_t power_of_2 = 1;
+  while (power_of_2 < val) {
+    power_of_2 *= 2;
+  }
+  return power_of_2;
+}
+
+// Takes a vector of objects and returns a vector of pointers to those objects.
+template <typename T, typename R>
+std::vector<R*> GetConstPointers(const std::vector<T>& v) {
+  std::vector<R*> result;
+  result.reserve(v.size());
+  for (auto& element : v) {
+    result.push_back(&element);
+  }
+  return result;
+}
+}  // namespace
+
 namespace vsoc {
 
-// ShmTypeValidator provides meaningful information about the type size
-// mismatch in compilation error messages, eg.
-//
-// error:
-//    static_assert failed "Class size changed, update version.h"
-//    static_assert(Current == Expected,
-// note: in instantiation of template class
-//    'ShmTypeValidator<vsoc::layout::myclass::ClassName, 1232, 1240>'
-//    requested here ASSERT_SHM_COMPATIBLE(ClassName, myclass);
-//
-template <typename Type, size_t Current, size_t Expected>
-struct ShmTypeValidator {
-  static_assert(Current == Expected, "Class size changed, update version.h");
-  static_assert(std::is_trivial<Type>(), "Class uses features that are unsafe");
-  static constexpr bool valid =
-      (Current == Expected) && std::is_trivial<Type>();
+namespace {
+
+class VSoCRegionLayoutImpl : public VSoCRegionLayout {
+ public:
+  VSoCRegionLayoutImpl(const char* region_name, size_t layout_size,
+                       int guest_to_host_signal_table_log_size,
+                       int host_to_guest_signal_table_log_size,
+                       const char* managed_by)
+      : region_name_(region_name),
+        layout_size_(layout_size),
+        guest_to_host_signal_table_log_size_(
+            guest_to_host_signal_table_log_size),
+        host_to_guest_signal_table_log_size_(
+            host_to_guest_signal_table_log_size),
+        managed_by_(managed_by) {
+    size_ = GetMinRegionSize();
+    LOG(INFO) << region_name << ": is " << size_;
+  }
+  VSoCRegionLayoutImpl(const VSoCRegionLayoutImpl&) = default;
+
+  const char* region_name() const override { return region_name_; }
+  const char* managed_by() const override { return managed_by_; }
+
+  size_t layout_size() const override { return layout_size_; }
+  int guest_to_host_signal_table_log_size() const override {
+    return guest_to_host_signal_table_log_size_;
+  }
+  int host_to_guest_signal_table_log_size() const override {
+    return host_to_guest_signal_table_log_size_;
+  }
+  uint32_t begin_offset() const override { return begin_offset_; }
+  size_t region_size() const override { return size_; }
+  void SetRegionSize(size_t size) { size_ = size; }
+  void SetBeginOffset(uint32_t offset) { begin_offset_ = offset; }
+
+  // Returns the minimum size the region needs to accomodate the signaling
+  // section and the data layout.
+  size_t GetMinRegionSize() const {
+    auto size = GetOffsetOfRegionData();
+    // Data section
+    size += layout_size_;
+    size = AlignToPageSize(size);
+    return size;
+  }
+
+  uint32_t GetOffsetOfRegionData() const {
+    uint32_t offset = 0;
+    // Signal tables
+    offset += (1 << guest_to_host_signal_table_log_size_) * sizeof(uint32_t);
+    offset += (1 << host_to_guest_signal_table_log_size_) * sizeof(uint32_t);
+    // Interrup signals
+    offset += 2 * sizeof(uint32_t);
+    return offset;
+  }
+
+ private:
+  const char* region_name_{};
+  const size_t layout_size_{};
+  const int guest_to_host_signal_table_log_size_{};
+  const int host_to_guest_signal_table_log_size_{};
+  const char* managed_by_{};
+  uint32_t begin_offset_{};
+  size_t size_{};
 };
 
-namespace {
+class VSoCMemoryLayoutImpl : public VSoCMemoryLayout {
+ public:
+  explicit VSoCMemoryLayoutImpl(std::vector<VSoCRegionLayoutImpl>&& regions)
+      : regions_(regions), region_idx_by_name_(GetNameToIndexMap(regions)) {
+    for (size_t i = 0; i < regions_.size(); ++i) {
+      // This link could be resolved later, but doing it here disables
+      // managed_by cycles among the regions.
+      if (regions[i].managed_by() &&
+          !region_idx_by_name_.count(regions[i].managed_by())) {
+        LOG(FATAL) << regions[i].region_name()
+                   << " managed by unknown region: " << regions[i].managed_by()
+                   << ". Manager Regions must be declared before the regions "
+                      "they manage";
+      }
+    }
+
+    uint32_t offset = 0;
+    // Reserve space for global header
+    offset += sizeof(vsoc_shm_layout_descriptor);
+    // and region descriptors
+    offset += regions_.size() * sizeof(vsoc_device_region);
+    offset = AlignToPageSize(offset);
+
+    // Calculate offsets for all regions and set the size of the device
+    UpdateRegionOffsetsAndDeviceSize(offset);
+  }
+
+  ~VSoCMemoryLayoutImpl() = default;
+
+  std::vector<const VSoCRegionLayout*> GetRegions() const {
+    static std::vector<const VSoCRegionLayout*> ret =
+        GetConstPointers<VSoCRegionLayoutImpl, const VSoCRegionLayout>(
+            regions_);
+    return ret;
+  }
+
+  const VSoCRegionLayout* GetRegionByName(
+      const char* region_name) const override {
+    if (!region_idx_by_name_.count(region_name)) {
+      return nullptr;
+    }
+    return &regions_[region_idx_by_name_.at(region_name)];
+  }
+
+  uint32_t GetMemoryFileSize() const override { return device_size_; }
+
+  void WriteLayout(void* shared_memory) const override;
+
+  bool ResizeRegion(const char* region_name, size_t new_min_size) override {
+    if (!region_idx_by_name_.count(region_name)) {
+      LOG(ERROR) << "Unable to resize region: " << region_name
+                 << ". Region not found";
+      return false;
+    }
+    auto index = region_idx_by_name_.at(region_name);
+    auto& region = regions_[index];
+    auto min_required_size = region.GetMinRegionSize();
+
+    // Align to page size
+    new_min_size = AlignToPageSize(new_min_size);
+    if (new_min_size < min_required_size) {
+      LOG(ERROR) << "Requested resize of region " << region_name << " to "
+                 << new_min_size << " (after alignment), it needs at least "
+                 << min_required_size << " bytes.";
+      return false;
+    }
+
+    region.SetRegionSize(new_min_size);
+
+    // Get new offset for next region
+    auto offset = region.begin_offset() + region.region_size();
+    // Update offsets for all following regions
+    UpdateRegionOffsetsAndDeviceSize(offset, index + 1);
+    return true;
+  }
+
+ protected:
+  VSoCMemoryLayoutImpl() = delete;
+  VSoCMemoryLayoutImpl(const VSoCMemoryLayoutImpl&) = delete;
+
+  // Helper function to allow the creation of the name to index map in the
+  // constructor and allow the field to be const
+  static std::map<const char*, size_t> GetNameToIndexMap(
+      const std::vector<VSoCRegionLayoutImpl>& regions) {
+    std::map<const char*, size_t> result;
+    for (size_t index = 0; index < regions.size(); ++index) {
+      auto region_name = regions[index].region_name();
+      if (result.count(region_name)) {
+        LOG(FATAL) << region_name << " used for more than one region";
+      }
+      result[region_name] = index;
+    }
+    return result;
+  }
+
+  // Updates the beginning offset of all regions starting at a specific index
+  // (useful after a resize operation) and the device's size.
+  void UpdateRegionOffsetsAndDeviceSize(uint32_t offset, size_t index = 0) {
+    for (; index < regions_.size(); ++index) {
+      regions_[index].SetBeginOffset(offset);
+      offset += regions_[index].region_size();
+    }
+
+    // Make the device's size the smaller power of two possible
+    device_size_ = AlignToPowerOf2(offset);
+  }
+
+  std::vector<VSoCRegionLayoutImpl> regions_;
+  const std::map<const char*, size_t> region_idx_by_name_;
+  uint32_t device_size_{};
+};
+
+// Writes a region's signal table layout to shared memory. Returns the region
+// offset of free memory after the table and interrupt signaled word.
+uint32_t WriteSignalTableDescription(vsoc_signal_table_layout* layout,
+                                     uint32_t offset, int log_size) {
+  layout->num_nodes_lg2 = log_size;
+  // First the signal table
+  layout->futex_uaddr_table_offset = offset;
+  offset += (1 << log_size) * sizeof(uint32_t);
+  // Then the interrupt signaled word
+  layout->interrupt_signalled_offset = offset;
+  offset += sizeof(uint32_t);
+  return offset;
+}
+
+// Writes a region's layout description to shared memory
+void WriteRegionDescription(vsoc_device_region* shmem_region_desc,
+                            const VSoCRegionLayoutImpl& region) {
+  // Region versions are deprecated, write some sensible value
+  shmem_region_desc->current_version = 0;
+  shmem_region_desc->min_compatible_version = 0;
+
+  shmem_region_desc->region_begin_offset = region.begin_offset();
+  shmem_region_desc->region_end_offset =
+      region.begin_offset() + region.region_size();
+  shmem_region_desc->offset_of_region_data = region.GetOffsetOfRegionData();
+  strncpy(shmem_region_desc->device_name, region.region_name(),
+          VSOC_DEVICE_NAME_SZ - 1);
+  shmem_region_desc->device_name[VSOC_DEVICE_NAME_SZ - 1] = '\0';
+  // Guest to host signal table at the beginning of the region
+  uint32_t offset = 0;
+  offset = WriteSignalTableDescription(
+      &shmem_region_desc->guest_to_host_signal_table, offset,
+      region.guest_to_host_signal_table_log_size());
+  // Host to guest signal table right after
+  offset = WriteSignalTableDescription(
+      &shmem_region_desc->host_to_guest_signal_table, offset,
+      region.host_to_guest_signal_table_log_size());
+  // Double check that the region metadata does not collide with the data
+  if (offset > shmem_region_desc->offset_of_region_data) {
+    LOG(FATAL) << "Error: Offset of region data too small (is "
+               << shmem_region_desc->offset_of_region_data << " should be "
+               << offset << " ) for region " << region.region_name()
+               << ". This is a bug";
+  }
+}
+
+void VSoCMemoryLayoutImpl::WriteLayout(void* shared_memory) const {
+  // Device header
+  static_assert(CURRENT_VSOC_LAYOUT_MAJOR_VERSION == 2,
+                "Region layout code must be updated");
+  auto header = reinterpret_cast<vsoc_shm_layout_descriptor*>(shared_memory);
+  header->major_version = CURRENT_VSOC_LAYOUT_MAJOR_VERSION;
+  header->minor_version = CURRENT_VSOC_LAYOUT_MINOR_VERSION;
+  header->size = GetMemoryFileSize();
+  header->region_count = regions_.size();
+
+  // Region descriptions go right after the layout descriptor
+  header->vsoc_region_desc_offset = sizeof(vsoc_shm_layout_descriptor);
+  auto region_descriptions = reinterpret_cast<vsoc_device_region*>(header + 1);
+  for (size_t idx = 0; idx < regions_.size(); ++idx) {
+    auto shmem_region_desc = &region_descriptions[idx];
+    const auto& region = regions_[idx];
+    WriteRegionDescription(shmem_region_desc, region);
+    // Handle managed_by links
+    if (region.managed_by()) {
+      auto manager_idx = region_idx_by_name_.at(region.managed_by());
+      if (manager_idx == VSOC_REGION_WHOLE) {
+        LOG(FATAL) << "Region '" << region.region_name() << "' has owner "
+                   << region.managed_by() << " with index " << manager_idx
+                   << " which is the default value for regions without an "
+                      "owner. Choose a different region to be at index "
+                   << manager_idx
+                   << ", make sure the chosen region is NOT the owner of any "
+                      "other region";
+      }
+      shmem_region_desc->managed_by = manager_idx;
+    } else {
+      shmem_region_desc->managed_by = VSOC_REGION_WHOLE;
+    }
+  }
+}
+
 template <class R>
-RegionMemoryLayout ValidateAndBuildLayout(int region_size,
-                                          int g_to_h_signal_table_log_size,
-                                          int h_to_g_signal_table_log_size,
-                                          const char* managed_by = nullptr) {
-  static_assert(
-      ShmTypeValidator<R, sizeof(R), vsoc::layout::VersionInfo<R>::size>::valid,
-      "Compilation error. Please fix above errors and retry.");
-  return RegionMemoryLayout(R::region_name, region_size,
-                            g_to_h_signal_table_log_size,
-                            h_to_g_signal_table_log_size, managed_by);
+VSoCRegionLayoutImpl ValidateAndBuildLayout(int g_to_h_signal_table_log_size,
+                                            int h_to_g_signal_table_log_size,
+                                            const char* managed_by = nullptr) {
+  // Double check that the Layout is a valid shm type.
+  ASSERT_SHM_COMPATIBLE(R);
+  return VSoCRegionLayoutImpl(R::region_name, sizeof(R),
+                              g_to_h_signal_table_log_size,
+                              h_to_g_signal_table_log_size, managed_by);
 }
 
 }  // namespace
 
-const std::vector<RegionMemoryLayout>& GetVsocMemoryLayout() {
-  static const std::vector<RegionMemoryLayout> layout = {
-      ValidateAndBuildLayout<layout::input_events::InputEventsLayout>(
-          /*size*/ 4096, /*g->h*/ 2, /*h->g*/ 2),
-      ValidateAndBuildLayout<layout::screen::ScreenLayout>(
-          /*size*/ 12292096, /*g->h*/ 2, /*h->g*/ 2),
-      ValidateAndBuildLayout<layout::gralloc::GrallocManagerLayout>(
-          /*size*/ 40960, /*g->h*/ 2, /*h->g*/ 2),
-      ValidateAndBuildLayout<layout::gralloc::GrallocBufferLayout>(
-          /*size*/ 407142400, /*g->h*/ 0, /*h->g*/ 0,
-          /* managed_by */ layout::gralloc::GrallocManagerLayout::region_name),
-      ValidateAndBuildLayout<layout::socket_forward::SocketForwardLayout>(
-          /*size*/ 2105344, /*g->h*/ 7, /*h->g*/ 7),
-      ValidateAndBuildLayout<layout::wifi::WifiExchangeLayout>(
-          /*size*/ 139264, /*g->h*/ 2, /*h->g*/ 2),
-      ValidateAndBuildLayout<layout::ril::RilLayout>(
-          /*size*/ 4096, /*g->h*/ 2, /*h->g*/ 2),
-      ValidateAndBuildLayout<layout::e2e_test::E2EPrimaryTestRegionLayout>(
-          /*size*/ 16384, /*g->h*/ 1, /*h->g*/ 1),
-      ValidateAndBuildLayout<layout::e2e_test::E2ESecondaryTestRegionLayout>(
-          /*size*/ 16384, /*g->h*/ 1, /*h->g*/ 1),
-      ValidateAndBuildLayout<layout::e2e_test::E2EManagerTestRegionLayout>(
-          /*size*/ 4096, /*g->h*/ 1, /*h->g*/ 1),
-      ValidateAndBuildLayout<layout::e2e_test::E2EManagedTestRegionLayout>(
-          /*size*/ 16384, /*g->h*/ 1, /*h->g*/ 1),
-      ValidateAndBuildLayout<layout::audio_data::AudioDataLayout>(
-          /*size*/ 20480, /*g->h*/ 2, /*h->g*/ 2)};
+VSoCMemoryLayout* VSoCMemoryLayout::Get() {
+  /*******************************************************************
+   * Make sure the first region is not the manager of other regions. *
+   *       This error will only be caught on runtime!!!!!            *
+   *******************************************************************/
+  static VSoCMemoryLayoutImpl layout(
+      {ValidateAndBuildLayout<layout::input_events::InputEventsLayout>(2, 2),
+       ValidateAndBuildLayout<layout::screen::ScreenLayout>(2, 2),
+       ValidateAndBuildLayout<layout::gralloc::GrallocManagerLayout>(2, 2),
+       ValidateAndBuildLayout<layout::gralloc::GrallocBufferLayout>(
+           0, 0,
+           /* managed_by */ layout::gralloc::GrallocManagerLayout::region_name),
+       ValidateAndBuildLayout<layout::socket_forward::SocketForwardLayout>(7,
+                                                                           7),
+       ValidateAndBuildLayout<layout::wifi::WifiExchangeLayout>(2, 2),
+       ValidateAndBuildLayout<layout::ril::RilLayout>(2, 2),
+       ValidateAndBuildLayout<layout::e2e_test::E2EPrimaryTestRegionLayout>(1,
+                                                                            1),
+       ValidateAndBuildLayout<layout::e2e_test::E2ESecondaryTestRegionLayout>(
+           1, 1),
+       ValidateAndBuildLayout<layout::e2e_test::E2EManagerTestRegionLayout>(1,
+                                                                            1),
+       ValidateAndBuildLayout<layout::e2e_test::E2EManagedTestRegionLayout>(1,
+                                                                            1),
+       ValidateAndBuildLayout<layout::audio_data::AudioDataLayout>(2, 2)});
 
-  return layout;
+  // We need this code to compile on both sides to enforce the static checks,
+  // but should only be used host side if for no other reason because of the
+  // possible resizing of some regions not being visible on the guest.
+#if !defined(CUTTLEFISH_HOST)
+  LOG(FATAL) << "Memory layout is not accurate in guest side, use region "
+                "classes or the vsoc driver directly instead.";
+#endif
+  return &layout;
 }
 
 }  // namespace vsoc
diff --git a/common/vsoc/lib/vsoc_memory.h b/common/vsoc/lib/vsoc_memory.h
index b6844b8..011e693 100644
--- a/common/vsoc/lib/vsoc_memory.h
+++ b/common/vsoc/lib/vsoc_memory.h
@@ -15,44 +15,55 @@
  * limitations under the License.
  */
 
+#include <stdint.h>
+
 #include <vector>
 
 namespace vsoc {
 
-class RegionMemoryLayout {
+class VSoCRegionLayout {
  public:
-  RegionMemoryLayout(const char* region_name, size_t region_size,
-                     int guest_to_host_signal_table_log_size,
-                     int host_to_guest_signal_table_log_size,
-                     const char* managed_by)
-      : region_name_(region_name),
-        region_size_(region_size),
-        guest_to_host_signal_table_log_size_(
-            guest_to_host_signal_table_log_size),
-        host_to_guest_signal_table_log_size_(
-            host_to_guest_signal_table_log_size),
-        managed_by_(managed_by) {}
+  virtual const char* region_name() const = 0;
+  virtual const char* managed_by() const = 0;
 
-  const char* region_name() const { return region_name_; }
-  size_t region_size() const { return region_size_; }
-  int guest_to_host_signal_table_log_size() const {
-    return guest_to_host_signal_table_log_size_;
-  }
-  int host_to_guest_signal_table_log_size() const {
-    return host_to_guest_signal_table_log_size_;
-  }
-  const char * managed_by() const {
-    return managed_by_;
-  }
-
- private:
-  const char* region_name_{};
-  size_t region_size_{};
-  int guest_to_host_signal_table_log_size_{};
-  int host_to_guest_signal_table_log_size_{};
-  const char* managed_by_{};
+  virtual size_t layout_size() const = 0;
+  virtual int guest_to_host_signal_table_log_size() const = 0;
+  virtual int host_to_guest_signal_table_log_size() const = 0;
+  virtual uint32_t begin_offset() const = 0;
+  virtual size_t region_size() const = 0;
+ protected:
+  VSoCRegionLayout() = default;
+  virtual ~VSoCRegionLayout() = default;
 };
 
-const std::vector<RegionMemoryLayout>& GetVsocMemoryLayout();
+class VSoCMemoryLayout {
+ public:
+  // Returns a pointer to the memory layout singleton.
+  static VSoCMemoryLayout* Get();
+
+  VSoCMemoryLayout(const VSoCMemoryLayout&) = delete;
+  VSoCMemoryLayout(VSoCMemoryLayout&&) = delete;
+
+  virtual std::vector<const VSoCRegionLayout *> GetRegions() const = 0;
+  virtual const VSoCRegionLayout* GetRegionByName(
+      const char* region_name) const = 0;
+
+  // Returns the smallest number of bytes that is a power of 2 and can
+  // accomodate the entire memory layout.
+  virtual uint32_t GetMemoryFileSize() const = 0;
+
+  // Writes the layout to memory. shared_memory should be the result of mmap-ing
+  // a file of at least GetMemoryFileSize() bytes.
+  virtual void WriteLayout(void * shared_memory) const = 0;
+
+  // Increase the size of the data section of a region to make the entire region
+  // at least new_min_size bytes. The actual region size will be no less than
+  // the minimum size required to accomodate the signal tables and the memory
+  // layout, and will be aligned to page size.
+  virtual bool ResizeRegion(const char* region_name, size_t new_min_size) = 0;
+ protected:
+  VSoCMemoryLayout() = default;
+  virtual ~VSoCMemoryLayout() = default;
+};
 
 }  // namespace vsoc
diff --git a/common/vsoc/shm/audio_data_layout.h b/common/vsoc/shm/audio_data_layout.h
index 30df4f8..3991ea0 100644
--- a/common/vsoc/shm/audio_data_layout.h
+++ b/common/vsoc/shm/audio_data_layout.h
@@ -26,10 +26,12 @@
 
 struct AudioDataLayout : public RegionLayout {
     static const char *const region_name;
+    static constexpr size_t layout_size = 16396;
 
     // size = 2^14 = 16384, packets are up to 4KB bytes each.
     CircularPacketQueue<14, 4096> audio_queue;
 };
+ASSERT_SHM_COMPATIBLE(AudioDataLayout);
 
 }  // namespace audio_data
 }  // namespace layout
diff --git a/common/vsoc/shm/base.h b/common/vsoc/shm/base.h
index 7bbaeb9..f5abec8 100644
--- a/common/vsoc/shm/base.h
+++ b/common/vsoc/shm/base.h
@@ -16,8 +16,31 @@
  */
 
 #include <stdint.h>
+#include <type_traits>
 
 // Base macros for all layout structures.
+// ShmTypeValidator provides meaningful information about the type size
+// mismatch in compilation error messages, eg.
+//
+// error:
+//    static_assert failed "Class size changed, update the layout_size field"
+//    static_assert(Current == Expected,
+// note: in instantiation of template class
+//    'ShmTypeValidator<vsoc::layout::myclass::ClassName>'
+//    requested here ASSERT_SHM_COMPATIBLE(ClassName);
+//
+template <typename Type, size_t expected_size = Type::layout_size>
+struct ShmTypeValidator {
+  static_assert(sizeof(Type) == expected_size,
+                "Class size changed, update the layout_size field");
+  static_assert(std::is_trivial<Type>(), "Class uses features that are unsafe");
+  static constexpr bool valid =
+      sizeof(Type) == expected_size && std::is_trivial<Type>();
+};
+
+#define ASSERT_SHM_COMPATIBLE(T)            \
+  static_assert(ShmTypeValidator<T>::valid, \
+                "Compilation error. Please fix above errors and retry.")
 
 namespace vsoc {
 namespace layout {
@@ -42,12 +65,18 @@
   Peer = Host
 #endif
 };
+// Enums can't have static members, so can't use the macro here.
+  static_assert(ShmTypeValidator<Sides, 4>::valid,
+              "Compilation error. Please fix above errors and retry.");
 
 /**
  * Base class for all region layout structures.
  */
 class RegionLayout {
+public:
+  static constexpr size_t layout_size = 1;
 };
+ASSERT_SHM_COMPATIBLE(RegionLayout);
 
 }  // namespace layout
 }  // namespace vsoc
diff --git a/common/vsoc/shm/circqueue.h b/common/vsoc/shm/circqueue.h
index aacdd2b..05893bf 100644
--- a/common/vsoc/shm/circqueue.h
+++ b/common/vsoc/shm/circqueue.h
@@ -36,6 +36,10 @@
  */
 template <uint32_t SizeLog2>
 class CircularQueueBase {
+ public:
+  static constexpr size_t layout_size = (1 << SizeLog2) + 12;
+
+ private:
   CircularQueueBase() = delete;
   CircularQueueBase(const CircularQueueBase&) = delete;
   CircularQueueBase& operator=(const CircularQueueBase&) = delete;
@@ -101,6 +105,7 @@
   char buffer_[BufferSize];
 };
 using CircularQueueBase64k = CircularQueueBase<16>;
+ASSERT_SHM_COMPATIBLE(CircularQueueBase64k);
 
 /**
  * Byte oriented circular queue. Reads will always return some data, but
@@ -110,6 +115,8 @@
 template <uint32_t SizeLog2>
 class CircularByteQueue : public CircularQueueBase<SizeLog2> {
  public:
+  static constexpr size_t layout_size =
+      CircularQueueBase<SizeLog2>::layout_size;
   /**
    * Read at most max_size bytes from the qeueue, placing them in buffer_out
    */
@@ -134,6 +141,7 @@
   using Range = typename CircularQueueBase<SizeLog2>::Range;
 };
 using CircularByteQueue64k = CircularByteQueue<16>;
+ASSERT_SHM_COMPATIBLE(CircularByteQueue64k);
 
 /**
  * Packet oriented circular queue. Reads will either return data or an error.
@@ -143,6 +151,9 @@
 template <uint32_t SizeLog2, uint32_t MaxPacketSize>
 class CircularPacketQueue : public CircularQueueBase<SizeLog2> {
  public:
+  static constexpr size_t layout_size =
+      CircularQueueBase<SizeLog2>::layout_size;
+
   /**
    * Read a single packet from the queue, placing its data into buffer_out.
    * If max_size indicates that buffer_out cannot hold the entire packet
@@ -186,6 +197,7 @@
   intptr_t CalculateBufferedSize(size_t payload);
 };
 using CircularPacketQueue64k = CircularPacketQueue<16, 1024>;
+ASSERT_SHM_COMPATIBLE(CircularPacketQueue64k);
 
 }  // namespace layout
 }  // namespace vsoc
diff --git a/common/vsoc/shm/e2e_test_region_layout.h b/common/vsoc/shm/e2e_test_region_layout.h
index 8853211..2c2670b 100644
--- a/common/vsoc/shm/e2e_test_region_layout.h
+++ b/common/vsoc/shm/e2e_test_region_layout.h
@@ -43,7 +43,7 @@
  * Flags that are used to indicate test status. Some of the latter testing
  * stages rely on initializion that must be done on the peer.
  */
-enum E2ETestStage {
+  enum E2ETestStage : uint32_t {
   // No tests have passed
   E2E_STAGE_NONE = 0,
   // This side has finished writing its pattern to the region
@@ -51,12 +51,16 @@
   // This side has confirmed that it can see its peer's writes to the region
   E2E_PEER_MEMORY_READ = 2,
 };
+static_assert(ShmTypeValidator<E2ETestStage, 4>::valid,
+              "Compilation error. Please fix above errors and retry.");
 
 /**
  * Structure that grants permission to write in the region to either the guest
  * or the host. This size of these fields is arbitrary.
  */
 struct E2EMemoryFill {
+  static constexpr size_t layout_size = 64;
+
   static const std::size_t kOwnedFieldSize = 32;
 
   // The compiler must not attempt to optimize away reads and writes to the
@@ -65,6 +69,7 @@
   char host_writable[kOwnedFieldSize];
   char guest_writable[kOwnedFieldSize];
 };
+ASSERT_SHM_COMPATIBLE(E2EMemoryFill);
 
 /**
  * Structure that grants permission to write in the region to either the guest
@@ -72,9 +77,10 @@
  */
 class E2ETestStageRegister {
  public:
+  static constexpr size_t layout_size = 4;
+
   E2ETestStage value() const {
-    E2ETestStage rval = static_cast<E2ETestStage>(value_);
-    return rval;
+    return value_;
   }
 
   void set_value(E2ETestStage new_value) { value_ = new_value; }
@@ -83,8 +89,9 @@
   // The compiler must not attempt to optimize away reads and writes to the
   // shared memory window. This is pretty typical when dealing with devices
   // doing memory mapped I/O.
-  uint32_t value_;
+  E2ETestStage value_;
 };
+ASSERT_SHM_COMPATIBLE(E2ETestStageRegister);
 
 /**
  * Describes the layout of the regions used for the end-to-end test. There
@@ -93,6 +100,9 @@
  */
 class E2ETestRegionLayout : public ::vsoc::layout::RegionLayout {
  public:
+  static constexpr size_t layout_size = 2 * E2ETestStageRegister::layout_size +
+                                        3 * 4 + E2EMemoryFill::layout_size;
+
   /**
    * Computes how many E2EMemoryFill records we need to cover the region.
    * Covering the entire region during the test ensures that everything is
@@ -123,36 +133,52 @@
   // until we examine the region.
   E2EMemoryFill data[1];
 };
+ASSERT_SHM_COMPATIBLE(E2ETestRegionLayout);
 
 struct E2EPrimaryTestRegionLayout : public E2ETestRegionLayout {
+  static constexpr size_t layout_size = E2ETestRegionLayout::layout_size;
+
   static const char* region_name;
   static const char guest_pattern[E2EMemoryFill::kOwnedFieldSize];
   static const char host_pattern[E2EMemoryFill::kOwnedFieldSize];
 };
+ASSERT_SHM_COMPATIBLE(E2EPrimaryTestRegionLayout);
 
 struct E2ESecondaryTestRegionLayout : public E2ETestRegionLayout {
+  static constexpr size_t layout_size = E2ETestRegionLayout::layout_size;
+
   static const char* region_name;
   static const char guest_pattern[E2EMemoryFill::kOwnedFieldSize];
   static const char host_pattern[E2EMemoryFill::kOwnedFieldSize];
 };
+ASSERT_SHM_COMPATIBLE(E2ESecondaryTestRegionLayout);
 
 /**
  * Defines an end-to-end region with a name that should never be configured.
  */
 struct E2EUnfindableRegionLayout : public E2ETestRegionLayout {
+  static constexpr size_t layout_size = E2ETestRegionLayout::layout_size;
+
   static const char* region_name;
 };
+ASSERT_SHM_COMPATIBLE(E2EUnfindableRegionLayout);
 
 struct E2EManagedTestRegionLayout : public RegionLayout {
+  static constexpr size_t layout_size = 4;
+
   static const char* region_name;
   uint32_t val;  // Not needed, here only to avoid an empty struct.
 };
+ASSERT_SHM_COMPATIBLE(E2EManagedTestRegionLayout);
 
 struct E2EManagerTestRegionLayout : public RegionLayout {
+  static constexpr size_t layout_size = 4 * 4;
+
   static const char* region_name;
   typedef E2EManagedTestRegionLayout ManagedRegion;
   uint32_t data[4];  // We don't need more than 4 for the tests
 };
+ASSERT_SHM_COMPATIBLE(E2EManagerTestRegionLayout);
 
 }  // namespace e2e_test
 }  // namespace layout
diff --git a/common/vsoc/shm/gralloc_layout.h b/common/vsoc/shm/gralloc_layout.h
index 3e0c883..4da740f 100644
--- a/common/vsoc/shm/gralloc_layout.h
+++ b/common/vsoc/shm/gralloc_layout.h
@@ -27,6 +27,9 @@
 namespace gralloc {
 
 struct BufferEntry {
+  static constexpr size_t layout_size =
+      7 * 4 + PixelFormatRegister::layout_size;
+
   uint32_t owned_by;
   uint32_t buffer_begin;
   uint32_t buffer_end;
@@ -44,12 +47,17 @@
     return buffer_end - buffer_begin;
   }
 };
+ASSERT_SHM_COMPATIBLE(BufferEntry);
 
 struct GrallocBufferLayout : public RegionLayout {
+  static constexpr size_t layout_size = 1;
   static const char* region_name;
 };
+ASSERT_SHM_COMPATIBLE(GrallocBufferLayout);
 
 struct GrallocManagerLayout : public RegionLayout {
+  static constexpr size_t layout_size =
+      8 + GuestLock::layout_size + BufferEntry::layout_size;
   static const char* region_name;
   typedef GrallocBufferLayout ManagedRegion;
 
@@ -60,6 +68,7 @@
   // Needs to be last field
   BufferEntry buffers_table[1];
 };
+ASSERT_SHM_COMPATIBLE(GrallocManagerLayout);
 
 } // namespace gralloc
 } // namespace layout
diff --git a/common/vsoc/shm/graphics.h b/common/vsoc/shm/graphics.h
index f29e0cf..0aa7875 100644
--- a/common/vsoc/shm/graphics.h
+++ b/common/vsoc/shm/graphics.h
@@ -68,7 +68,7 @@
 //   * Observant reviewers can verify that the same pixel value is not assigned
 //     to multiple formats. Keep the enums in numerical order below to
 //     make this easier.
-enum PixelFormat {
+enum PixelFormat : uint32_t {
   VSOC_PIXEL_FORMAT_UNINITIALIZED = PixelFormatBuilder<1,0>::value,
   VSOC_PIXEL_FORMAT_BLOB =          PixelFormatBuilder<1,1>::value,
 
@@ -129,25 +129,34 @@
   //   VSOC_PIXEL_FORMAT_sRGB_X_8888
   //   VSOC_PIXEL_FORMAT_sRGB_A_8888
 };
+// Enums can't have static members, so can't use the macro here.
+static_assert(ShmTypeValidator<PixelFormat, 4>::valid,
+              "Compilation error. Please fix above errors and retry.");
 
 namespace layout {
 
 // VSoC memory layout for a register that accepts a single pixel format.
 // The value is volatile to ensure that the compiler does not eliminate stores.
 struct PixelFormatRegister {
+  static constexpr size_t layout_size = 4;
+
   volatile PixelFormat value_;
 };
+ASSERT_SHM_COMPATIBLE(PixelFormatRegister);
 
 // Register layout for a mask giving different PixelFormats. Reserve enough
 // space to allow for future expansion. For example, we may well end with
 // a 12 bit per channel format in the future.
 struct PixelFormatMaskRegister {
+  static constexpr size_t layout_size = 8;
+
   volatile uint64_t value_;
 
   bool HasValue(PixelFormat in) {
     return !!(value_ & (uint64_t(1) << in));
   }
 };
+ASSERT_SHM_COMPATIBLE(PixelFormatMaskRegister);
 
 // Ensure that the mask is large enough to hold the highest encodable
 // pixel format.
diff --git a/common/vsoc/shm/input_events_layout.h b/common/vsoc/shm/input_events_layout.h
index 7cb4654..737c903 100644
--- a/common/vsoc/shm/input_events_layout.h
+++ b/common/vsoc/shm/input_events_layout.h
@@ -26,6 +26,10 @@
 namespace input_events {
 
 struct InputEventsLayout : public RegionLayout {
+  static constexpr size_t layout_size =
+      CircularPacketQueue<10, 256>::layout_size +
+      2 * CircularPacketQueue<10, 16>::layout_size;
+
   static const char* region_name;
   // Event queues for the different input devices supported. Both the power
   // button and the keyboard need only generate 2 input events for every
@@ -35,6 +39,7 @@
   CircularPacketQueue<10, 16> keyboard_queue;
   CircularPacketQueue<10, 16> power_button_queue;
 };
+ASSERT_SHM_COMPATIBLE(InputEventsLayout);
 
 }  // namespace input_events
 }  // namespace layout
diff --git a/common/vsoc/shm/lock.h b/common/vsoc/shm/lock.h
index 6ebdaa2..cc86add 100644
--- a/common/vsoc/shm/lock.h
+++ b/common/vsoc/shm/lock.h
@@ -50,6 +50,8 @@
  */
 class SpinLock {
  public:
+  static constexpr size_t layout_size = 4;
+
   /**
    * Acquire the spinlock on the queue. This will effectively block all
    * readers and writers.
@@ -87,12 +89,16 @@
  protected:
   std::atomic<uint32_t> lock_;
 };
+ASSERT_SHM_COMPATIBLE(SpinLock);
 
 /**
  * This is a generic synchronization primitive that provides space for the
  * owner of the lock to write platform-specific information.
  */
 class WaitingLockBase {
+ public:
+  static constexpr size_t layout_size = 40;
+
  protected:
   // Common code to handle locking
   // Must be called with the kernel's thread id
@@ -137,6 +143,7 @@
   int64_t owner_scratch_[2];
 #pragma clang diagnostic pop
 };
+ASSERT_SHM_COMPATIBLE(WaitingLockBase);
 
 /**
  * GuestLocks can be acquired and released only on the guest. They reside
@@ -148,6 +155,8 @@
  */
 class GuestLock : public WaitingLockBase {
  public:
+  static constexpr size_t layout_size = WaitingLockBase::layout_size;
+
 #ifndef CUTTLEFISH_HOST
   void Lock();
   void Unlock();
@@ -161,6 +170,7 @@
   bool Recover();
 #endif
 };
+ASSERT_SHM_COMPATIBLE(GuestLock);
 
 /**
  * HostLocks can be acquired and released only on the host. They reside
@@ -172,6 +182,8 @@
  */
 class HostLock : public WaitingLockBase {
  public:
+  static constexpr size_t layout_size = WaitingLockBase::layout_size;
+
 #ifdef CUTTLEFISH_HOST
   void Lock();
   void Unlock();
@@ -186,6 +198,7 @@
   bool Recover();
 #endif
 };
+ASSERT_SHM_COMPATIBLE(HostLock);
 
 /**
  * GuestAndHostLocks can be acquired and released on either side of the
@@ -213,6 +226,8 @@
  */
 class GuestAndHostLock : public WaitingLockBase {
  public:
+  static constexpr size_t layout_size = WaitingLockBase::layout_size;
+
   void Lock(RegionView*);
   void Unlock(RegionView*);
   /**
@@ -225,6 +240,7 @@
    */
   bool Recover(RegionView*);
 };
+ASSERT_SHM_COMPATIBLE(GuestAndHostLock);
 
 }  // namespace layout
 }  // namespace vsoc
diff --git a/common/vsoc/shm/ril_layout.h b/common/vsoc/shm/ril_layout.h
index 8910bde..33348e2 100644
--- a/common/vsoc/shm/ril_layout.h
+++ b/common/vsoc/shm/ril_layout.h
@@ -24,6 +24,7 @@
 namespace ril {
 
 struct RilLayout : public RegionLayout {
+  static constexpr size_t layout_size = 4 * 16 + 4;
   static const char* region_name;
 
   char ipaddr[16]; // xxx.xxx.xxx.xxx\0 = 16 bytes
@@ -32,6 +33,7 @@
   char broadcast[16];
   uint32_t prefixlen;
 };
+ASSERT_SHM_COMPATIBLE(RilLayout);
 }  // namespace ril
 }  // namespace layout
 }  // namespace vsoc
diff --git a/common/vsoc/shm/screen_layout.h b/common/vsoc/shm/screen_layout.h
index 3e54c6c..7ad0ca3 100644
--- a/common/vsoc/shm/screen_layout.h
+++ b/common/vsoc/shm/screen_layout.h
@@ -15,8 +15,6 @@
  * limitations under the License.
  */
 
-#include <vector>
-
 #include "common/vsoc/shm/base.h"
 #include "common/vsoc/shm/lock.h"
 
@@ -27,13 +25,19 @@
 
 namespace screen {
 struct TimeSpec {
+  static constexpr size_t layout_size = 16;
+
   int64_t ts_sec;
   uint32_t ts_nsec;
   // Host and guest compilers are giving the structure different sizes without
   // this field.
   uint32_t reserved;
 };
+ASSERT_SHM_COMPATIBLE(TimeSpec);
+
 struct CompositionStats {
+  static constexpr size_t layout_size = 4 + 2 * 2 + 5 * TimeSpec::layout_size;
+
   uint32_t num_prepare_calls;
   uint16_t num_layers;
   uint16_t num_hwcomposited_layers;
@@ -43,8 +47,10 @@
   TimeSpec set_start;
   TimeSpec set_end;
 };
+ASSERT_SHM_COMPATIBLE(CompositionStats);
 
 struct ScreenLayout : public RegionLayout {
+  static constexpr size_t layout_size = 24 + CompositionStats::layout_size;
   static const char* region_name;
   // Display properties
   uint32_t x_res;
@@ -62,6 +68,7 @@
   CompositionStats stats;
   uint8_t buffer[0];
 };
+ASSERT_SHM_COMPATIBLE(ScreenLayout);
 
 }  // namespace screen
 
diff --git a/common/vsoc/shm/socket_forward_layout.h b/common/vsoc/shm/socket_forward_layout.h
index 69d4ae2..5c78f21 100644
--- a/common/vsoc/shm/socket_forward_layout.h
+++ b/common/vsoc/shm/socket_forward_layout.h
@@ -36,8 +36,13 @@
   // If both are closed then the queue goes back to INACTIVE
   // BOTH_CLOSED = 0,
 };
+static_assert(ShmTypeValidator<QueueState, 4>::valid,
+              "Compilation error. Please fix above errors and retry.");
 
 struct Queue {
+  static constexpr size_t layout_size =
+      CircularPacketQueue<16, kMaxPacketSize>::layout_size + 4;
+
   CircularPacketQueue<16, kMaxPacketSize> queue;
 
   QueueState queue_state_;
@@ -46,8 +51,11 @@
     return queue.Recover();
   }
 };
+ASSERT_SHM_COMPATIBLE(Queue);
 
 struct QueuePair {
+  static constexpr size_t layout_size = 2 * Queue::layout_size + 8;
+
   // Traffic originating from host that proceeds towards guest.
   Queue host_to_guest;
   // Traffic originating from guest that proceeds towards host.
@@ -67,8 +75,11 @@
     return recovered;
   }
 };
+ASSERT_SHM_COMPATIBLE(QueuePair);
 
 struct SocketForwardLayout : public RegionLayout {
+  static constexpr size_t layout_size = QueuePair::layout_size * kNumQueues + 8;
+
   bool Recover() {
     bool recovered = false;
     for (auto& i : queues_) {
@@ -85,6 +96,8 @@
   static const char* region_name;
 };
 
+ASSERT_SHM_COMPATIBLE(SocketForwardLayout);
+
 }  // namespace socket_forward
 }  // namespace layout
 }  // namespace vsoc
diff --git a/common/vsoc/shm/version.h b/common/vsoc/shm/version.h
deleted file mode 100644
index cc2e6b6..0000000
--- a/common/vsoc/shm/version.h
+++ /dev/null
@@ -1,175 +0,0 @@
-#pragma once
-
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Version information for structures that are present in VSoC shared memory
-// windows. The proper use of this file will:
-//
-//   * ensure that the guest and host builds agree on the sizes of the shared
-//     structures.
-//
-//   * provides a single version code for the entire vsoc layout, assuming
-//     that reviewers excercise some care.
-//
-//
-//  Use:
-//
-//    Every new class / structure in the shm folder needs to add a size
-//    entry here, #include the base.h file, and add a ASSERT_SHM_COMPATIBLE
-//    instantiation just below the class definition,
-//
-//    For templatized classes / structs the author should choose a fixed size,
-//    create a using alias, and instantiate the checks on the alias.
-//    See CircularByteQueue64k for an example of this usage.
-//
-//   Note to reviewers:
-//
-//     It is probably ok to approve new additions  here without forcing a
-//     a version change.
-//
-//     However, the version must increment for any change in the value of a
-//     constant.
-//
-//     #ifdef, etc is absolutely forbidden in this file and highly discouraged
-//     in the other vsoc/shm files.
-
-#include <cstdint>
-
-#include "common/vsoc/shm/audio_data_layout.h"
-#include "common/vsoc/shm/e2e_test_region_layout.h"
-#include "common/vsoc/shm/gralloc_layout.h"
-#include "common/vsoc/shm/input_events_layout.h"
-#include "common/vsoc/shm/ril_layout.h"
-#include "common/vsoc/shm/screen_layout.h"
-#include "common/vsoc/shm/socket_forward_layout.h"
-#include "common/vsoc/shm/wifi_exchange_layout.h"
-
-namespace vsoc {
-namespace layout {
-
-template <typename T>
-class VersionInfo {
- public:
-  constexpr static size_t size = -1;
-};
-
-// Versioning information for audio_data_layout.h
-// Changes to these structures will affect only the audio_data region
-template <>
-class VersionInfo<audio_data::AudioDataLayout> {
- public:
-  // One circular queue of with a 16KB buffer, a 32 bits spinlock and
-  // two 32 bits integers.
-  constexpr static size_t size = 16384 + 3 * 4;
-};
-
-// Versioning information for e2e_test_region.h
-// Changes to these structures will affect only the e2e_test_region
-template <>
-class VersionInfo<e2e_test::E2EManagerTestRegionLayout> {
- public:
-  constexpr static size_t size = 16;
-};
-template <>
-class VersionInfo<e2e_test::E2EPrimaryTestRegionLayout> {
- public:
-  constexpr static size_t size = 84;
-};
-template <>
-class VersionInfo<e2e_test::E2ESecondaryTestRegionLayout> {
- public:
-  constexpr static size_t size = 84;
-};
-template <>
-class VersionInfo<e2e_test::E2ETestRegionLayout> {
- public:
-  constexpr static size_t size = 84;
-};
-template <>
-class VersionInfo<e2e_test::E2EUnfindableRegionLayout> {
- public:
-  constexpr static size_t size = 84;
-};
-template <>
-class VersionInfo<e2e_test::E2EManagedTestRegionLayout> {
- public:
-  constexpr static size_t size = 4;
-};
-
-// Versioning information for gralloc_layout.h
-// Changes to these structures will affect only the gralloc region
-template <>
-class VersionInfo<gralloc::GrallocManagerLayout> {
- public:
-  constexpr static size_t size = 80;
-};
-template <>
-class VersionInfo<gralloc::GrallocBufferLayout> {
- public:
-  constexpr static size_t size = 1;
-};
-
-// Versioning information for input_events_layout.h
-// Changes to these structures will affect only the input_events region
-template <>
-class VersionInfo<input_events::InputEventsLayout> {
- public:
-  // Three circular queues, each with a 1024 bytes buffer, a 32 bits spinlock
-  // and two 32 bits integers.
-  constexpr static size_t size = 3 * (1024 + 3 * 4);
-};
-
-// Versioning information for ril_layout.h
-template <>
-class VersionInfo<ril::RilLayout> {
- public:
-  constexpr static size_t size = 68;
-};
-
-// Versioning information for screen_layout.h
-// Changes to these structures will affect only the screen region.
-template <>
-class VersionInfo<screen::ScreenLayout> {
- public:
-  constexpr static size_t size = 112;
-};
-
-// Versioning Information for socket_forward_layout.h
-template <>
-class VersionInfo<socket_forward::SocketForwardLayout> {
- public:
-  constexpr static size_t size = ((((65548 + 4)  // queue + state
-                                    * 2)     // host_to_guest and guest_to_host
-                                   + 4 + 4)  // port and state_lock
-                                  * socket_forward::kNumQueues) +
-                                 4     // seq_num
-                                 + 4;  // generation number
-};
-
-// Versioning information for wifi_layout.h
-template <>
-class VersionInfo<wifi::WifiExchangeLayout> {
- public:
-  constexpr static size_t size =
-      65548 +  // sizeof(CircularPacketQueue<16, 8192>) - forward
-      65548 +  // sizeof(CircularPacketQueue<16, 8192>) - reverse
-      6 +      // uint8_t[6] MAC address.
-      6;       // uint8_t[6] MAC address.
-};
-
-}  // namespace layout
-}  // namespace vsoc
diff --git a/common/vsoc/shm/wifi_exchange_layout.h b/common/vsoc/shm/wifi_exchange_layout.h
index 3eaa1b6..df4659e 100644
--- a/common/vsoc/shm/wifi_exchange_layout.h
+++ b/common/vsoc/shm/wifi_exchange_layout.h
@@ -25,6 +25,8 @@
 namespace wifi {
 
 struct WifiExchangeLayout : public RegionLayout {
+  static constexpr size_t layout_size = 2 * CircularPacketQueue<16, 8192>::layout_size + 12;
+
   // Traffic originating from host that proceeds towards guest.
   CircularPacketQueue<16, 8192> guest_ingress;
   // Traffic originating from guest that proceeds towards host.
@@ -38,6 +40,8 @@
   static const char* region_name;
 };
 
+ASSERT_SHM_COMPATIBLE(WifiExchangeLayout);
+
 }  // namespace wifi
 }  // namespace layout
 }  // namespace vsoc
diff --git a/host/commands/launch/main.cc b/host/commands/launch/main.cc
index bc8371f..c3b2151 100644
--- a/host/commands/launch/main.cc
+++ b/host/commands/launch/main.cc
@@ -35,6 +35,8 @@
 
 #include "common/libs/fs/shared_select.h"
 #include "common/libs/strings/str_split.h"
+#include "common/vsoc/lib/vsoc_memory.h"
+#include "common/vsoc/shm/screen_layout.h"
 #include "host/commands/launch/pre_launch_initializers.h"
 #include "host/libs/config/file_partition.h"
 #include "host/libs/config/guest_config.h"
@@ -69,7 +71,12 @@
              "The size of the blank data image to generate, MB.");
 DEFINE_string(blank_data_image_fmt, "ext4",
               "The fs format for the blank data image. Used with mkfs.");
+
 DECLARE_int32(dpi);
+DECLARE_int32(x_res);
+DECLARE_int32(y_res);
+DECLARE_int32(num_screen_buffers);
+
 DEFINE_bool(disable_app_armor_security, false,
             "Disable AppArmor security in libvirt. For debug only.");
 DEFINE_bool(disable_dac_security, false,
@@ -86,10 +93,6 @@
               "virsh " VIRSH_OPTIONS_PLACEHOLDER " create /dev/fd/0",
               "Command to start an instance. If <virsh_options> is present it "
               "will be replaced by options to the virsh command");
-DEFINE_string(layout,
-              StringFromEnv("ANDROID_HOST_OUT", StringFromEnv("HOME", ".")) +
-                  "/config/vsoc_mem.json",
-              "Location of the vsoc_mem.json file.");
 DEFINE_bool(log_xml, false, "Log the XML machine configuration");
 DEFINE_int32(memory_mb, 2048,
              "Total amount of memory available for guest, MB.");
@@ -148,23 +151,6 @@
   return std::string("-c ").append(FLAGS_hypervisor_uri);
 }
 
-Json::Value LoadLayoutFile(const std::string& file) {
-  char real_file_path[PATH_MAX];
-  if (realpath(file.c_str(), real_file_path) == nullptr) {
-    LOG(FATAL) << "Could not get real path for file " << file << ": "
-               << strerror(errno);
-  }
-
-  Json::Value result;
-  Json::Reader reader;
-  std::ifstream ifs(real_file_path);
-  if (!reader.parse(ifs, result)) {
-    LOG(FATAL) << "Could not read layout file " << file << ": "
-               << reader.getFormattedErrorMessages();
-  }
-  return result;
-}
-
 // VirtualUSBManager manages virtual USB device presence for Cuttlefish.
 class VirtualUSBManager {
  public:
@@ -210,11 +196,10 @@
 // Cuttlefish and host-side daemons.
 class IVServerManager {
  public:
-  IVServerManager(const Json::Value& json_root)
-      : server_(ivserver::IVServerOptions(FLAGS_layout, FLAGS_mempath,
+  IVServerManager()
+      : server_(ivserver::IVServerOptions(FLAGS_mempath,
                                           FLAGS_qemusocket,
-                                          vsoc::GetDomain()),
-                json_root) {}
+                                          vsoc::GetDomain())) {}
 
   ~IVServerManager() = default;
 
@@ -484,8 +469,6 @@
     FLAGS_vendor_image = FLAGS_system_image_dir + "/vendor.img";
   }
 
-  Json::Value json_root = LoadLayoutFile(FLAGS_layout);
-
   // Each of these calls is free to fail and terminate launch if file does not
   // exist or could not be created.
   auto system_partition = config::FilePartition::ReuseExistingFile(
@@ -511,6 +494,7 @@
   }
 
   std::string entropy_source = "/dev/urandom";
+  auto& memory_layout = *vsoc::VSoCMemoryLayout::Get();
 
   config::GuestConfig cfg;
   cfg.SetID(FLAGS_instance)
@@ -520,7 +504,7 @@
       .SetInitRDName(FLAGS_initrd)
       .SetKernelArgs(cmdline.str())
       .SetIVShMemSocketPath(FLAGS_qemusocket)
-      .SetIVShMemVectorCount(json_root["vsoc_device_regions"].size())
+      .SetIVShMemVectorCount(memory_layout.GetRegions().size())
       .SetSystemPartitionPath(system_partition->GetName())
       .SetCachePartitionPath(cache_partition->GetName())
       .SetDataPartitionPath(data_partition->GetName())
@@ -545,7 +529,23 @@
   VirtualUSBManager vadb(cfg.GetUSBV1SocketName(), FLAGS_vhci_port,
                          GetPerInstanceDefault("android_usbip"));
   vadb.Start();
-  IVServerManager ivshmem(json_root);
+
+  // TODO(b/79170615) These values need to go to the config object/file and the
+  // region resizing be done by the ivserver process (or maybe the config
+  // library to ensure all processes have the correct value?)
+  size_t screen_size =
+      memory_layout
+          .GetRegionByName(vsoc::layout::screen::ScreenLayout::region_name)
+          ->region_size();
+  auto actual_width = ((FLAGS_x_res * 4) + 15) & ~15;  // aligned to 16
+  screen_size += FLAGS_num_screen_buffers *
+                 (actual_width * FLAGS_y_res + 16 /* padding */);
+  screen_size += (FLAGS_num_screen_buffers - 1) * 4096; /* Guard pages */
+  memory_layout.ResizeRegion(vsoc::layout::screen::ScreenLayout::region_name,
+                             screen_size);
+  // TODO(b/79170615) Resize gralloc region too.
+
+  IVServerManager ivshmem;
   ivshmem.Start();
   KernelLogMonitor kmon(cfg.GetKernelLogSocketName(),
                         GetDefaultPerInstancePath("kernel.log"),
diff --git a/host/commands/launch/screen_region_handler.cc b/host/commands/launch/screen_region_handler.cc
index 5844537..4214482 100644
--- a/host/commands/launch/screen_region_handler.cc
+++ b/host/commands/launch/screen_region_handler.cc
@@ -25,12 +25,13 @@
 DEFINE_int32(y_res, 1280, "Height of the screen in pixels");
 DEFINE_int32(dpi, 160, "Pixels per inch for the screen");
 DEFINE_int32(refresh_rate_hz, 60, "Screen refresh rate in Hertz");
+DEFINE_int32(num_screen_buffers, 3, "The number of screen buffers");
 
 void InitializeScreenRegion() {
   auto region =
       vsoc::screen::ScreenRegionView::GetInstance(vsoc::GetDomain().c_str());
   if (!region) {
-    LOG(ERROR) << "Framebuffer region was not found";
+    LOG(ERROR) << "Screen region was not found";
     return;
   }
   auto dest = region->data();
diff --git a/host/config/Android.mk b/host/config/Android.mk
index 908c90d..59298fc 100644
--- a/host/config/Android.mk
+++ b/host/config/Android.mk
@@ -19,14 +19,6 @@
 LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := vsoc_mem_json
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(HOST_OUT)/config
-LOCAL_MODULE_STEM := vsoc_mem.json
-LOCAL_SRC_FILES := vsoc_mem.json
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
 LOCAL_MODULE := cuttlefish_dtb
 LOCAL_MODULE_CLASS := ETC
 LOCAL_MODULE_PATH := $(HOST_OUT)/config
diff --git a/host/config/vsoc_mem.json b/host/config/vsoc_mem.json
deleted file mode 100644
index 4d1a25f..0000000
--- a/host/config/vsoc_mem.json
+++ /dev/null
@@ -1,250 +0,0 @@
-{
-  "vsoc_device_regions" : [
-   {
-     "device_name" : "vsoc_input",
-     "__comment" : "Send input events to the guest",
-     "current_version" : 1,
-     "min_compatible_version" : 1,
-     "region_size" : 4096,
-
-     "guest_to_host_signal_table" : {
-       "__comment" : "sizeof each node is based on common/libs/shm_compatible/lock.h",
-       "num_nodes_lg2" : 0
-      },
-
-     "host_to_guest_signal_table" : {
-       "num_nodes_lg2" : 0
-      }
-   },
-
-   {
-     "device_name" : "hwcomposer",
-     "__comment" : "HWComposer related",
-     "current_version" : 1,
-     "min_compatible_version" : 1,
-     "region_size" : 16384,
-
-     "guest_to_host_signal_table" : {
-       "__comment" : "sizeof each node is based on common/libs/shm_compatible/lock.h",
-       "num_nodes_lg2" : 2
-      },
-
-     "host_to_guest_signal_table" : {
-       "num_nodes_lg2" : 2
-      }
-   },
-
-   {
-     "device_name" : "input_events",
-     "__comment" : "Send input events from host to guest",
-     "current_version" : 0,
-     "min_compatible_version" : 0,
-     "region_size": 4096,
-
-     "guest_to_host_signal_table" : {
-       "__comment" : "sizeof each node is based on common/libs/shm_compatible/lock.h",
-       "num_nodes_lg2" : 2
-      },
-
-     "host_to_guest_signal_table" : {
-       "num_nodes_lg2" : 2
-      }
-   },
-
-   {
-     "device_name" : "screen",
-     "__comment" : "The screen region.",
-     "current_version" : 0,
-     "min_compatible_version" : 0,
-     "region_size": 12292096,
-
-     "guest_to_host_signal_table" : {
-       "__comment" : "sizeof each node is based on common/libs/shm_compatible/lock.h",
-       "num_nodes_lg2" : 2
-      },
-
-     "host_to_guest_signal_table" : {
-       "num_nodes_lg2" : 2
-      }
-   },
-
-   {
-     "device_name" : "gralloc_manager",
-     "__comment" : "Manages allocation of gralloc buffers",
-     "current_version" : 0,
-     "min_compatible_version" : 0,
-     "region_size" : 40960,
-
-     "guest_to_host_signal_table" : {
-       "__comment" : "sizeof each node is based on common/libs/shm/lock.h",
-       "num_nodes_lg2" : 2
-      },
-
-     "host_to_guest_signal_table" : {
-       "num_nodes_lg2" : 2
-      }
-   },
-
-   {
-     "device_name" : "gralloc_memory",
-     "__comment" : "Holds the gralloc buffers. Size is 400 MB minus the size of the framebuffer",
-     "managed_by" : "gralloc_manager",
-     "current_version" : 0,
-     "min_compatible_version" : 0,
-     "region_size" : 407142400,
-
-     "guest_to_host_signal_table" : {
-       "__comment" : "sizeof each node is based on common/libs/shm/lock.h",
-       "num_nodes_lg2" : 0
-      },
-
-     "host_to_guest_signal_table" : {
-       "num_nodes_lg2" : 0
-      }
-   },
-
-   {
-     "device_name" : "socket_forward",
-     "__comment" : "Holds the data being used by the socket forwarding",
-     "current_version" : 0,
-     "min_compatible_version" : 0,
-     "__comment" : "FIXME this region size is huge until I nail down the correct size",
-     "region_size" : 2105344,
-
-     "guest_to_host_signal_table" : {
-       "__comment" : [
-           "sizeof each node is based on common/libs/shm/lock.h",
-           "16 spinlocks = 16 * 4 = 64",
-           "then the atomic generation number is + 4"
-       ],
-       "num_nodes_lg2" : 7
-      },
-
-     "host_to_guest_signal_table" : {
-       "num_nodes_lg2" : 7
-      }
-   },
-
-   {
-     "device_name" : "wifi_exchange",
-     "__comment" : [
-       "WIFI exchange buffer for primary wireless network interface.",
-       "Must be able to accomodate at least one pagesize long packet each direction",
-       "Region size = 2 * CircularPacketQueue64k_size + 1024 bytes for control structures."
-     ],
-     "current_version" : 0,
-     "min_compatible_version" : 0,
-     "region_size" : 139264,
-
-     "guest_to_host_signal_table" : {
-       "num_nodes_lg2" : 2
-      },
-
-     "host_to_guest_signal_table" : {
-       "num_nodes_lg2" : 2
-      }
-   },
-
-
-   {
-     "device_name" : "ril",
-     "__comment" : [
-       "Holds initialization values for the ril hal."
-     ],
-     "current_version" : 0,
-     "min_compatible_version" : 0,
-     "region_size" : 4096,
-
-     "guest_to_host_signal_table" : {
-       "num_nodes_lg2" : 2
-      },
-
-     "host_to_guest_signal_table" : {
-       "num_nodes_lg2" : 2
-      }
-   },
-
-
-   {
-    "device_name" : "e2e_primary",
-    "__comment" : "Sanity testing",
-    "current_version" : 1,
-    "min_compatible_version" : 1,
-    "region_size" : 16384,
-
-    "guest_to_host_signal_table" : {
-      "num_nodes_lg2" : 1
-    },
-
-    "host_to_guest_signal_table" : {
-      "num_nodes_lg2" : 1
-    }
-   },
-
-   {
-    "device_name" : "e2e_secondary",
-    "__comment" : "Sanity testing",
-    "current_version" : 1,
-    "min_compatible_version" : 1,
-    "region_size" : 16384,
-
-    "guest_to_host_signal_table" : {
-      "num_nodes_lg2" : 1
-    },
-
-    "host_to_guest_signal_table" : {
-      "num_nodes_lg2" : 1
-    }
-   },
-
-   {
-    "device_name" : "e2e_manager",
-    "__comment" : "Sanity testing of managed regions",
-    "current_version" : 1,
-    "min_compatible_version" : 1,
-    "region_size" : 4096,
-
-    "guest_to_host_signal_table" : {
-      "num_nodes_lg2" : 1
-    },
-
-    "host_to_guest_signal_table" : {
-      "num_nodes_lg2" : 1
-    }
-   },
-
-   {
-    "device_name" : "e2e_managed",
-    "__comment" : "Sanity testing of managed regions",
-    "current_version" : 1,
-    "min_compatible_version" : 1,
-    "region_size" : 16384,
-    "managed_by" : "e2e_manager",
-
-    "guest_to_host_signal_table" : {
-      "num_nodes_lg2" : 1
-    },
-
-    "host_to_guest_signal_table" : {
-      "num_nodes_lg2" : 1
-    }
-   },
-
-   {
-     "device_name" : "audio_data",
-     "__comment" : "Write audio HAL output data to ringbuffer",
-     "current_version" : 0,
-     "min_compatible_version" : 0,
-     "region_size": 20480,
-
-     "guest_to_host_signal_table" : {
-       "__comment" : "sizeof each node is based on common/libs/shm_compatible/lock.h",
-       "num_nodes_lg2" : 2
-      },
-
-     "host_to_guest_signal_table" : {
-       "num_nodes_lg2" : 2
-      }
-   }
-  ]
-}
diff --git a/host/libs/ivserver/Android.bp b/host/libs/ivserver/Android.bp
index bfaafa9..93fa62e 100644
--- a/host/libs/ivserver/Android.bp
+++ b/host/libs/ivserver/Android.bp
@@ -27,6 +27,7 @@
     ],
     shared_libs: [
         "libbase",
+        "vsoc_lib",
     ],
     static_libs: [
         "libjsoncpp",
@@ -46,6 +47,7 @@
         "libcuttlefish_fs",
         "cuttlefish_auto_resources",
         "libbase",
+        "vsoc_lib",
     ],
     static_libs: [
         "libivserver",
diff --git a/host/libs/ivserver/ivserver.cc b/host/libs/ivserver/ivserver.cc
index d966764..eb377ec 100644
--- a/host/libs/ivserver/ivserver.cc
+++ b/host/libs/ivserver/ivserver.cc
@@ -26,9 +26,8 @@
 
 namespace ivserver {
 
-IVServer::IVServer(const IVServerOptions &options, const Json::Value &json_root)
-    : json_root_{json_root},
-      vsoc_shmem_(VSoCSharedMemory::New(options.shm_file_path, json_root_)) {
+IVServer::IVServer(const IVServerOptions &options)
+    : vsoc_shmem_(VSoCSharedMemory::New(options.shm_file_path)) {
   LOG_IF(WARNING, unlink(options.qemu_socket_path.c_str()) == 0)
       << "Removed existing unix socket: " << options.qemu_socket_path
       << ". We can't confirm yet whether another instance is running.";
diff --git a/host/libs/ivserver/ivserver.h b/host/libs/ivserver/ivserver.h
index ad32d81..70fb39f 100644
--- a/host/libs/ivserver/ivserver.h
+++ b/host/libs/ivserver/ivserver.h
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 
-#include <json/json.h>
 #include <memory>
 
 #include "common/libs/fs/shared_fd.h"
@@ -28,8 +27,9 @@
 // new connections.
 class IVServer final {
  public:
-  IVServer(const IVServerOptions &options, const Json::Value &json_root);
+  IVServer(const IVServerOptions &options);
   IVServer(const IVServer &) = delete;
+  IVServer& operator=(const IVServer&) = delete;
 
   // Serves incoming client and qemu connection.
   // This method should never return.
@@ -39,7 +39,6 @@
   void HandleNewClientConnection();
   void HandleNewQemuConnection();
 
-  const Json::Value &json_root_;
   std::unique_ptr<VSoCSharedMemory> vsoc_shmem_;
   cvd::SharedFD qemu_channel_;
   cvd::SharedFD client_channel_;
diff --git a/host/libs/ivserver/options.cc b/host/libs/ivserver/options.cc
index 25f88dd..56c3dce 100644
--- a/host/libs/ivserver/options.cc
+++ b/host/libs/ivserver/options.cc
@@ -17,18 +17,15 @@
 
 namespace ivserver {
 
-IVServerOptions::IVServerOptions(const std::string &mem_layout_conf,
-                                 const std::string &shm_file_path,
+IVServerOptions::IVServerOptions(const std::string &shm_file_path,
                                  const std::string &qemu_socket_path,
                                  const std::string &client_socket_path)
-    : memory_layout_conf_path(mem_layout_conf),
-      shm_file_path(shm_file_path),
+    : shm_file_path(shm_file_path),
       qemu_socket_path(qemu_socket_path),
       client_socket_path(client_socket_path) {}
 
 std::ostream &operator<<(std::ostream &out, const IVServerOptions &options) {
-  out << "\nmem_layout_conf_path: " << options.memory_layout_conf_path
-      << "\nshm_file: " << options.shm_file_path
+  out << "\nshm_file: " << options.shm_file_path
       << "\nqemu_socket_path: " << options.qemu_socket_path
       << "\nclient_socket_path: " << options.client_socket_path << std::endl;
 
diff --git a/host/libs/ivserver/options.h b/host/libs/ivserver/options.h
index 53a51e2..40b3246 100644
--- a/host/libs/ivserver/options.h
+++ b/host/libs/ivserver/options.h
@@ -24,14 +24,12 @@
 const uint16_t kIVServerMajorVersion = 1;
 const uint16_t kIVServerMinorVersion = 0;
 const uint32_t kIVServerDefaultShmSizeInMiB = 4;
-const std::string kIVServerDefaultLayoutFile = "vsoc_mem.json";
 
 //
 // structure that contains the various options to start the server.
 //
 struct IVServerOptions final {
-  IVServerOptions(const std::string &mem_layout_conf,
-                  const std::string &shm_file_path,
+  IVServerOptions(const std::string &shm_file_path,
                   const std::string &qemu_socket_path,
                   const std::string &client_socket_path);
 
@@ -41,7 +39,6 @@
   friend std::ostream &operator<<(std::ostream &out,
                                   const IVServerOptions &opts);
 
-  const std::string memory_layout_conf_path;
   const std::string shm_file_path;
   const std::string qemu_socket_path;
   const std::string client_socket_path;
diff --git a/host/libs/ivserver/qemu_client.cc b/host/libs/ivserver/qemu_client.cc
index 2771e06..e3a5cde 100644
--- a/host/libs/ivserver/qemu_client.cc
+++ b/host/libs/ivserver/qemu_client.cc
@@ -81,7 +81,7 @@
   for (const auto region_data : shmem.Regions()) {
     if (!SendSocketInfo(QemuFDMsg::kHostSideHald, region_data.host_fd)) {
       LOG(ERROR) << "Failed to send Host Side FD for region "
-                 << region_data.values.device_name << ": " << client_socket_->StrError();
+                 << region_data.device_name << ": " << client_socket_->StrError();
       return false;
     }
   }
@@ -95,7 +95,7 @@
   for (const auto region_data : shmem.Regions()) {
     if (!SendSocketInfo(QemuFDMsg::kGuestSideHal, region_data.guest_fd)) {
       LOG(ERROR) << "Failed to send Guest Side FD for region "
-                 << region_data.values.device_name << ": " << client_socket_->StrError();
+                 << region_data.device_name << ": " << client_socket_->StrError();
       return false;
     }
   }
diff --git a/host/libs/ivserver/vsocsharedmem.cc b/host/libs/ivserver/vsocsharedmem.cc
index 952c0fe..080ad20 100644
--- a/host/libs/ivserver/vsocsharedmem.cc
+++ b/host/libs/ivserver/vsocsharedmem.cc
@@ -29,64 +29,15 @@
 
 #include <glog/logging.h>
 
+#include "common/vsoc/lib/vsoc_memory.h"
 #include "uapi/vsoc_shm.h"
 
 namespace ivserver {
 namespace {
 
-static_assert(CURRENT_VSOC_LAYOUT_MAJOR_VERSION == 2,
-              "Region layout code must be updated");
-
-// Field names from the json file. These are declared so the compiler will
-// catch typos.
-const char g_vsoc_device_regions[] = "vsoc_device_regions";
-const char g_device_name_tag[] = "device_name";
-const char g_managed_by_tag[] = "managed_by";
-
-class RegionAllocator {
- public:
-  static uint32_t PageSize() {
-    static long page_size = sysconf(_SC_PAGESIZE);
-    return page_size;
-  }
-
-  explicit RegionAllocator(const std::string &name, uint32_t max_size,
-                           uint32_t offset = 0)
-      : name_{name}, max_size_{max_size}, offset_{offset} {}
-
-  uint32_t Allocate(uint32_t size, const char *usage, bool *error) {
-    if (size > (max_size_ - offset_)) {
-      *error = true;
-      LOG(ERROR) << name_ << ":"
-                 << "allocation of " << size << "bytes for " << usage
-                 << " will overflow memory region";
-    }
-
-    offset_ += size;
-    return (offset_ - size);
-  }
-
-  void PadTo(uint32_t size, bool *error) {
-    uint32_t padding = ((offset_ + (size - 1)) / size) * size - offset_;
-    Allocate(padding, "padding", error);
-  }
-
-  uint32_t AllocateRest(bool *error) {
-    return Allocate(max_size_ - offset_, "rest of region", error);
-  }
-
-  uint32_t GetOffset() const { return offset_; }
-
- private:
-  std::string name_;
-  uint32_t max_size_;
-  uint32_t offset_;
-};
-
 class VSoCSharedMemoryImpl : public VSoCSharedMemory {
  public:
-  VSoCSharedMemoryImpl(const vsoc_shm_layout_descriptor &header,
-                       const std::map<std::string, size_t> &name_to_region_idx,
+  VSoCSharedMemoryImpl(const std::map<std::string, size_t> &name_to_region_idx,
                        const std::vector<Region> &regions,
                        const std::string &path);
 
@@ -101,7 +52,6 @@
  private:
   void CreateLayout();
 
-  const vsoc_shm_layout_descriptor &header_;
   cvd::SharedFD shared_mem_fd_;
   const std::map<std::string, size_t> region_name_to_index_;
   const std::vector<Region> region_data_;
@@ -111,11 +61,9 @@
 };
 
 VSoCSharedMemoryImpl::VSoCSharedMemoryImpl(
-    const vsoc_shm_layout_descriptor &header,
     const std::map<std::string, size_t> &name_to_region_idx,
     const std::vector<Region> &regions, const std::string &path)
-    : header_{header},
-      region_name_to_index_{name_to_region_idx},
+    : region_name_to_index_{name_to_region_idx},
       region_data_{regions} {
   // TODO(ender): Lock the file after creation and check lock status upon second
   // execution attempt instead of throwing an error.
@@ -127,7 +75,8 @@
   LOG_IF(FATAL, !shared_mem_fd_->IsOpen())
       << "Error in creating shared_memory file: " << shared_mem_fd_->StrError();
 
-  int truncate_res = shared_mem_fd_->Truncate(header_.size);
+  int truncate_res = shared_mem_fd_->Truncate(
+      vsoc::VSoCMemoryLayout::Get()->GetMemoryFileSize());
   LOG_IF(FATAL, truncate_res == -1)
       << "Error in sizing up the shared memory file: "
       << shared_mem_fd_->StrError();
@@ -144,18 +93,13 @@
 }
 
 void VSoCSharedMemoryImpl::CreateLayout() {
-  void *mmap_addr = shared_mem_fd_->Mmap(0, header_.size,
-                                         PROT_READ | PROT_WRITE, MAP_SHARED, 0);
+  auto mmap_length = vsoc::VSoCMemoryLayout::Get()->GetMemoryFileSize();
+  void *mmap_addr = shared_mem_fd_->Mmap(0, mmap_length, PROT_READ | PROT_WRITE,
+                                         MAP_SHARED, 0);
   LOG_IF(FATAL, mmap_addr == MAP_FAILED)
       << "Error mmaping file: " << strerror(errno);
-  *reinterpret_cast<vsoc_shm_layout_descriptor *>(mmap_addr) = header_;
-  auto region_dest = reinterpret_cast<vsoc_device_region *>(
-      reinterpret_cast<uintptr_t>(mmap_addr) + header_.vsoc_region_desc_offset);
-
-  for (const auto &region : region_data_) {
-    *region_dest++ = region.values;
-  }
-  munmap(mmap_addr, header_.size);
+  vsoc::VSoCMemoryLayout::Get()->WriteLayout(mmap_addr);
+  munmap(mmap_addr, mmap_length);
 }
 
 bool VSoCSharedMemoryImpl::GetEventFdPairForRegion(
@@ -169,186 +113,42 @@
   return true;
 }
 
-template <typename T>
-void GetMandatoryUInt(const std::string &region_name,
-                      const Json::Value &json_region, const char *field_name,
-                      bool *error, T *dest) {
-  if (!json_region.isMember(field_name)) {
-    LOG(ERROR) << region_name << " missing " << field_name << " field";
-    *error = true;
-    return;
-  }
-  if (!json_region[field_name].isNumeric()) {
-    LOG(ERROR) << region_name << " " << field_name << " is not numeric";
-    *error = true;
-    return;
-  }
-  *dest = json_region[field_name].asUInt();
-}
-
-void JSONToSignalTable(const std::string &region_name,
-                       const Json::Value &json_region, const char *table_name,
-                       RegionAllocator *allocator, bool *error,
-                       vsoc_signal_table_layout *dest) {
-  if (!json_region.isMember(table_name)) {
-    LOG(ERROR) << region_name << " has no " << table_name << " section";
-    *error = true;
-    return;
-  }
-  GetMandatoryUInt(region_name, json_region[table_name], "num_nodes_lg2", error,
-                   &dest->num_nodes_lg2);
-  dest->futex_uaddr_table_offset = allocator->Allocate(
-      (1 << dest->num_nodes_lg2) * sizeof(uint32_t), "node table", error);
-  dest->interrupt_signalled_offset =
-      allocator->Allocate(sizeof(uint32_t), "signal word", error);
-}
-
-std::shared_ptr<VSoCSharedMemory::Region> JSONToRegion(
-    const std::string &region_name, const Json::Value &json_region,
-    bool *failed) {
-  std::shared_ptr<VSoCSharedMemory::Region> region(
-      new VSoCSharedMemory::Region);
-  GetMandatoryUInt(region_name, json_region, "current_version", failed,
-                   &region->values.current_version);
-  GetMandatoryUInt(region_name, json_region, "min_compatible_version", failed,
-                   &region->values.min_compatible_version);
-  GetMandatoryUInt(region_name, json_region, "region_size", failed,
-                   &region->values.region_end_offset);
-  RegionAllocator allocator(region_name, region->values.region_end_offset);
-  JSONToSignalTable(region_name, json_region, "guest_to_host_signal_table",
-                    &allocator, failed,
-                    &region->values.guest_to_host_signal_table);
-  JSONToSignalTable(region_name, json_region, "host_to_guest_signal_table",
-                    &allocator, failed,
-                    &region->values.host_to_guest_signal_table);
-
-  region->values.offset_of_region_data = allocator.AllocateRest(failed);
-  return region;
-}
-
 }  // anonymous namespace
 
 std::unique_ptr<VSoCSharedMemory> VSoCSharedMemory::New(
-    const std::string &path, const Json::Value &root) {
-  // This is so catastrophic that there isn't anything else to check.
-  if (!root.isMember(g_vsoc_device_regions)) {
-    LOG(ERROR) << "vsoc_device_regions section is absent";
-    return nullptr;
-  }
-  auto device_regions = root[g_vsoc_device_regions];
-  bool failed = false;
-  RegionAllocator shm_file("shared_memory_file", UINT32_MAX);
-  vsoc_shm_layout_descriptor header{};
-  header.major_version = CURRENT_VSOC_LAYOUT_MAJOR_VERSION;
-  header.minor_version = CURRENT_VSOC_LAYOUT_MINOR_VERSION;
-  // size is handled at N1
-  header.region_count = device_regions.size();
-  shm_file.Allocate(sizeof(header), "header", &failed);
-  header.vsoc_region_desc_offset =
-      shm_file.Allocate(sizeof(vsoc_device_region) * header.region_count,
-                        "region descriptors", &failed);
-  // Align to a page boundary for the first region
-  shm_file.PadTo(RegionAllocator::PageSize(), &failed);
+    const std::string &path) {
+  auto device_layout = vsoc::VSoCMemoryLayout::Get();
 
   std::map<std::string, size_t> name_to_region_idx;
   std::vector<Region> regions;
-  regions.reserve(header.region_count);
-  std::map<std::string, std::string> managed_by_references;
+  regions.reserve(device_layout->GetRegions().size());
 
-  // Pass 1: Parse individual region structures validating all of the
-  // fields that can be validated without help.
-  for (const auto &json_region : device_regions) {
-    if (!json_region.isMember(g_device_name_tag)) {
-      LOG(ERROR) << g_device_name_tag << " is missing from region";
-      failed = true;
-      continue;
-    }
-    const std::string device_name = json_region[g_device_name_tag].asString();
-    if (name_to_region_idx.count(device_name)) {
-      LOG(ERROR) << device_name << " used for more than one region";
-      failed = true;
-      continue;
-    }
-    std::shared_ptr<Region> region =
-        JSONToRegion(device_name, json_region, &failed);
+  for (auto region_spec : device_layout->GetRegions()) {
+    auto device_name = region_spec->region_name();
+
     // Create one pair of eventfds for this region. Note that the guest to host
     // eventfd is non-blocking, whereas the host to guest eventfd is blocking.
     // This is in anticipation of blocking semantics for the host side locks.
-    region->host_fd = cvd::SharedFD::Event(0, EFD_NONBLOCK);
-    if (!region->host_fd->IsOpen()) {
-      failed = true;
+    auto host_fd = cvd::SharedFD::Event(0, EFD_NONBLOCK);
+    if (!host_fd->IsOpen()) {
       LOG(ERROR) << "Failed to create host eventfd for " << device_name << ": "
-                 << region->host_fd->StrError();
+                 << host_fd->StrError();
+      return nullptr;
     }
-    region->guest_fd = cvd::SharedFD::Event(0, EFD_NONBLOCK);
-    if (!region->guest_fd->IsOpen()) {
-      failed = true;
+    auto guest_fd = cvd::SharedFD::Event(0, EFD_NONBLOCK);
+    if (!guest_fd->IsOpen()) {
       LOG(ERROR) << "Failed to create guest eventfd for " << device_name << ": "
-                 << region->guest_fd->StrError();
-    }
-    region->values.region_begin_offset = shm_file.Allocate(
-        region->values.region_end_offset, device_name.c_str(), &failed);
-    shm_file.PadTo(RegionAllocator::PageSize(), &failed);
-    region->values.region_end_offset = shm_file.GetOffset();
-    if (sizeof(region->values.device_name) - device_name.size() < 1) {
-      LOG(ERROR) << device_name << " is too long for a region name";
-      failed = true;
-    } else {
-      strcpy(region->values.device_name, device_name.c_str());
+                 << guest_fd->StrError();
+      return nullptr;
     }
 
-    name_to_region_idx[device_name] = regions.size();
-    regions.push_back(*region);
-    // We will attempt to resolve this link in Pass 2
-    if (json_region.isMember(g_managed_by_tag)) {
-      managed_by_references[device_name] =
-          json_region[g_managed_by_tag].asString();
-    }
+    auto region_idx = regions.size();
+    name_to_region_idx[device_name] = region_idx;
+    regions.emplace_back(device_name, host_fd, guest_fd);
   }
 
-  // Pass 2: Resolve the managed_by_references
-  for (const auto &it : managed_by_references) {
-    if (!name_to_region_idx.count(it.second)) {
-      LOG(ERROR) << it.first << " managed by missing region " << it.second;
-      failed = true;
-      continue;
-    }
-    regions[name_to_region_idx[it.first]].values.managed_by =
-        name_to_region_idx[it.second];
-    if (regions[name_to_region_idx[it.first]].values.managed_by ==
-        VSOC_REGION_WHOLE) {
-      LOG(ERROR)
-          << "Region '" << it.first << "' has owner " << it.second
-          << " with index "
-          << regions[name_to_region_idx[it.first]].values.managed_by
-          << " which is the default value for regions without an owner. Choose"
-             "a different region to be at index "
-          << regions[name_to_region_idx[it.first]].values.managed_by
-          << ", make sure the chosen region is NOT the owner of any other "
-             "region";
-    }
-  }
-  if (failed) {
-    return nullptr;
-  }
-  // Handles size (marker N1)
-  // The size must be a power of 2
-  size_t temp = shm_file.GetOffset();
-  size_t allocated_size = 0;
-  // Find the highest set bit
-  while(temp) {
-    allocated_size = temp;
-    // Clear a bit
-    temp = temp & (temp -1);
-  }
-  // If the size is already a power of 2 just use it. Otherswise use the
-  // next higher power of 2
-  if (allocated_size < shm_file.GetOffset()) {
-    allocated_size *= 2;
-  }
-  header.size = allocated_size;
   return std::unique_ptr<VSoCSharedMemory>(
-      new VSoCSharedMemoryImpl(header, name_to_region_idx, regions, path));
+      new VSoCSharedMemoryImpl(name_to_region_idx, regions, path));
 }
 
 }  // namespace ivserver
diff --git a/host/libs/ivserver/vsocsharedmem.h b/host/libs/ivserver/vsocsharedmem.h
index f732f6b..613c6a0 100644
--- a/host/libs/ivserver/vsocsharedmem.h
+++ b/host/libs/ivserver/vsocsharedmem.h
@@ -16,10 +16,10 @@
  */
 
 #include <inttypes.h>
-#include <json/json.h>
 #include <map>
 #include <memory>
 #include <string>
+#include <vector>
 
 #include "common/libs/fs/shared_fd.h"
 #include "uapi/vsoc_shm.h"
@@ -30,7 +30,11 @@
  public:
   // Region describes a VSoCSharedMem region.
   struct Region {
-    vsoc_device_region values{};
+    Region() = default;
+    explicit Region(const char *device_name, const cvd::SharedFD &host_fd,
+                    const cvd::SharedFD &guest_fd)
+        : device_name(device_name), host_fd(host_fd), guest_fd(guest_fd) {}
+    const char *device_name;
     cvd::SharedFD host_fd;
     cvd::SharedFD guest_fd;
   };
@@ -38,8 +42,7 @@
   VSoCSharedMemory() = default;
   virtual ~VSoCSharedMemory() = default;
 
-  static std::unique_ptr<VSoCSharedMemory> New(const std::string &name,
-                                               const Json::Value &json_root);
+  static std::unique_ptr<VSoCSharedMemory> New(const std::string &name);
 
   virtual bool GetEventFdPairForRegion(const std::string &region_name,
                                        cvd::SharedFD *guest_to_host,