Writes region description to shmem file in the launcher.

The VSoCMemoryLayout needed to show accurate size values on all
host processes, which gets complicated because the launcher may resize
some regions. With this change VSoCMemoryLayout no longer holds the
size information, it is instead calculated on the launcher and
persisted to the shared memory file, where every host process can read
it from.

Bug: 110539298
Test: local and gce runs
Change-Id: Id7feda309ff4ee3c432523cc820f6d6c4c2dbb41
Merged-In: Id7feda309ff4ee3c432523cc820f6d6c4c2dbb41
(cherry picked from commit 22561d9a52380e9ca562c02dc6de0a6b6f67cfeb)
diff --git a/Android.bp b/Android.bp
index c79a9c0..be209a0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -111,7 +111,6 @@
     header_libs: ["cuttlefish_glog"],
     shared_libs: [
         "libcuttlefish_fs",
-        "libcuttlefish_utils",
         "cuttlefish_auto_resources",
         "libbase",
         "liblog",
diff --git a/common/vsoc/lib/vsoc_memory.cpp b/common/vsoc/lib/vsoc_memory.cpp
index 0053e98..807b2d9 100644
--- a/common/vsoc/lib/vsoc_memory.cpp
+++ b/common/vsoc/lib/vsoc_memory.cpp
@@ -24,7 +24,6 @@
 #include <type_traits>
 
 #include "common/libs/glog/logging.h"
-#include "common/libs/utils/size_utils.h"
 #include "common/vsoc/shm/audio_data_layout.h"
 #include "common/vsoc/shm/base.h"
 #include "common/vsoc/shm/e2e_test_region_layout.h"
@@ -68,8 +67,6 @@
         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;
 
@@ -83,30 +80,6 @@
   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 = cvd::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_{};
@@ -114,8 +87,6 @@
   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_{};
 };
 
 class VSoCMemoryLayoutImpl : public VSoCMemoryLayout {
@@ -133,16 +104,6 @@
                       "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 = cvd::AlignToPageSize(offset);
-
-    // Calculate offsets for all regions and set the size of the device
-    UpdateRegionOffsetsAndDeviceSize(offset);
   }
 
   ~VSoCMemoryLayoutImpl() = default;
@@ -162,39 +123,6 @@
     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 = cvd::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);
-    LOG(INFO) << region_name << ": resized to " << 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;
@@ -214,105 +142,10 @@
     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_ = cvd::RoundUpToNextPowerOf2(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>
 VSoCRegionLayoutImpl ValidateAndBuildLayout(int g_to_h_signal_table_log_size,
                                             int h_to_g_signal_table_log_size,
@@ -353,10 +186,9 @@
        ValidateAndBuildLayout<layout::audio_data::AudioDataLayout>(2, 2)});
 
   // 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.
+  // but should only be used host side.
 #if !defined(CUTTLEFISH_HOST)
-  LOG(FATAL) << "Memory layout is not accurate in guest side, use region "
+  LOG(FATAL) << "Memory layout should not be used guest side, use region "
                 "classes or the vsoc driver directly instead.";
 #endif
   return &layout;
diff --git a/common/vsoc/lib/vsoc_memory.h b/common/vsoc/lib/vsoc_memory.h
index 011e693..49853f9 100644
--- a/common/vsoc/lib/vsoc_memory.h
+++ b/common/vsoc/lib/vsoc_memory.h
@@ -29,8 +29,6 @@
   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;
@@ -47,20 +45,6 @@
   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;
diff --git a/host/commands/launch/Android.bp b/host/commands/launch/Android.bp
index 2100e52..c39aada 100644
--- a/host/commands/launch/Android.bp
+++ b/host/commands/launch/Android.bp
@@ -19,6 +19,7 @@
         "main.cc",
         "screen_region_handler.cc",
         "ril_region_handler.cc",
+        "vsoc_shared_memory.cc",
         "wifi_region_handler.cc",
     ],
     header_libs: [
diff --git a/host/commands/launch/main.cc b/host/commands/launch/main.cc
index fb2b66f..f449b22 100644
--- a/host/commands/launch/main.cc
+++ b/host/commands/launch/main.cc
@@ -39,9 +39,11 @@
 #include "common/libs/strings/str_split.h"
 #include "common/libs/utils/environment.h"
 #include "common/libs/utils/subprocess.h"
+#include "common/libs/utils/size_utils.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/commands/launch/vsoc_shared_memory.h"
 #include "host/libs/config/cuttlefish_config.h"
 #include "host/libs/ivserver/ivserver.h"
 #include "host/libs/ivserver/options.h"
@@ -202,28 +204,6 @@
   VirtualUSBManager& operator=(const VirtualUSBManager&) = delete;
 };
 
-// IVServerManager takes care of serving shared memory segments between
-// Cuttlefish and host-side daemons.
-class IVServerManager {
- public:
-  IVServerManager(const std::string& mempath, const std::string& qemu_socket)
-      : server_(ivserver::IVServerOptions(mempath, qemu_socket,
-                                          vsoc::GetDomain())) {}
-
-  ~IVServerManager() = default;
-
-  // Start IVServer thread.
-  void Start() {
-    std::thread([this] { server_.Serve(); }).detach();
-  }
-
- private:
-  ivserver::IVServer server_;
-
-  IVServerManager(const IVServerManager&) = delete;
-  IVServerManager& operator=(const IVServerManager&) = delete;
-};
-
 // KernelLogMonitor receives and monitors kernel log for Cuttlefish.
 class KernelLogMonitor {
  public:
@@ -395,6 +375,33 @@
   return FLAGS_adb_mode == kAdbModeUsb;
 }
 
+void LaunchIvServer() {
+  auto config = vsoc::CuttlefishConfig::Get();
+  // Resize gralloc region
+  auto actual_width = cvd::AlignToPowerOf2(FLAGS_x_res * 4, 4);  // align to 16
+  uint32_t screen_buffers_size =
+      FLAGS_num_screen_buffers *
+      cvd::AlignToPageSize(actual_width * FLAGS_y_res + 16 /* padding */);
+  screen_buffers_size +=
+      (FLAGS_num_screen_buffers - 1) * 4096; /* Guard pages */
+
+  // TODO(b/79170615) Resize gralloc region too.
+
+  vsoc::CreateSharedMemoryFile(
+      config->mempath(),
+      {{vsoc::layout::screen::ScreenLayout::region_name, screen_buffers_size}});
+
+  // Construct the server outside the thread so that the socket is guaranteed to
+  // be created when this function return. Use a shared pointer to avoid the
+  // destruction of the object.
+  std::shared_ptr<ivserver::IVServer> server(new ivserver::IVServer(ivserver::IVServerOptions(
+        config->mempath(), config->ivshmem_qemu_socket_path(),
+        vsoc::GetDomain())));
+  std::thread([server] {
+    server->Serve();
+  }).detach();
+}
+
 void LaunchSocketForwardProxyIfEnabled() {
   if (AdbTunnelEnabled()) {
     cvd::subprocess({FLAGS_socket_forward_proxy_binary,
@@ -420,6 +427,7 @@
         {"/usr/bin/sudo", "-E", FLAGS_wifi_relay_binary, GetConfigFileArg()});
   }
 }
+
 bool ResolveInstanceFiles() {
   if (FLAGS_system_image_dir.empty()) {
     LOG(FATAL) << "--system_image_dir must be specified.";
@@ -636,23 +644,6 @@
     LOG(ERROR) << "Unable to write cuttlefish environment file";
   }
 
-  auto& memory_layout = *vsoc::VSoCMemoryLayout::Get();
-  // 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_region_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_region_size += FLAGS_num_screen_buffers *
-                 (actual_width * FLAGS_y_res + 16 /* padding */);
-  screen_region_size += (FLAGS_num_screen_buffers - 1) * 4096; /* Guard pages */
-  memory_layout.ResizeRegion(vsoc::layout::screen::ScreenLayout::region_name,
-                             screen_region_size);
-  // TODO(b/79170615) Resize gralloc region too.
-
-
   auto config = vsoc::CuttlefishConfig::Get();
   // Save the config object before starting any host process
   if (!config->SaveToFile(GetConfigFile())) {
@@ -664,9 +655,7 @@
                          config->usb_ip_socket_name());
   vadb.Start();
 
-  // Start IVServer
-  IVServerManager ivshmem(config->mempath(), config->ivshmem_qemu_socket_path());
-  ivshmem.Start();
+  LaunchIvServer();
 
   KernelLogMonitor kmon(config->kernel_log_socket_name(),
                         config->PerInstancePath("kernel.log"),
diff --git a/host/commands/launch/vsoc_shared_memory.cc b/host/commands/launch/vsoc_shared_memory.cc
new file mode 100644
index 0000000..a963be7
--- /dev/null
+++ b/host/commands/launch/vsoc_shared_memory.cc
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include "host/commands/launch/vsoc_shared_memory.h"
+
+#include <unistd.h>
+
+#include <map>
+#include <vector>
+
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/utils/size_utils.h"
+#include "common/vsoc/lib/vsoc_memory.h"
+#include "glog/logging.h"
+
+#include "uapi/vsoc_shm.h"
+
+namespace vsoc {
+
+namespace {
+
+uint32_t OffsetOfRegionData(const VSoCRegionLayout& layout) {
+  uint32_t offset = 0;
+  // Signal tables
+  offset +=
+      (1 << layout.guest_to_host_signal_table_log_size()) * sizeof(uint32_t);
+  offset +=
+      (1 << layout.host_to_guest_signal_table_log_size()) * sizeof(uint32_t);
+  // Interrup signals
+  offset += 2 * sizeof(uint32_t);
+  return offset;
+}
+
+struct VSoCRegionAllocator {
+  const VSoCRegionLayout* region_layout;
+  uint32_t begin_offset;
+  uint32_t region_size;
+
+  VSoCRegionAllocator(const VSoCRegionLayout& layout, uint32_t offset,
+                      uint32_t requested_layout_increase = 0)
+      : region_layout(&layout),
+        begin_offset(offset),
+        region_size(cvd::AlignToPageSize(OffsetOfRegionData(layout) +
+                                         layout.layout_size() +
+                                         requested_layout_increase)) {}
+};
+
+// 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 VSoCRegionAllocator& allocator) {
+  // 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 = allocator.begin_offset;
+  shmem_region_desc->region_end_offset =
+      allocator.begin_offset + allocator.region_size;
+  shmem_region_desc->offset_of_region_data =
+      OffsetOfRegionData(*allocator.region_layout);
+  strncpy(shmem_region_desc->device_name,
+          allocator.region_layout->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,
+      allocator.region_layout->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,
+      allocator.region_layout->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 "
+               << allocator.region_layout->region_name() << ". This is a bug";
+  }
+}
+
+void WriteLayout(void* shared_memory,
+                 const std::vector<VSoCRegionAllocator>& allocators,
+                 uint32_t file_size) {
+  // 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 = file_size;
+  header->region_count = allocators.size();
+
+  std::map<std::string, size_t> region_idx_by_name;
+  for (size_t idx = 0; idx < allocators.size(); ++idx) {
+    region_idx_by_name[allocators[idx].region_layout->region_name()] = idx;
+  }
+
+  // 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 < allocators.size(); ++idx) {
+    auto shmem_region_desc = &region_descriptions[idx];
+    const auto& region = *allocators[idx].region_layout;
+    WriteRegionDescription(shmem_region_desc, allocators[idx]);
+    // 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;
+    }
+  }
+}
+}  // namespace
+
+void CreateSharedMemoryFile(
+    const std::string& path,
+    const std::map<std::string, uint32_t>& layout_increases) {
+  // TODO(ender): Lock the file after creation and check lock status upon second
+  // execution attempt instead of throwing an error.
+  LOG_IF(WARNING, unlink(path.c_str()) == 0)
+      << "Removed existing instance of " << path
+      << ". We currently don't know if another instance of daemon is running";
+  auto shared_mem_fd = cvd::SharedFD::Open(
+      path.c_str(), O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+  LOG_IF(FATAL, !shared_mem_fd->IsOpen())
+      << "Error in creating shared_memory file: " << shared_mem_fd->StrError();
+
+  auto region_layouts = VSoCMemoryLayout::Get()->GetRegions();
+  std::vector<VSoCRegionAllocator> allocators;
+  uint32_t file_size =
+      cvd::AlignToPageSize(sizeof(vsoc_shm_layout_descriptor) +
+                           region_layouts.size() * sizeof(vsoc_device_region));
+  for (auto layout : region_layouts) {
+    allocators.emplace_back(*layout, file_size /* offset */,
+                            layout_increases.count(layout->region_name())
+                                ? layout_increases.at(layout->region_name())
+                                : 0);
+    file_size += allocators.back().region_size;
+  }
+  file_size = cvd::RoundUpToNextPowerOf2(file_size);
+
+  int truncate_res = shared_mem_fd->Truncate(file_size);
+  LOG_IF(FATAL, truncate_res == -1)
+      << "Error in sizing up the shared memory file: "
+      << shared_mem_fd->StrError();
+
+  void* mmap_addr =
+      shared_mem_fd->Mmap(0, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, 0);
+  LOG_IF(FATAL, mmap_addr == MAP_FAILED)
+      << "Error mmaping file: " << strerror(errno);
+  WriteLayout(mmap_addr, allocators, file_size);
+  munmap(mmap_addr, file_size);
+}
+
+}  // namespace vsoc
diff --git a/host/commands/launch/vsoc_shared_memory.h b/host/commands/launch/vsoc_shared_memory.h
new file mode 100644
index 0000000..94c03a1
--- /dev/null
+++ b/host/commands/launch/vsoc_shared_memory.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+#pragma once
+
+#include <map>
+#include <string>
+
+namespace vsoc {
+
+// Creates the shared memory file and initializes it with with the region
+// information. The size of each region is determined to be the smallest
+// multiple of page size that can accommodate the header and the layout. The
+// size of the layout can be increased by specifyng it on the
+// layout_increases_by_region_name parameter.
+void CreateSharedMemoryFile(
+    const std::string& path,
+    const std::map<std::string, uint32_t>& layout_increases_by_region_name = {});
+
+}  // namespace vsoc
diff --git a/host/libs/ivserver/vsocsharedmem.cc b/host/libs/ivserver/vsocsharedmem.cc
index 080ad20..ab90fc2 100644
--- a/host/libs/ivserver/vsocsharedmem.cc
+++ b/host/libs/ivserver/vsocsharedmem.cc
@@ -63,24 +63,11 @@
 VSoCSharedMemoryImpl::VSoCSharedMemoryImpl(
     const std::map<std::string, size_t> &name_to_region_idx,
     const std::vector<Region> &regions, const std::string &path)
-    : region_name_to_index_{name_to_region_idx},
+    : shared_mem_fd_(cvd::SharedFD::Open(path.c_str(), O_RDWR)),
+      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.
-  LOG_IF(WARNING, unlink(path.c_str()) == 0)
-      << "Removed existing instance of " << path
-      << ". We currently don't know if another instance of daemon is running";
-  shared_mem_fd_ = cvd::SharedFD::Open(path.c_str(), O_RDWR | O_CREAT | O_EXCL,
-                                       S_IRUSR | S_IWUSR);
   LOG_IF(FATAL, !shared_mem_fd_->IsOpen())
       << "Error in creating shared_memory file: " << shared_mem_fd_->StrError();
-
-  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();
-  CreateLayout();
 }
 
 const cvd::SharedFD &VSoCSharedMemoryImpl::SharedMemFD() const {
@@ -92,16 +79,6 @@
   return region_data_;
 }
 
-void VSoCSharedMemoryImpl::CreateLayout() {
-  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);
-  vsoc::VSoCMemoryLayout::Get()->WriteLayout(mmap_addr);
-  munmap(mmap_addr, mmap_length);
-}
-
 bool VSoCSharedMemoryImpl::GetEventFdPairForRegion(
     const std::string &region_name, cvd::SharedFD *guest_to_host,
     cvd::SharedFD *host_to_guest) const {