First attempt at adding a singleton to region view classes

Makes the Open() method protected in TypedRegionView, sublcasses need
to handle instantiation (preferable through the template defined in
RegionView) or take extra steps to make Open() public.

Bug: 72181993
Change-Id: Iaeb20bec3b0525ce0ac6c6aab8d09d3e554fd71d
diff --git a/Android.bp b/Android.bp
index 124bc8a..546a56c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -92,6 +92,7 @@
         "common/vsoc/lib/audio_data_layout.cpp",
         "common/vsoc/lib/audio_data_region_view.cpp",
         "common/vsoc/lib/e2e_test_region_layout.cpp",
+        "common/vsoc/lib/e2e_test_region_view.cpp",
         "common/vsoc/lib/fb_bcast_layout.cpp",
         "common/vsoc/lib/fb_bcast_region_view.cpp",
         "common/vsoc/lib/gralloc_layout.cpp",
diff --git a/common/libs/wifi/packet_switch.cc b/common/libs/wifi/packet_switch.cc
index 8202821..b913a69 100644
--- a/common/libs/wifi/packet_switch.cc
+++ b/common/libs/wifi/packet_switch.cc
@@ -27,17 +27,18 @@
 PacketSwitch::~PacketSwitch() { Stop(); }
 
 bool PacketSwitch::Init() {
-  bool res;
 #ifdef CUTTLEFISH_HOST
-  res = shm_wifi_.Open(vsoc::GetDomain().c_str());
+  shm_wifi_ =
+      vsoc::wifi::WifiExchangeView::GetInstance(vsoc::GetDomain().c_str());
 #else
-  res = shm_wifi_.Open();
+  shm_wifi_ = vsoc::wifi::WifiExchangeView::GetInstance();
 #endif
 
-  if (res) {
-    worker_ = shm_wifi_.StartWorker();
+  if (shm_wifi_) {
+    worker_ = shm_wifi_->StartWorker();
+    return true;
   }
-  return res;
+  return false;
 }
 
 void PacketSwitch::Start() {
@@ -60,7 +61,7 @@
 #ifdef CUTTLEFISH_HOST
       LOG(INFO) << "Awaiting packet.";
 #endif
-      shm_wifi_.Recv(msg.get(), maxlen);
+        shm_wifi_->Recv(msg.get(), maxlen);
 #ifdef CUTTLEFISH_HOST
       LOG(INFO) << "Received packet.";
 #endif
@@ -102,7 +103,7 @@
       nl_->WRCL().Send(&c);
       c.WaitComplete();
     } else {
-      shm_wifi_.Send(header, header->nlmsg_len);
+      shm_wifi_->Send(header, header->nlmsg_len);
     }
   }
 }
diff --git a/common/libs/wifi/packet_switch.h b/common/libs/wifi/packet_switch.h
index e2b027c..a693387 100644
--- a/common/libs/wifi/packet_switch.h
+++ b/common/libs/wifi/packet_switch.h
@@ -46,7 +46,7 @@
 
   std::unique_ptr<std::thread> shm_xchg_;
   std::unique_ptr<vsoc::RegionWorker> worker_;
-  vsoc::wifi::WifiExchangeView shm_wifi_;
+  std::shared_ptr<vsoc::wifi::WifiExchangeView> shm_wifi_;
 
   PacketSwitch(const PacketSwitch&) = delete;
   PacketSwitch& operator=(const PacketSwitch&) = delete;
diff --git a/common/vsoc/lib/audio_data_region_view.cpp b/common/vsoc/lib/audio_data_region_view.cpp
index 868cc94..063f7e5 100644
--- a/common/vsoc/lib/audio_data_region_view.cpp
+++ b/common/vsoc/lib/audio_data_region_view.cpp
@@ -25,12 +25,20 @@
 namespace vsoc {
 namespace audio_data {
 
-// static
-AudioDataRegionView *AudioDataRegionView::GetInstance() {
-    static AudioDataRegionView sInstance;
-    return &sInstance;
+#if defined(CUTTLEFISH_HOST)
+std::shared_ptr<AudioDataRegionView> AudioDataRegionView::GetInstance(
+    const char* domain) {
+  return RegionView::GetInstanceImpl<AudioDataRegionView>(
+      [](std::shared_ptr<AudioDataRegionView> region, const char* domain) {
+        return region->Open(domain);
+      },
+      domain);
 }
-
+#else
+std::shared_ptr<AudioDataRegionView> AudioDataRegionView::GetInstance() {
+  return RegionView::GetInstanceImpl<AudioDataRegionView>(
+      std::mem_fn(&AudioDataRegionView::Open));
+}
+#endif
 }  // namespace audio_data
 }  // namespace vsoc
-
diff --git a/common/vsoc/lib/audio_data_region_view.h b/common/vsoc/lib/audio_data_region_view.h
index 13e51f4..44d8dad 100644
--- a/common/vsoc/lib/audio_data_region_view.h
+++ b/common/vsoc/lib/audio_data_region_view.h
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+#include <memory>
+
 #include <android-base/macros.h>
 
 #include "common/vsoc/lib/typed_region_view.h"
@@ -26,15 +28,16 @@
 class AudioDataRegionView
     : public vsoc::TypedRegionView<vsoc::layout::audio_data::AudioDataLayout> {
 public:
+    AudioDataRegionView() = default;
     AudioDataRegionView(const AudioDataRegionView &) = delete;
     AudioDataRegionView &operator=(const AudioDataRegionView &) = delete;
 
-    static AudioDataRegionView *GetInstance();
-
-private:
-    AudioDataRegionView() = default;
+#if defined(CUTTLEFISH_HOST)
+    static std::shared_ptr<AudioDataRegionView> GetInstance(const char *domain);
+#else
+    static std::shared_ptr<AudioDataRegionView> GetInstance();
+#endif
 };
 
 }  // namespace audio_data
 }  // namespace vsoc
-
diff --git a/common/vsoc/lib/e2e_test_region_view.cpp b/common/vsoc/lib/e2e_test_region_view.cpp
new file mode 100644
index 0000000..9bcebd9
--- /dev/null
+++ b/common/vsoc/lib/e2e_test_region_view.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 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 "common/vsoc/lib/e2e_test_region_view.h"
+
+namespace vsoc {
+
+#if defined(CUTTLEFISH_HOST)
+std::shared_ptr<E2EPrimaryRegionView> E2EPrimaryRegionView::GetInstance(
+    const char* domain) {
+  return vsoc::RegionView::GetInstanceImpl<E2EPrimaryRegionView>(
+      [](std::shared_ptr<E2EPrimaryRegionView> region, const char* domain) {
+        return region->Open(domain);
+      },
+      domain);
+}
+#else
+std::shared_ptr<E2EPrimaryRegionView> E2EPrimaryRegionView::GetInstance() {
+  return vsoc::RegionView::GetInstanceImpl<E2EPrimaryRegionView>(
+      std::mem_fn(&E2EPrimaryRegionView::Open));
+}
+#endif
+
+#if defined(CUTTLEFISH_HOST)
+std::shared_ptr<E2ESecondaryRegionView> E2ESecondaryRegionView::GetInstance(
+    const char* domain) {
+  return vsoc::RegionView::GetInstanceImpl<E2ESecondaryRegionView>(
+      [](std::shared_ptr<E2ESecondaryRegionView> region, const char* domain) {
+        return region->Open(domain);
+      },
+      domain);
+}
+#else
+std::shared_ptr<E2ESecondaryRegionView> E2ESecondaryRegionView::GetInstance() {
+  return vsoc::RegionView::GetInstanceImpl<E2ESecondaryRegionView>(
+      std::mem_fn(&E2ESecondaryRegionView::Open));
+}
+#endif
+
+#if defined(CUTTLEFISH_HOST)
+std::shared_ptr<E2EUnfindableRegionView> E2EUnfindableRegionView::GetInstance(
+    const char* domain) {
+  return vsoc::RegionView::GetInstanceImpl<E2EUnfindableRegionView>(
+      [](std::shared_ptr<E2EUnfindableRegionView> region, const char* domain) {
+        return region->Open(domain);
+      },
+      domain);
+}
+#else
+std::shared_ptr<E2EUnfindableRegionView>
+E2EUnfindableRegionView::GetInstance() {
+  return vsoc::RegionView::GetInstanceImpl<E2EUnfindableRegionView>(
+      std::mem_fn(&E2EUnfindableRegionView::Open));
+}
+#endif
+
+}  // namespace vsoc
diff --git a/common/vsoc/lib/e2e_test_region_view.h b/common/vsoc/lib/e2e_test_region_view.h
index 079eb88..e6e7a78 100644
--- a/common/vsoc/lib/e2e_test_region_view.h
+++ b/common/vsoc/lib/e2e_test_region_view.h
@@ -15,6 +15,9 @@
  * limitations under the License.
  */
 
+#include <memory>
+#include <functional>
+
 #include "common/vsoc/lib/typed_region_view.h"
 #include "common/vsoc/shm/e2e_test_region_layout.h"
 
@@ -63,10 +66,34 @@
   }
 };
 
-using E2EPrimaryRegionView =
-    vsoc::E2ERegionView<layout::e2e_test::E2EPrimaryTestRegionLayout>;
-using E2ESecondaryRegionView =
-    vsoc::E2ERegionView<layout::e2e_test::E2ESecondaryTestRegionLayout>;
-using E2EUnfindableRegionView =
-    vsoc::E2ERegionView<layout::e2e_test::E2EUnfindableRegionLayout>;
-};  // namespace vsoc
+class E2EPrimaryRegionView
+    : public vsoc::E2ERegionView<layout::e2e_test::E2EPrimaryTestRegionLayout> {
+ public:
+#if defined(CUTTLEFISH_HOST)
+  static std::shared_ptr<E2EPrimaryRegionView> GetInstance(const char* domain);
+#else
+  static std::shared_ptr<E2EPrimaryRegionView> GetInstance();
+#endif
+};
+class E2ESecondaryRegionView
+    : public vsoc::E2ERegionView<
+          layout::e2e_test::E2ESecondaryTestRegionLayout> {
+ public:
+#if defined(CUTTLEFISH_HOST)
+  static std::shared_ptr<E2ESecondaryRegionView> GetInstance(
+      const char* domain);
+#else
+  static std::shared_ptr<E2ESecondaryRegionView> GetInstance();
+#endif
+};
+class E2EUnfindableRegionView
+    : public vsoc::E2ERegionView<layout::e2e_test::E2EUnfindableRegionLayout> {
+ public:
+#if defined(CUTTLEFISH_HOST)
+  static std::shared_ptr<E2EUnfindableRegionView> GetInstance(
+      const char* domain);
+#else
+  static std::shared_ptr<E2EUnfindableRegionView> GetInstance();
+#endif
+};
+} // namespace vsoc
diff --git a/common/vsoc/lib/fb_bcast_region_view.cpp b/common/vsoc/lib/fb_bcast_region_view.cpp
index 3afd9a3..0ad526a 100644
--- a/common/vsoc/lib/fb_bcast_region_view.cpp
+++ b/common/vsoc/lib/fb_bcast_region_view.cpp
@@ -27,7 +27,7 @@
 // the hwcomposer when it's ran out of work to do and needs to get more from the
 // hwcomposer.
 void FBBroadcastRegionView::BroadcastNewFrame(uint32_t seq_num,
-                                          vsoc_reg_off_t frame_offset) {
+                                              vsoc_reg_off_t frame_offset) {
   {
     auto lock_guard(make_lock_guard(&data()->bcast_lock));
     data()->seq_num = seq_num;
@@ -42,7 +42,8 @@
   SendSignal(side, &data()->seq_num);
 }
 
-vsoc_reg_off_t FBBroadcastRegionView::WaitForNewFrameSince(uint32_t* last_seq_num) {
+vsoc_reg_off_t FBBroadcastRegionView::WaitForNewFrameSince(
+    uint32_t* last_seq_num) {
   static std::unique_ptr<RegionWorker> worker = StartWorker();
   // It's ok to read seq_num here without holding the lock because the lock will
   // be acquired immediately after so we'll block if necessary to wait for the
@@ -61,3 +62,19 @@
     return data()->frame_offset;
   }
 }
+
+#if defined(CUTTLEFISH_HOST)
+std::shared_ptr<FBBroadcastRegionView> FBBroadcastRegionView::GetInstance(
+    const char* domain) {
+  return RegionView::GetInstanceImpl<FBBroadcastRegionView>(
+      [](std::shared_ptr<FBBroadcastRegionView> region, const char* domain) {
+        return region->Open(domain);
+      },
+      domain);
+}
+#else
+std::shared_ptr<FBBroadcastRegionView> FBBroadcastRegionView::GetInstance() {
+  return RegionView::GetInstanceImpl<FBBroadcastRegionView>(
+      std::mem_fn(&FBBroadcastRegionView::Open));
+}
+#endif
diff --git a/common/vsoc/lib/fb_bcast_region_view.h b/common/vsoc/lib/fb_bcast_region_view.h
index 26bc588..e92734f 100644
--- a/common/vsoc/lib/fb_bcast_region_view.h
+++ b/common/vsoc/lib/fb_bcast_region_view.h
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+#include <memory>
+
 #include "common/vsoc/lib/typed_region_view.h"
 #include "common/vsoc/shm/fb_bcast_layout.h"
 #include "common/vsoc/shm/graphics.h"
@@ -23,23 +25,18 @@
 namespace vsoc {
 namespace framebuffer {
 
-class FBBroadcastRegionView : public vsoc::TypedRegionView<
-                              vsoc::layout::framebuffer::FBBroadcastLayout> {
+class FBBroadcastRegionView
+    : public vsoc::TypedRegionView<
+          vsoc::layout::framebuffer::FBBroadcastLayout> {
  public:
   // Screen width in pixels
-  int x_res() const {
-    return data().x_res;
-  }
+  int x_res() const { return data().x_res; }
 
   // Screen height in pixels
-  int y_res() const {
-    return data().y_res;
-  }
+  int y_res() const { return data().y_res; }
 
   // Dots per inch
-  int dpi() const {
-    return data().dpi;
-  }
+  int dpi() const { return data().dpi; }
 
   // Refresh rate in Hertz
   int refresh_rate_hz() const {
@@ -47,9 +44,7 @@
     return kFbRefreshRateHz;
   }
 
-  uint32_t pixel_format() const {
-    return kFbPixelFormat;
-  }
+  uint32_t pixel_format() const { return kFbPixelFormat; }
 
   uint32_t bytes_per_pixel() const {
     return vsoc::PixelFormatProperties<kFbPixelFormat>::bytes_per_pixel;
@@ -67,9 +62,15 @@
   // the new sequential number in *last_seq_num.
   vsoc_reg_off_t WaitForNewFrameSince(uint32_t* last_seq_num);
 
+#if defined(CUTTLEFISH_HOST)
+  static std::shared_ptr<FBBroadcastRegionView> GetInstance(const char* domain);
+#else
+  static std::shared_ptr<FBBroadcastRegionView> GetInstance();
+#endif
+
  private:
   static constexpr uint32_t kFbPixelFormat = vsoc::VSOC_PIXEL_FORMAT_RGBA_8888;
   static constexpr int kFbRefreshRateHz = 60;
 };
-} // namespace framebuffer
-} // namespace vsoc
+}  // namespace framebuffer
+}  // namespace vsoc
diff --git a/common/vsoc/lib/fb_bcast_region_view_test.cpp b/common/vsoc/lib/fb_bcast_region_view_test.cpp
index 0921058..2216b96 100644
--- a/common/vsoc/lib/fb_bcast_region_view_test.cpp
+++ b/common/vsoc/lib/fb_bcast_region_view_test.cpp
@@ -22,19 +22,19 @@
 int main() {
   uint32_t frame_num = 0;
   vsoc_reg_off_t offset = 0;
-  FBBroadcastRegionView region;
+
 #if defined(CUTTLEFISH_HOST)
-  auto rval = region.Open(vsoc::GetDomain().c_str());
+  auto region = FBBroadcastRegionView::GetInstance(vsoc::GetDomain().c_str());
 #else
-  auto rval = region.Open();
+  auto region = FBBroadcastRegionView::GetInstance();
 #endif
-  if (!rval) {
+  if (!region) {
     fprintf(stderr, "Error opening region\n");
     return 1;
   }
 
   while (1) {
-    offset = region.WaitForNewFrameSince(&frame_num);
+    offset = region->WaitForNewFrameSince(&frame_num);
     printf("Signaled frame_num = %d, offset = 0x%x\n", frame_num, offset);
   }
 
diff --git a/common/vsoc/lib/input_events_region_view.cpp b/common/vsoc/lib/input_events_region_view.cpp
index 191fe03..fb07247 100644
--- a/common/vsoc/lib/input_events_region_view.cpp
+++ b/common/vsoc/lib/input_events_region_view.cpp
@@ -96,5 +96,20 @@
   return ret / sizeof(InputEvent);
 }
 
+#if defined(CUTTLEFISH_HOST)
+std::shared_ptr<InputEventsRegionView> InputEventsRegionView::GetInstance(
+    const char* domain) {
+  return RegionView::GetInstanceImpl<InputEventsRegionView>(
+      [](std::shared_ptr<InputEventsRegionView> region, const char* domain) {
+        return region->Open(domain);
+      },
+      domain);
+}
+#else
+std::shared_ptr<InputEventsRegionView> InputEventsRegionView::GetInstance() {
+  return RegionView::GetInstanceImpl<InputEventsRegionView>(
+      std::mem_fn(&InputEventsRegionView::Open));
+}
+#endif
 }
 }
diff --git a/common/vsoc/lib/input_events_region_view.h b/common/vsoc/lib/input_events_region_view.h
index 87627ed..93a6ccb 100644
--- a/common/vsoc/lib/input_events_region_view.h
+++ b/common/vsoc/lib/input_events_region_view.h
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+#include <memory>
+
 #include "common/vsoc/lib/typed_region_view.h"
 #include "common/vsoc/shm/input_events_layout.h"
 #include "uapi/vsoc_shm.h"
@@ -48,7 +50,12 @@
   intptr_t GetScreenEventsOrWait(InputEvent* buffer, int max_event_count);
   intptr_t GetKeyboardEventsOrWait(InputEvent* buffer, int max_event_count);
   intptr_t GetPowerButtonEventsOrWait(InputEvent* buffer, int max_event_count);
-};
 
+#if defined(CUTTLEFISH_HOST)
+  static std::shared_ptr<InputEventsRegionView> GetInstance(const char* domain);
+#else
+  static std::shared_ptr<InputEventsRegionView> GetInstance();
+#endif
+};
 }  // namespace input_events
 }  // namespace vsoc
diff --git a/common/vsoc/lib/region_view.h b/common/vsoc/lib/region_view.h
index 0f82ace..efc1335 100644
--- a/common/vsoc/lib/region_view.h
+++ b/common/vsoc/lib/region_view.h
@@ -24,6 +24,7 @@
 #include <cstdint>
 
 #include <functional>
+#include <map>
 #include <thread>
 
 #include "common/libs/fs/shared_fd.h"
@@ -202,6 +203,49 @@
     return rval;
   }
 
+  // Implementation of the region singletons. This method cannot be called
+  // directly, but rather from static function in the concrete region views
+  // classes.
+  template <typename R>
+#if defined(CUTTLEFISH_HOST)
+  static std::shared_ptr<R> GetInstanceImpl(
+      std::function<bool(std::shared_ptr<R>, const char*)> initializer,
+      const char* domain) {
+    static std::mutex mtx;
+    static std::map<std::string, std::shared_ptr<R>> instances;
+    if (!domain) {
+      return nullptr;
+    }
+    std::lock_guard<std::mutex> lock(mtx);
+    // Get a reference to the actual shared pointer that's stored in the map, if
+    // there wasn't one it will be default constructed pointing to nullptr.
+    std::shared_ptr<R>& instance = instances[domain];
+    if (!instance) {
+      // Update the referenced pointer with the address of the newly created
+      // region view.
+      instance.reset(new R());
+      if (!initializer(instance, domain)) {
+        instance.reset();
+      }
+    }
+    return instance;
+  }
+#else
+  static std::shared_ptr<R> GetInstanceImpl(
+      std::function<bool(std::shared_ptr<R>)> initializer) {
+    static std::mutex mtx;
+    static std::shared_ptr<R> instance;
+    std::lock_guard<std::mutex> lock(mtx);
+    if (!instance) {
+      instance.reset(new R());
+      if (!initializer(instance)) {
+        instance.reset();
+      }
+    }
+    return instance;
+  }
+#endif
+
   std::shared_ptr<RegionControl> control_;
   void* region_base_{};
 };
diff --git a/common/vsoc/lib/ril_region_view.cpp b/common/vsoc/lib/ril_region_view.cpp
index 98c0625..366ca6d 100644
--- a/common/vsoc/lib/ril_region_view.cpp
+++ b/common/vsoc/lib/ril_region_view.cpp
@@ -23,30 +23,20 @@
 namespace vsoc {
 namespace ril {
 
-// TODO(jemoreira): use the general region singleton implementation when ready
 #if defined(CUTTLEFISH_HOST)
-RilRegionView* RilRegionView::GetInstance(const char* domain) {
-#else
-RilRegionView* RilRegionView::GetInstance() {
-#endif
-  static std::mutex m;
-  static RilRegionView* region;
-
-  std::lock_guard<std::mutex> lock(m);
-  if (!region) {
-    region = new RilRegionView();
-
-#if defined(CUTTLEFISH_HOST)
-    if (!region->Open(domain)) {
-#else
-    if (!region->Open()) {
-#endif
-      delete region;
-      region = nullptr;
-    }
-  }
-  return region;
+std::shared_ptr<RilRegionView> RilRegionView::GetInstance(const char* domain) {
+  return RegionView::GetInstanceImpl<RilRegionView>(
+      [](std::shared_ptr<RilRegionView> region, const char* domain) {
+        return region->Open(domain);
+      },
+      domain);
 }
+#else
+std::shared_ptr<RilRegionView> RilRegionView::GetInstance() {
+  return RegionView::GetInstanceImpl<RilRegionView>(
+      std::mem_fn(&RilRegionView::Open));
+}
+#endif
 
 const char* RilRegionView::address_and_prefix_length() const {
   static char buffer[sizeof(data().ipaddr) + 3]{};  // <ipaddr>/dd
diff --git a/common/vsoc/lib/ril_region_view.h b/common/vsoc/lib/ril_region_view.h
index 69c573f..dcd9e00 100644
--- a/common/vsoc/lib/ril_region_view.h
+++ b/common/vsoc/lib/ril_region_view.h
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+#include <memory>
+
 #include "common/vsoc/lib/typed_region_view.h"
 #include "common/vsoc/shm/ril_layout.h"
 
@@ -24,9 +26,10 @@
     : public vsoc::TypedRegionView<vsoc::layout::ril::RilLayout> {
  public:
 #if defined(CUTTLEFISH_HOST)
-  static RilRegionView* GetInstance(const char* domain = nullptr);
+  static std::shared_ptr<RilRegionView> GetInstance(
+      const char* domain = nullptr);
 #else
-  static RilRegionView* GetInstance();
+  static std::shared_ptr<RilRegionView> GetInstance();
 #endif
 
   // returns a string with '<ip>/<prefix_len>' like this: 192.168.99.2/30
diff --git a/common/vsoc/lib/typed_region_view.h b/common/vsoc/lib/typed_region_view.h
index ec16c4d..7a599f6 100644
--- a/common/vsoc/lib/typed_region_view.h
+++ b/common/vsoc/lib/typed_region_view.h
@@ -49,6 +49,7 @@
         control_->region_desc().offset_of_region_data);
   }
 
+ protected:
 #if defined(CUTTLEFISH_HOST)
   bool Open(const char* domain) {
     return RegionView::Open(LayoutType::region_name, domain);
diff --git a/common/vsoc/lib/wifi_exchange_view.cpp b/common/vsoc/lib/wifi_exchange_view.cpp
index 301f35f..1bbc189 100644
--- a/common/vsoc/lib/wifi_exchange_view.cpp
+++ b/common/vsoc/lib/wifi_exchange_view.cpp
@@ -48,5 +48,21 @@
   memcpy(mac_address, data()->mac_address, ETH_ALEN);
 }
 
+#if defined(CUTTLEFISH_HOST)
+std::shared_ptr<WifiExchangeView> WifiExchangeView::GetInstance(
+    const char* domain) {
+  return RegionView::GetInstanceImpl<WifiExchangeView>(
+      [](std::shared_ptr<WifiExchangeView> region, const char* domain) {
+        return region->Open(domain);
+      },
+      domain);
+}
+#else
+std::shared_ptr<WifiExchangeView> WifiExchangeView::GetInstance() {
+  return RegionView::GetInstanceImpl<WifiExchangeView>(
+      std::mem_fn(&WifiExchangeView::Open));
+}
+#endif
+
 }  // namespace wifi
 }  // namespace vsoc
diff --git a/common/vsoc/lib/wifi_exchange_view.h b/common/vsoc/lib/wifi_exchange_view.h
index 6bdab03..5d00bd8 100644
--- a/common/vsoc/lib/wifi_exchange_view.h
+++ b/common/vsoc/lib/wifi_exchange_view.h
@@ -15,6 +15,8 @@
  */
 #pragma once
 
+#include <memory>
+
 #include "common/vsoc/lib/typed_region_view.h"
 #include "common/vsoc/shm/wifi_exchange_layout.h"
 #include "uapi/vsoc_shm.h"
@@ -39,6 +41,12 @@
 
   void SetConfigReady();
   void WaitConfigReady();
+
+#if defined(CUTTLEFISH_HOST)
+  static std::shared_ptr<WifiExchangeView> GetInstance(const char* domain);
+#else
+  static std::shared_ptr<WifiExchangeView> GetInstance();
+#endif
 };
 
 }  // namespace wifi
diff --git a/guest/commands/vsoc_input_service/vsoc_input_service.cpp b/guest/commands/vsoc_input_service/vsoc_input_service.cpp
index c969aea..fd535cb 100644
--- a/guest/commands/vsoc_input_service/vsoc_input_service.cpp
+++ b/guest/commands/vsoc_input_service/vsoc_input_service.cpp
@@ -37,12 +37,6 @@
 
 namespace {
 
-template <class RegionView>
-RegionView* GetRegionView() {
-  static RegionView instance;
-  return &instance;
-}
-
 void EventLoop(std::shared_ptr<VirtualDeviceBase> device,
                std::function<int(InputEvent*, int)> next_events) {
   while (1) {
@@ -70,8 +64,9 @@
     return false;
   }
 
-  FBBroadcastRegionView* fb_broadcast = GetRegionView<FBBroadcastRegionView>();
-  if (!fb_broadcast->Open()) {
+  std::shared_ptr<FBBroadcastRegionView> fb_broadcast =
+      FBBroadcastRegionView::GetInstance();
+  if (!fb_broadcast) {
     SLOGE("Failed to open framebuffer broadcast region");
     return false;
   }
@@ -86,9 +81,8 @@
 }
 
 bool VSoCInputService::ProcessEvents() {
-  InputEventsRegionView* input_events_rv =
-      GetRegionView<InputEventsRegionView>();
-  input_events_rv->Open();
+  std::shared_ptr<InputEventsRegionView> input_events_rv =
+      InputEventsRegionView::GetInstance();
   // TODO(jemoreira): Post available devices to region
   input_events_rv->StartWorker();
 
@@ -96,22 +90,22 @@
   std::thread screen_thread([this]() {
     EventLoop(
         virtual_touchscreen_, [](InputEvent* event_buffer, int max_events) {
-          return GetRegionView<InputEventsRegionView>()->GetScreenEventsOrWait(
+          return InputEventsRegionView::GetInstance()->GetScreenEventsOrWait(
               event_buffer, max_events);
         });
   });
   std::thread keyboard_thread([this]() {
     EventLoop(virtual_keyboard_, [](InputEvent* event_buffer, int max_events) {
-      return GetRegionView<InputEventsRegionView>()->GetKeyboardEventsOrWait(
+      return InputEventsRegionView::GetInstance()->GetKeyboardEventsOrWait(
           event_buffer, max_events);
     });
   });
   std::thread button_thread([this]() {
-    EventLoop(virtual_power_button_, [](InputEvent* event_buffer,
-                                        int max_events) {
-      return GetRegionView<InputEventsRegionView>()->GetPowerButtonEventsOrWait(
-          event_buffer, max_events);
-    });
+    EventLoop(virtual_power_button_,
+              [](InputEvent* event_buffer, int max_events) {
+                return InputEventsRegionView::GetInstance()
+                    ->GetPowerButtonEventsOrWait(event_buffer, max_events);
+              });
   });
 
   screen_thread.join();
diff --git a/guest/frontend/vnc_server/virtual_inputs.cpp b/guest/frontend/vnc_server/virtual_inputs.cpp
index 0deffa2..822f47c 100644
--- a/guest/frontend/vnc_server/virtual_inputs.cpp
+++ b/guest/frontend/vnc_server/virtual_inputs.cpp
@@ -29,214 +29,216 @@
 using vsoc::input_events::InputEventsRegionView;
 
 namespace {
-  void AddKeyMappings(std::map<uint32_t, uint32_t>* key_mapping) {
-    (*key_mapping)[cvd::xk::AltLeft] = KEY_LEFTALT;
-    (*key_mapping)[cvd::xk::ControlLeft] = KEY_LEFTCTRL;
-    (*key_mapping)[cvd::xk::ShiftLeft] = KEY_LEFTSHIFT;
-    (*key_mapping)[cvd::xk::AltRight] = KEY_RIGHTALT;
-    (*key_mapping)[cvd::xk::ControlRight] = KEY_RIGHTCTRL;
-    (*key_mapping)[cvd::xk::ShiftRight] = KEY_RIGHTSHIFT;
-    (*key_mapping)[cvd::xk::MetaLeft] = KEY_LEFTMETA;
-    (*key_mapping)[cvd::xk::MetaRight] = KEY_RIGHTMETA;
-    (*key_mapping)[cvd::xk::MultiKey] = KEY_COMPOSE;
+void AddKeyMappings(std::map<uint32_t, uint32_t>* key_mapping) {
+  (*key_mapping)[cvd::xk::AltLeft] = KEY_LEFTALT;
+  (*key_mapping)[cvd::xk::ControlLeft] = KEY_LEFTCTRL;
+  (*key_mapping)[cvd::xk::ShiftLeft] = KEY_LEFTSHIFT;
+  (*key_mapping)[cvd::xk::AltRight] = KEY_RIGHTALT;
+  (*key_mapping)[cvd::xk::ControlRight] = KEY_RIGHTCTRL;
+  (*key_mapping)[cvd::xk::ShiftRight] = KEY_RIGHTSHIFT;
+  (*key_mapping)[cvd::xk::MetaLeft] = KEY_LEFTMETA;
+  (*key_mapping)[cvd::xk::MetaRight] = KEY_RIGHTMETA;
+  (*key_mapping)[cvd::xk::MultiKey] = KEY_COMPOSE;
 
-    (*key_mapping)[cvd::xk::CapsLock] = KEY_CAPSLOCK;
-    (*key_mapping)[cvd::xk::NumLock] = KEY_NUMLOCK;
-    (*key_mapping)[cvd::xk::ScrollLock] = KEY_SCROLLLOCK;
+  (*key_mapping)[cvd::xk::CapsLock] = KEY_CAPSLOCK;
+  (*key_mapping)[cvd::xk::NumLock] = KEY_NUMLOCK;
+  (*key_mapping)[cvd::xk::ScrollLock] = KEY_SCROLLLOCK;
 
-    (*key_mapping)[cvd::xk::BackSpace] = KEY_BACKSPACE;
-    (*key_mapping)[cvd::xk::Tab] = KEY_TAB;
-    (*key_mapping)[cvd::xk::Return] = KEY_ENTER;
-    (*key_mapping)[cvd::xk::Escape] = KEY_ESC;
+  (*key_mapping)[cvd::xk::BackSpace] = KEY_BACKSPACE;
+  (*key_mapping)[cvd::xk::Tab] = KEY_TAB;
+  (*key_mapping)[cvd::xk::Return] = KEY_ENTER;
+  (*key_mapping)[cvd::xk::Escape] = KEY_ESC;
 
-    (*key_mapping)[' '] = KEY_SPACE;
-    (*key_mapping)['!'] = KEY_1;
-    (*key_mapping)['"'] = KEY_APOSTROPHE;
-    (*key_mapping)['#'] = KEY_3;
-    (*key_mapping)['$'] = KEY_4;
-    (*key_mapping)['%'] = KEY_5;
-    (*key_mapping)['^'] = KEY_6;
-    (*key_mapping)['&'] = KEY_7;
-    (*key_mapping)['\''] = KEY_APOSTROPHE;
-    (*key_mapping)['('] = KEY_9;
-    (*key_mapping)[')'] = KEY_0;
-    (*key_mapping)['*'] = KEY_8;
-    (*key_mapping)['+'] = KEY_EQUAL;
-    (*key_mapping)[','] = KEY_COMMA;
-    (*key_mapping)['-'] = KEY_MINUS;
-    (*key_mapping)['.'] = KEY_DOT;
-    (*key_mapping)['/'] = KEY_SLASH;
-    (*key_mapping)['0'] = KEY_0;
-    (*key_mapping)['1'] = KEY_1;
-    (*key_mapping)['2'] = KEY_2;
-    (*key_mapping)['3'] = KEY_3;
-    (*key_mapping)['4'] = KEY_4;
-    (*key_mapping)['5'] = KEY_5;
-    (*key_mapping)['6'] = KEY_6;
-    (*key_mapping)['7'] = KEY_7;
-    (*key_mapping)['8'] = KEY_8;
-    (*key_mapping)['9'] = KEY_9;
-    (*key_mapping)[':'] = KEY_SEMICOLON;
-    (*key_mapping)[';'] = KEY_SEMICOLON;
-    (*key_mapping)['<'] = KEY_COMMA;
-    (*key_mapping)['='] = KEY_EQUAL;
-    (*key_mapping)['>'] = KEY_DOT;
-    (*key_mapping)['?'] = KEY_SLASH;
-    (*key_mapping)['@'] = KEY_2;
-    (*key_mapping)['A'] = KEY_A;
-    (*key_mapping)['B'] = KEY_B;
-    (*key_mapping)['C'] = KEY_C;
-    (*key_mapping)['D'] = KEY_D;
-    (*key_mapping)['E'] = KEY_E;
-    (*key_mapping)['F'] = KEY_F;
-    (*key_mapping)['G'] = KEY_G;
-    (*key_mapping)['H'] = KEY_H;
-    (*key_mapping)['I'] = KEY_I;
-    (*key_mapping)['J'] = KEY_J;
-    (*key_mapping)['K'] = KEY_K;
-    (*key_mapping)['L'] = KEY_L;
-    (*key_mapping)['M'] = KEY_M;
-    (*key_mapping)['N'] = KEY_N;
-    (*key_mapping)['O'] = KEY_O;
-    (*key_mapping)['P'] = KEY_P;
-    (*key_mapping)['Q'] = KEY_Q;
-    (*key_mapping)['R'] = KEY_R;
-    (*key_mapping)['S'] = KEY_S;
-    (*key_mapping)['T'] = KEY_T;
-    (*key_mapping)['U'] = KEY_U;
-    (*key_mapping)['V'] = KEY_V;
-    (*key_mapping)['W'] = KEY_W;
-    (*key_mapping)['X'] = KEY_X;
-    (*key_mapping)['Y'] = KEY_Y;
-    (*key_mapping)['Z'] = KEY_Z;
-    (*key_mapping)['['] = KEY_LEFTBRACE;
-    (*key_mapping)['\\'] = KEY_BACKSLASH;
-    (*key_mapping)[']'] = KEY_RIGHTBRACE;
-    (*key_mapping)['-'] = KEY_MINUS;
-    (*key_mapping)['_'] = KEY_MINUS;
-    (*key_mapping)['`'] = KEY_GRAVE;
-    (*key_mapping)['a'] = KEY_A;
-    (*key_mapping)['b'] = KEY_B;
-    (*key_mapping)['c'] = KEY_C;
-    (*key_mapping)['d'] = KEY_D;
-    (*key_mapping)['e'] = KEY_E;
-    (*key_mapping)['f'] = KEY_F;
-    (*key_mapping)['g'] = KEY_G;
-    (*key_mapping)['h'] = KEY_H;
-    (*key_mapping)['i'] = KEY_I;
-    (*key_mapping)['j'] = KEY_J;
-    (*key_mapping)['k'] = KEY_K;
-    (*key_mapping)['l'] = KEY_L;
-    (*key_mapping)['m'] = KEY_M;
-    (*key_mapping)['n'] = KEY_N;
-    (*key_mapping)['o'] = KEY_O;
-    (*key_mapping)['p'] = KEY_P;
-    (*key_mapping)['q'] = KEY_Q;
-    (*key_mapping)['r'] = KEY_R;
-    (*key_mapping)['s'] = KEY_S;
-    (*key_mapping)['t'] = KEY_T;
-    (*key_mapping)['u'] = KEY_U;
-    (*key_mapping)['v'] = KEY_V;
-    (*key_mapping)['w'] = KEY_W;
-    (*key_mapping)['x'] = KEY_X;
-    (*key_mapping)['y'] = KEY_Y;
-    (*key_mapping)['z'] = KEY_Z;
-    (*key_mapping)['{'] = KEY_LEFTBRACE;
-    (*key_mapping)['\\'] = KEY_BACKSLASH;
-    (*key_mapping)['|'] = KEY_BACKSLASH;
-    (*key_mapping)['}'] = KEY_RIGHTBRACE;
-    (*key_mapping)['~'] = KEY_GRAVE;
+  (*key_mapping)[' '] = KEY_SPACE;
+  (*key_mapping)['!'] = KEY_1;
+  (*key_mapping)['"'] = KEY_APOSTROPHE;
+  (*key_mapping)['#'] = KEY_3;
+  (*key_mapping)['$'] = KEY_4;
+  (*key_mapping)['%'] = KEY_5;
+  (*key_mapping)['^'] = KEY_6;
+  (*key_mapping)['&'] = KEY_7;
+  (*key_mapping)['\''] = KEY_APOSTROPHE;
+  (*key_mapping)['('] = KEY_9;
+  (*key_mapping)[')'] = KEY_0;
+  (*key_mapping)['*'] = KEY_8;
+  (*key_mapping)['+'] = KEY_EQUAL;
+  (*key_mapping)[','] = KEY_COMMA;
+  (*key_mapping)['-'] = KEY_MINUS;
+  (*key_mapping)['.'] = KEY_DOT;
+  (*key_mapping)['/'] = KEY_SLASH;
+  (*key_mapping)['0'] = KEY_0;
+  (*key_mapping)['1'] = KEY_1;
+  (*key_mapping)['2'] = KEY_2;
+  (*key_mapping)['3'] = KEY_3;
+  (*key_mapping)['4'] = KEY_4;
+  (*key_mapping)['5'] = KEY_5;
+  (*key_mapping)['6'] = KEY_6;
+  (*key_mapping)['7'] = KEY_7;
+  (*key_mapping)['8'] = KEY_8;
+  (*key_mapping)['9'] = KEY_9;
+  (*key_mapping)[':'] = KEY_SEMICOLON;
+  (*key_mapping)[';'] = KEY_SEMICOLON;
+  (*key_mapping)['<'] = KEY_COMMA;
+  (*key_mapping)['='] = KEY_EQUAL;
+  (*key_mapping)['>'] = KEY_DOT;
+  (*key_mapping)['?'] = KEY_SLASH;
+  (*key_mapping)['@'] = KEY_2;
+  (*key_mapping)['A'] = KEY_A;
+  (*key_mapping)['B'] = KEY_B;
+  (*key_mapping)['C'] = KEY_C;
+  (*key_mapping)['D'] = KEY_D;
+  (*key_mapping)['E'] = KEY_E;
+  (*key_mapping)['F'] = KEY_F;
+  (*key_mapping)['G'] = KEY_G;
+  (*key_mapping)['H'] = KEY_H;
+  (*key_mapping)['I'] = KEY_I;
+  (*key_mapping)['J'] = KEY_J;
+  (*key_mapping)['K'] = KEY_K;
+  (*key_mapping)['L'] = KEY_L;
+  (*key_mapping)['M'] = KEY_M;
+  (*key_mapping)['N'] = KEY_N;
+  (*key_mapping)['O'] = KEY_O;
+  (*key_mapping)['P'] = KEY_P;
+  (*key_mapping)['Q'] = KEY_Q;
+  (*key_mapping)['R'] = KEY_R;
+  (*key_mapping)['S'] = KEY_S;
+  (*key_mapping)['T'] = KEY_T;
+  (*key_mapping)['U'] = KEY_U;
+  (*key_mapping)['V'] = KEY_V;
+  (*key_mapping)['W'] = KEY_W;
+  (*key_mapping)['X'] = KEY_X;
+  (*key_mapping)['Y'] = KEY_Y;
+  (*key_mapping)['Z'] = KEY_Z;
+  (*key_mapping)['['] = KEY_LEFTBRACE;
+  (*key_mapping)['\\'] = KEY_BACKSLASH;
+  (*key_mapping)[']'] = KEY_RIGHTBRACE;
+  (*key_mapping)['-'] = KEY_MINUS;
+  (*key_mapping)['_'] = KEY_MINUS;
+  (*key_mapping)['`'] = KEY_GRAVE;
+  (*key_mapping)['a'] = KEY_A;
+  (*key_mapping)['b'] = KEY_B;
+  (*key_mapping)['c'] = KEY_C;
+  (*key_mapping)['d'] = KEY_D;
+  (*key_mapping)['e'] = KEY_E;
+  (*key_mapping)['f'] = KEY_F;
+  (*key_mapping)['g'] = KEY_G;
+  (*key_mapping)['h'] = KEY_H;
+  (*key_mapping)['i'] = KEY_I;
+  (*key_mapping)['j'] = KEY_J;
+  (*key_mapping)['k'] = KEY_K;
+  (*key_mapping)['l'] = KEY_L;
+  (*key_mapping)['m'] = KEY_M;
+  (*key_mapping)['n'] = KEY_N;
+  (*key_mapping)['o'] = KEY_O;
+  (*key_mapping)['p'] = KEY_P;
+  (*key_mapping)['q'] = KEY_Q;
+  (*key_mapping)['r'] = KEY_R;
+  (*key_mapping)['s'] = KEY_S;
+  (*key_mapping)['t'] = KEY_T;
+  (*key_mapping)['u'] = KEY_U;
+  (*key_mapping)['v'] = KEY_V;
+  (*key_mapping)['w'] = KEY_W;
+  (*key_mapping)['x'] = KEY_X;
+  (*key_mapping)['y'] = KEY_Y;
+  (*key_mapping)['z'] = KEY_Z;
+  (*key_mapping)['{'] = KEY_LEFTBRACE;
+  (*key_mapping)['\\'] = KEY_BACKSLASH;
+  (*key_mapping)['|'] = KEY_BACKSLASH;
+  (*key_mapping)['}'] = KEY_RIGHTBRACE;
+  (*key_mapping)['~'] = KEY_GRAVE;
 
-    (*key_mapping)[cvd::xk::F1] = KEY_F1;
-    (*key_mapping)[cvd::xk::F2] = KEY_F2;
-    (*key_mapping)[cvd::xk::F3] = KEY_F3;
-    (*key_mapping)[cvd::xk::F4] = KEY_F4;
-    (*key_mapping)[cvd::xk::F5] = KEY_F5;
-    (*key_mapping)[cvd::xk::F6] = KEY_F6;
-    (*key_mapping)[cvd::xk::F7] = KEY_F7;
-    (*key_mapping)[cvd::xk::F8] = KEY_F8;
-    (*key_mapping)[cvd::xk::F9] = KEY_F9;
-    (*key_mapping)[cvd::xk::F10] = KEY_F10;
-    (*key_mapping)[cvd::xk::F11] = KEY_F11;
-    (*key_mapping)[cvd::xk::F12] = KEY_F12;
-    (*key_mapping)[cvd::xk::F13] = KEY_F13;
-    (*key_mapping)[cvd::xk::F14] = KEY_F14;
-    (*key_mapping)[cvd::xk::F15] = KEY_F15;
-    (*key_mapping)[cvd::xk::F16] = KEY_F16;
-    (*key_mapping)[cvd::xk::F17] = KEY_F17;
-    (*key_mapping)[cvd::xk::F18] = KEY_F18;
-    (*key_mapping)[cvd::xk::F19] = KEY_F19;
-    (*key_mapping)[cvd::xk::F20] = KEY_F20;
-    (*key_mapping)[cvd::xk::F21] = KEY_F21;
-    (*key_mapping)[cvd::xk::F22] = KEY_F22;
-    (*key_mapping)[cvd::xk::F23] = KEY_F23;
-    (*key_mapping)[cvd::xk::F24] = KEY_F24;
+  (*key_mapping)[cvd::xk::F1] = KEY_F1;
+  (*key_mapping)[cvd::xk::F2] = KEY_F2;
+  (*key_mapping)[cvd::xk::F3] = KEY_F3;
+  (*key_mapping)[cvd::xk::F4] = KEY_F4;
+  (*key_mapping)[cvd::xk::F5] = KEY_F5;
+  (*key_mapping)[cvd::xk::F6] = KEY_F6;
+  (*key_mapping)[cvd::xk::F7] = KEY_F7;
+  (*key_mapping)[cvd::xk::F8] = KEY_F8;
+  (*key_mapping)[cvd::xk::F9] = KEY_F9;
+  (*key_mapping)[cvd::xk::F10] = KEY_F10;
+  (*key_mapping)[cvd::xk::F11] = KEY_F11;
+  (*key_mapping)[cvd::xk::F12] = KEY_F12;
+  (*key_mapping)[cvd::xk::F13] = KEY_F13;
+  (*key_mapping)[cvd::xk::F14] = KEY_F14;
+  (*key_mapping)[cvd::xk::F15] = KEY_F15;
+  (*key_mapping)[cvd::xk::F16] = KEY_F16;
+  (*key_mapping)[cvd::xk::F17] = KEY_F17;
+  (*key_mapping)[cvd::xk::F18] = KEY_F18;
+  (*key_mapping)[cvd::xk::F19] = KEY_F19;
+  (*key_mapping)[cvd::xk::F20] = KEY_F20;
+  (*key_mapping)[cvd::xk::F21] = KEY_F21;
+  (*key_mapping)[cvd::xk::F22] = KEY_F22;
+  (*key_mapping)[cvd::xk::F23] = KEY_F23;
+  (*key_mapping)[cvd::xk::F24] = KEY_F24;
 
-    (*key_mapping)[cvd::xk::Keypad0] = KEY_KP0;
-    (*key_mapping)[cvd::xk::Keypad1] = KEY_KP1;
-    (*key_mapping)[cvd::xk::Keypad2] = KEY_KP2;
-    (*key_mapping)[cvd::xk::Keypad3] = KEY_KP3;
-    (*key_mapping)[cvd::xk::Keypad4] = KEY_KP4;
-    (*key_mapping)[cvd::xk::Keypad5] = KEY_KP5;
-    (*key_mapping)[cvd::xk::Keypad6] = KEY_KP6;
-    (*key_mapping)[cvd::xk::Keypad7] = KEY_KP7;
-    (*key_mapping)[cvd::xk::Keypad8] = KEY_KP8;
-    (*key_mapping)[cvd::xk::Keypad9] = KEY_KP9;
-    (*key_mapping)[cvd::xk::KeypadMultiply] = KEY_KPASTERISK;
-    (*key_mapping)[cvd::xk::KeypadSubtract] = KEY_KPMINUS;
-    (*key_mapping)[cvd::xk::KeypadAdd] = KEY_KPPLUS;
-    (*key_mapping)[cvd::xk::KeypadDecimal] = KEY_KPDOT;
-    (*key_mapping)[cvd::xk::KeypadEnter] = KEY_KPENTER;
-    (*key_mapping)[cvd::xk::KeypadDivide] = KEY_KPSLASH;
-    (*key_mapping)[cvd::xk::KeypadEqual] = KEY_KPEQUAL;
-    (*key_mapping)[cvd::xk::PlusMinus] = KEY_KPPLUSMINUS;
+  (*key_mapping)[cvd::xk::Keypad0] = KEY_KP0;
+  (*key_mapping)[cvd::xk::Keypad1] = KEY_KP1;
+  (*key_mapping)[cvd::xk::Keypad2] = KEY_KP2;
+  (*key_mapping)[cvd::xk::Keypad3] = KEY_KP3;
+  (*key_mapping)[cvd::xk::Keypad4] = KEY_KP4;
+  (*key_mapping)[cvd::xk::Keypad5] = KEY_KP5;
+  (*key_mapping)[cvd::xk::Keypad6] = KEY_KP6;
+  (*key_mapping)[cvd::xk::Keypad7] = KEY_KP7;
+  (*key_mapping)[cvd::xk::Keypad8] = KEY_KP8;
+  (*key_mapping)[cvd::xk::Keypad9] = KEY_KP9;
+  (*key_mapping)[cvd::xk::KeypadMultiply] = KEY_KPASTERISK;
+  (*key_mapping)[cvd::xk::KeypadSubtract] = KEY_KPMINUS;
+  (*key_mapping)[cvd::xk::KeypadAdd] = KEY_KPPLUS;
+  (*key_mapping)[cvd::xk::KeypadDecimal] = KEY_KPDOT;
+  (*key_mapping)[cvd::xk::KeypadEnter] = KEY_KPENTER;
+  (*key_mapping)[cvd::xk::KeypadDivide] = KEY_KPSLASH;
+  (*key_mapping)[cvd::xk::KeypadEqual] = KEY_KPEQUAL;
+  (*key_mapping)[cvd::xk::PlusMinus] = KEY_KPPLUSMINUS;
 
-    (*key_mapping)[cvd::xk::SysReq] = KEY_SYSRQ;
-    (*key_mapping)[cvd::xk::LineFeed] = KEY_LINEFEED;
-    (*key_mapping)[cvd::xk::Home] = KEY_HOME;
-    (*key_mapping)[cvd::xk::Up] = KEY_UP;
-    (*key_mapping)[cvd::xk::PageUp] = KEY_PAGEUP;
-    (*key_mapping)[cvd::xk::Left] = KEY_LEFT;
-    (*key_mapping)[cvd::xk::Right] = KEY_RIGHT;
-    (*key_mapping)[cvd::xk::End] = KEY_END;
-    (*key_mapping)[cvd::xk::Down] = KEY_DOWN;
-    (*key_mapping)[cvd::xk::PageDown] = KEY_PAGEDOWN;
-    (*key_mapping)[cvd::xk::Insert] = KEY_INSERT;
-    (*key_mapping)[cvd::xk::Delete] = KEY_DELETE;
-    (*key_mapping)[cvd::xk::Pause] = KEY_PAUSE;
-    (*key_mapping)[cvd::xk::KeypadSeparator] = KEY_KPCOMMA;
-    (*key_mapping)[cvd::xk::Yen] = KEY_YEN;
-    (*key_mapping)[cvd::xk::Cancel] = KEY_STOP;
-    (*key_mapping)[cvd::xk::Redo] = KEY_AGAIN;
-    (*key_mapping)[cvd::xk::Undo] = KEY_UNDO;
-    (*key_mapping)[cvd::xk::Find] = KEY_FIND;
-    (*key_mapping)[cvd::xk::Print] = KEY_PRINT;
-    (*key_mapping)[cvd::xk::VolumeDown] = KEY_VOLUMEDOWN;
-    (*key_mapping)[cvd::xk::Mute] = KEY_MUTE;
-    (*key_mapping)[cvd::xk::VolumeUp] = KEY_VOLUMEUP;
-    (*key_mapping)[cvd::xk::Menu] = KEY_MENU;
-    (*key_mapping)[cvd::xk::VNCMenu] = KEY_MENU;
-  }
+  (*key_mapping)[cvd::xk::SysReq] = KEY_SYSRQ;
+  (*key_mapping)[cvd::xk::LineFeed] = KEY_LINEFEED;
+  (*key_mapping)[cvd::xk::Home] = KEY_HOME;
+  (*key_mapping)[cvd::xk::Up] = KEY_UP;
+  (*key_mapping)[cvd::xk::PageUp] = KEY_PAGEUP;
+  (*key_mapping)[cvd::xk::Left] = KEY_LEFT;
+  (*key_mapping)[cvd::xk::Right] = KEY_RIGHT;
+  (*key_mapping)[cvd::xk::End] = KEY_END;
+  (*key_mapping)[cvd::xk::Down] = KEY_DOWN;
+  (*key_mapping)[cvd::xk::PageDown] = KEY_PAGEDOWN;
+  (*key_mapping)[cvd::xk::Insert] = KEY_INSERT;
+  (*key_mapping)[cvd::xk::Delete] = KEY_DELETE;
+  (*key_mapping)[cvd::xk::Pause] = KEY_PAUSE;
+  (*key_mapping)[cvd::xk::KeypadSeparator] = KEY_KPCOMMA;
+  (*key_mapping)[cvd::xk::Yen] = KEY_YEN;
+  (*key_mapping)[cvd::xk::Cancel] = KEY_STOP;
+  (*key_mapping)[cvd::xk::Redo] = KEY_AGAIN;
+  (*key_mapping)[cvd::xk::Undo] = KEY_UNDO;
+  (*key_mapping)[cvd::xk::Find] = KEY_FIND;
+  (*key_mapping)[cvd::xk::Print] = KEY_PRINT;
+  (*key_mapping)[cvd::xk::VolumeDown] = KEY_VOLUMEDOWN;
+  (*key_mapping)[cvd::xk::Mute] = KEY_MUTE;
+  (*key_mapping)[cvd::xk::VolumeUp] = KEY_VOLUMEUP;
+  (*key_mapping)[cvd::xk::Menu] = KEY_MENU;
+  (*key_mapping)[cvd::xk::VNCMenu] = KEY_MENU;
 }
+}  // namespace
 
 VirtualInputs::VirtualInputs() {
-  bool open = input_events_region_view_.Open();
-  LOG_ALWAYS_FATAL_IF(!open, "Failed to open Input events region view");
+  input_events_region_view_ =
+      vsoc::input_events::InputEventsRegionView::GetInstance();
+  LOG_FATAL_IF(!input_events_region_view_,
+               "Failed to open Input events region view");
   AddKeyMappings(&keymapping_);
 }
 
 void VirtualInputs::GenerateKeyPressEvent(int key_code, bool down) {
   if (keymapping_.count(key_code)) {
-    input_events_region_view_.HandleKeyboardEvent(down, keymapping_[key_code]);
+    input_events_region_view_->HandleKeyboardEvent(down, keymapping_[key_code]);
   } else {
     ALOGI("Unknown keycode %d", key_code);
   }
 }
 
 void VirtualInputs::PressPowerButton(bool down) {
-  input_events_region_view_.HandlePowerButtonEvent(down);
+  input_events_region_view_->HandlePowerButtonEvent(down);
 }
 
 void VirtualInputs::HandlePointerEvent(bool touch_down, int x, int y) {
-  input_events_region_view_.HandleSingleTouchEvent(touch_down, x, y);
+  input_events_region_view_->HandleSingleTouchEvent(touch_down, x, y);
 }
diff --git a/guest/frontend/vnc_server/virtual_inputs.h b/guest/frontend/vnc_server/virtual_inputs.h
index fa989a9..3b129af 100644
--- a/guest/frontend/vnc_server/virtual_inputs.h
+++ b/guest/frontend/vnc_server/virtual_inputs.h
@@ -34,7 +34,8 @@
   void HandlePointerEvent(bool touch_down, int x, int y);
 
  private:
-  vsoc::input_events::InputEventsRegionView input_events_region_view_;
+  std::shared_ptr<vsoc::input_events::InputEventsRegionView>
+      input_events_region_view_;
   std::map<uint32_t, uint32_t> keymapping_;
 };
 
diff --git a/guest/hals/audio/record_audio.cpp b/guest/hals/audio/record_audio.cpp
index 6e9937d..3aa27fd 100644
--- a/guest/hals/audio/record_audio.cpp
+++ b/guest/hals/audio/record_audio.cpp
@@ -77,8 +77,7 @@
     usage(me);
   }
 
-  AudioDataRegionView *audio_data_rv = AudioDataRegionView::GetInstance();
-  audio_data_rv->Open();
+  auto audio_data_rv = AudioDataRegionView::GetInstance();
 
   /* std::unique_ptr<vsoc::RegionWorker> audio_worker = */
     audio_data_rv->StartWorker();
@@ -103,7 +102,7 @@
 
   while (!gDone) {
     intptr_t res = audio_data_rv->data()->audio_queue.Read(
-            audio_data_rv,
+            audio_data_rv.get(),
             reinterpret_cast<char *>(buffer),
             sizeof(buffer));
 
diff --git a/guest/hals/audio/vsoc_audio.cpp b/guest/hals/audio/vsoc_audio.cpp
index 67ff28f..fe21ffd 100644
--- a/guest/hals/audio/vsoc_audio.cpp
+++ b/guest/hals/audio/vsoc_audio.cpp
@@ -215,7 +215,7 @@
 
 ssize_t GceAudio::SendMsg(const msghdr& msg, int /* flags */) {
     intptr_t res = audio_data_rv_->data()->audio_queue.Writev(
-            audio_data_rv_,
+            audio_data_rv_.get(),
             msg.msg_iov,
             msg.msg_iovlen,
             true /* non_blocking */);
@@ -294,7 +294,6 @@
   GceAudio* rval = new GceAudio;
 
   rval->audio_data_rv_ = AudioDataRegionView::GetInstance();
-  rval->audio_data_rv_->Open();
   rval->audio_worker_ = rval->audio_data_rv_->StartWorker();
 
   rval->common.tag = HARDWARE_DEVICE_TAG;
diff --git a/guest/hals/audio/vsoc_audio.h b/guest/hals/audio/vsoc_audio.h
index 6a6e0e6..3d1f917 100644
--- a/guest/hals/audio/vsoc_audio.h
+++ b/guest/hals/audio/vsoc_audio.h
@@ -17,6 +17,7 @@
 
 #include <list>
 #include <map>
+#include <memory>
 
 #include "common/libs/fs/shared_fd.h"
 #include "common/libs/threads/cuttlefish_thread.h"
@@ -266,7 +267,7 @@
 #endif
 
   using AudioDataRegionView = vsoc::audio_data::AudioDataRegionView;
-  AudioDataRegionView *audio_data_rv_ = NULL;
+  std::shared_ptr<AudioDataRegionView> audio_data_rv_;
   std::unique_ptr<vsoc::RegionWorker> audio_worker_;
 
   // Lock to protect the data below.
diff --git a/guest/hals/gralloc/gralloc.cpp b/guest/hals/gralloc/gralloc.cpp
index 32bcc07..5d395db 100644
--- a/guest/hals/gralloc/gralloc.cpp
+++ b/guest/hals/gralloc/gralloc.cpp
@@ -14,12 +14,16 @@
  * limitations under the License.
  */
 
-#include "gralloc_vsoc_priv.h"
 #include <hardware/gralloc.h>
 #include <hardware/hardware.h>
 #include <log/log.h>
 #include <stdlib.h>
 
+#include "guest/hals/gralloc/gralloc_vsoc_priv.h"
+#include "guest/vsoc/lib/gralloc_region_view.h"
+
+using vsoc::gralloc::GrallocRegionView;
+
 namespace {
 
 static const int kSwiftShaderPadding = 4;
@@ -160,9 +164,13 @@
 
 /******************************************************************************/
 
-static int gralloc_alloc(
-    alloc_device_t* dev, int w, int h, int format, int /*usage*/,
-    buffer_handle_t* pHandle, int* pStrideInPixels) {
+static int gralloc_alloc(alloc_device_t* /*dev*/,
+                         int w,
+                         int h,
+                         int format,
+                         int /*usage*/,
+                         buffer_handle_t* pHandle,
+                         int* pStrideInPixels) {
   int fd = -1;
 
   int bytes_per_pixel = formatToBytesPerPixel(format);
@@ -180,8 +188,7 @@
   }
   size = align(size + formatToBytesPerFrame(format, w, h), PAGE_SIZE);
   size += PAGE_SIZE;
-  fd = reinterpret_cast<vsoc_alloc_device_t*>(dev)
-           ->gralloc_region->AllocateBuffer(size, &offset);
+  fd = GrallocRegionView::GetInstance()->AllocateBuffer(size, &offset);
   if (fd < 0) {
     ALOGE("Unable to allocate buffer (%s)", strerror(-fd));
     return fd;
@@ -267,8 +274,7 @@
     dev->device.alloc   = gralloc_alloc;
     dev->device.free    = gralloc_free;
 
-    dev->gralloc_region = vsoc::gralloc::GrallocRegionView::GetInstance();
-    if (!dev->gralloc_region) {
+    if (!GrallocRegionView::GetInstance()) {
       LOG_FATAL("Unable to instantiate the gralloc region");
       free(dev);
       return -EIO;
diff --git a/guest/hals/gralloc/gralloc_vsoc_priv.h b/guest/hals/gralloc/gralloc_vsoc_priv.h
index 2f4f287..3f4d179 100644
--- a/guest/hals/gralloc/gralloc_vsoc_priv.h
+++ b/guest/hals/gralloc/gralloc_vsoc_priv.h
@@ -19,11 +19,8 @@
 #include <hardware/gralloc.h>
 #include <log/log.h>
 
-#include "guest/vsoc/lib/gralloc_region_view.h"
-
 struct vsoc_alloc_device_t {
   alloc_device_t device;
-  vsoc::gralloc::GrallocRegionView* gralloc_region;
 };
 
 struct vsoc_gralloc_module_t {
diff --git a/guest/hals/hwcomposer/hwcomposer.cpp b/guest/hals/hwcomposer/hwcomposer.cpp
index 7b91f46..cb59136 100644
--- a/guest/hals/hwcomposer/hwcomposer.cpp
+++ b/guest/hals/hwcomposer/hwcomposer.cpp
@@ -31,12 +31,6 @@
 using vsoc::framebuffer::FBBroadcastRegionView;
 
 // TODO(jemoreira): FBBroadcastRegionView may belong in the HWC region
-
-FBBroadcastRegionView* GetFBBroadcastRegionView() {
-  static FBBroadcastRegionView instance;
-  return &instance;
-}
-
 namespace {
 
 // Ensures that the layer does not include any inconsistencies
@@ -88,7 +82,6 @@
   pthread_t vsync_thread;
   int64_t vsync_base_timestamp;
   int32_t vsync_period_ns;
-  FBBroadcastRegionView* fb_broadcast;
   uint32_t frame_num;
 };
 
@@ -173,8 +166,8 @@
       const vsoc_buffer_handle_t* fb_handle =
           reinterpret_cast<const vsoc_buffer_handle_t*>(
               list->hwLayers[i].handle);
-      pdev->fb_broadcast->BroadcastNewFrame(pdev->frame_num++,
-                                            fb_handle->offset);
+      FBBroadcastRegionView::GetInstance()->BroadcastNewFrame(
+          pdev->frame_num++, fb_handle->offset);
       break;
     }
   }
@@ -240,18 +233,19 @@
   return -EINVAL;
 }
 
-int32_t vsoc_hwc_attribute(vsoc_hwc_device* pdev, uint32_t attribute) {
+int32_t vsoc_hwc_attribute(uint32_t attribute) {
+  auto fb_broadcast = FBBroadcastRegionView::GetInstance();
   switch (attribute) {
     case HWC_DISPLAY_VSYNC_PERIOD:
-      return 1000000000 / pdev->fb_broadcast->refresh_rate_hz();
+      return 1000000000 / fb_broadcast->refresh_rate_hz();
     case HWC_DISPLAY_WIDTH:
-      return pdev->fb_broadcast->x_res();
+      return fb_broadcast->x_res();
     case HWC_DISPLAY_HEIGHT:
-      return pdev->fb_broadcast->y_res();
+      return fb_broadcast->y_res();
     case HWC_DISPLAY_DPI_X:
     case HWC_DISPLAY_DPI_Y:
       // The number of pixels per thousand inches
-      return pdev->fb_broadcast->dpi() * 1000;
+      return fb_broadcast->dpi() * 1000;
     case HWC_DISPLAY_COLOR_TRANSFORM:
       // TODO(jemoreira): Add the other color transformations
       return HAL_COLOR_TRANSFORM_IDENTITY;
@@ -261,10 +255,9 @@
   }
 }
 
-int hwc_getDisplayAttributes(struct hwc_composer_device_1* dev, int disp,
+int hwc_getDisplayAttributes(struct hwc_composer_device_1* /*dev*/, int disp,
                              uint32_t /*config*/, const uint32_t* attributes,
                              int32_t* values) {
-  vsoc_hwc_device* pdev = reinterpret_cast<vsoc_hwc_device*>(dev);
 
   if (disp != HWC_DISPLAY_PRIMARY) {
     ALOGE("Unknown display type %u", disp);
@@ -272,7 +265,7 @@
   }
 
   for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) {
-    values[i] = vsoc_hwc_attribute(pdev, attributes[i]);
+    values[i] = vsoc_hwc_attribute(attributes[i]);
   }
 
   return 0;
@@ -325,8 +318,7 @@
   dev->base.getDisplayConfigs = hwc_getDisplayConfigs;
   dev->base.getDisplayAttributes = hwc_getDisplayAttributes;
 
-  dev->fb_broadcast = GetFBBroadcastRegionView();
-  if (!dev->fb_broadcast->Open()) {
+  if (!FBBroadcastRegionView::GetInstance()) {
     ALOGE("Unable to open framebuffer broadcaster (%s)", __FUNCTION__);
     delete dev;
     return -1;
diff --git a/guest/libs/legacy_framebuffer/vsoc_framebuffer.cpp b/guest/libs/legacy_framebuffer/vsoc_framebuffer.cpp
index 32071a0..1669715 100644
--- a/guest/libs/legacy_framebuffer/vsoc_framebuffer.cpp
+++ b/guest/libs/legacy_framebuffer/vsoc_framebuffer.cpp
@@ -39,12 +39,6 @@
 const char* const VSoCFrameBuffer::kFrameBufferPath =
     "/dev/userspace_framebuffer";
 
-
-static vsoc::framebuffer::FBBroadcastRegionView* GetFBBroadcastRegionView() {
-  static vsoc::framebuffer::FBBroadcastRegionView instance;
-  return &instance;
-}
-
 const VSoCFrameBuffer & VSoCFrameBuffer::getInstance() {
   static VSoCFrameBuffer instance;
   instance.Configure();
@@ -53,11 +47,12 @@
 
 
 VSoCFrameBuffer::VSoCFrameBuffer()
-  : fb_region_view_(GetFBBroadcastRegionView()), line_length_(-1) { }
+  : line_length_(-1) { }
 
 
 void VSoCFrameBuffer::Configure() {
-  if (!fb_region_view_->Open()) {
+  fb_region_view_ = vsoc::framebuffer::FBBroadcastRegionView::GetInstance();
+  if (!fb_region_view_) {
     SLOGE("Failed to open broadcaster region");
   }
   line_length_ = align(x_res() * sizeof(Pixel));
diff --git a/guest/libs/legacy_framebuffer/vsoc_framebuffer.h b/guest/libs/legacy_framebuffer/vsoc_framebuffer.h
index 873c2fc..ce3ef6a 100644
--- a/guest/libs/legacy_framebuffer/vsoc_framebuffer.h
+++ b/guest/libs/legacy_framebuffer/vsoc_framebuffer.h
@@ -17,7 +17,9 @@
 
 #include <pthread.h>
 #include <sys/mman.h>
+
 #include <climits>
+#include <memory>
 
 struct private_handle_t;
 struct remoter_request_packet;
@@ -101,7 +103,7 @@
   VSoCFrameBuffer();
   void Configure();
 
-  vsoc::framebuffer::FBBroadcastRegionView* fb_region_view_;
+  std::shared_ptr<vsoc::framebuffer::FBBroadcastRegionView> fb_region_view_;
   static const int kBitsPerPixel = sizeof(Pixel) * CHAR_BIT;
   // Length of a scan-line in bytes.
   int line_length_;
diff --git a/guest/vsoc/lib/gralloc_region_view.cpp b/guest/vsoc/lib/gralloc_region_view.cpp
index 2ec1aba..a3073d6 100644
--- a/guest/vsoc/lib/gralloc_region_view.cpp
+++ b/guest/vsoc/lib/gralloc_region_view.cpp
@@ -16,11 +16,11 @@
 
 #include "guest/vsoc/lib/gralloc_region_view.h"
 
-#include <atomic>
 #include <common/vsoc/lib/lock_guard.h>
 #include <log/log.h>
 #include <sys/types.h>
 #include <uapi/vsoc_shm.h>
+#include <atomic>
 
 using vsoc::gralloc::GrallocRegionView;
 using vsoc::layout::gralloc::BufferEntry;
@@ -40,17 +40,7 @@
 
 }  // namespace
 
-GrallocRegionView::GrallocRegionView() {
-  // The construction in the singleton is thread safe, so we call Open here to
-  // make sure it opens thread safe too. The singleton will return null if the
-  // region failed to open.
-  Open();
-}
-
 bool GrallocRegionView::Open() {
-  if (is_open_) {
-    return true;
-  }
   if (!vsoc::ManagerRegionView<GrallocManagerLayout>::Open()) {
     return false;
   }
@@ -67,7 +57,6 @@
       managed_region->region_size() - offset_of_buffer_memory_;
 
   // TODO(jemoreira): Handle the case of unexpected values in the region.
-  is_open_ = true;
   return true;
 }
 
@@ -152,14 +141,8 @@
   }
 }
 
-/* static */
-// The C++03 standard does not guarantee this singleton implemention to be
-// thread safe, however magic statics are part of the gcc compiler since
-// version 4.3.
-GrallocRegionView* GrallocRegionView::GetInstance() {
-  static GrallocRegionView singleton;
-  if (!singleton.is_open_) {
-    return NULL;
-  }
-  return &singleton;
+
+std::shared_ptr<GrallocRegionView> GrallocRegionView::GetInstance() {
+  return RegionView::GetInstanceImpl<GrallocRegionView>(
+      std::mem_fn(&GrallocRegionView::Open));
 }
diff --git a/guest/vsoc/lib/gralloc_region_view.h b/guest/vsoc/lib/gralloc_region_view.h
index 2432e8c..3857cf0 100644
--- a/guest/vsoc/lib/gralloc_region_view.h
+++ b/guest/vsoc/lib/gralloc_region_view.h
@@ -18,6 +18,7 @@
 
 #include <common/vsoc/shm/gralloc_layout.h>
 #include <guest/vsoc/lib/manager_region_view.h>
+#include <memory>
 #include <stdlib.h>
 
 namespace vsoc {
@@ -26,6 +27,7 @@
 class GrallocRegionView : public vsoc::ManagerRegionView<
                           vsoc::layout::gralloc::GrallocManagerLayout> {
  public:
+  GrallocRegionView() = default;
   // Allocates a gralloc buffer of (at least) the specified size. Returns a file
   // descriptor that exposes the buffer when mmapped from 0 to (the page
   // aligned) size (and fails to mmap anything outside of that range) or a
@@ -33,9 +35,9 @@
   // TODO(jemoreira): Include debug info like stride, width, height, etc
   int AllocateBuffer(size_t size, uint32_t* begin_offset = nullptr);
 
-  static GrallocRegionView* GetInstance();
+  static std::shared_ptr<GrallocRegionView> GetInstance();
+
  protected:
-  GrallocRegionView();
   GrallocRegionView(const GrallocRegionView&) = delete;
   GrallocRegionView & operator=(const GrallocRegionView&) = delete;
 
@@ -43,7 +45,6 @@
 
   vsoc_reg_off_t offset_of_buffer_memory_{};
   uint32_t total_buffer_memory_{};
-  bool is_open_{false};
 };
 
 } // namespace gralloc
diff --git a/guest/vsoc/lib/guest_region_e2e_test.cpp b/guest/vsoc/lib/guest_region_e2e_test.cpp
index 2dcce74..564a68a 100644
--- a/guest/vsoc/lib/guest_region_e2e_test.cpp
+++ b/guest/vsoc/lib/guest_region_e2e_test.cpp
@@ -42,10 +42,10 @@
 }
 
 template <typename View>
-void DeathTestView(View* r) {
+void DeathTestView() {
   disable_tombstones();
-  // region.Open should never return.
-  EXPECT_FALSE(r->Open());
+  // View::GetInstance should never return.
+  EXPECT_FALSE(!!View::GetInstance());
 }
 
 // Here is a summary of the two regions interrupt and write test:
@@ -64,7 +64,7 @@
 // 12. Confirm that no interrupt is pending in the second region
 
 template <typename View>
-void SetGuestStrings(View* in) {
+void SetGuestStrings(std::shared_ptr<View> in) {
   size_t num_data = in->string_size();
   EXPECT_LE(2U, num_data);
   for (size_t i = 0; i < num_data; ++i) {
@@ -76,7 +76,7 @@
 }
 
 template <typename View>
-void CheckPeerStrings(View* in) {
+void CheckPeerStrings(std::shared_ptr<View> in) {
   size_t num_data = in->string_size();
   EXPECT_LE(2U, num_data);
   for (size_t i = 0; i < num_data; ++i) {
@@ -85,76 +85,94 @@
 }
 
 TEST(RegionTest, BasicPeerTests) {
-  vsoc::E2EPrimaryRegionView primary;
-  vsoc::E2ESecondaryRegionView secondary;
-  ASSERT_TRUE(primary.Open());
-  ASSERT_TRUE(secondary.Open());
+  std::shared_ptr<vsoc::E2EPrimaryRegionView> primary =
+      vsoc::E2EPrimaryRegionView::GetInstance();
+  std::shared_ptr<vsoc::E2ESecondaryRegionView> secondary =
+      vsoc::E2ESecondaryRegionView::GetInstance();
+  ASSERT_TRUE(!!primary);
+  ASSERT_TRUE(!!secondary);
   LOG(INFO) << "Regions are open";
-  SetGuestStrings(&primary);
+  SetGuestStrings(primary);
   LOG(INFO) << "Primary guest strings are set";
-  EXPECT_FALSE(secondary.HasIncomingInterrupt());
+  EXPECT_FALSE(secondary->HasIncomingInterrupt());
   LOG(INFO) << "Verified no early second interrupt";
-  EXPECT_TRUE(primary.MaybeInterruptPeer());
+  EXPECT_TRUE(primary->MaybeInterruptPeer());
   LOG(INFO) << "Interrupt sent. Waiting for first interrupt from peer";
-  primary.WaitForInterrupt();
+  primary->WaitForInterrupt();
   LOG(INFO) << "First interrupt received";
-  CheckPeerStrings(&primary);
+  CheckPeerStrings(primary);
   LOG(INFO) << "Verified peer's primary strings";
-  SetGuestStrings(&secondary);
+  SetGuestStrings(secondary);
   LOG(INFO) << "Secondary guest strings are set";
-  EXPECT_TRUE(secondary.MaybeInterruptPeer());
+  EXPECT_TRUE(secondary->MaybeInterruptPeer());
   LOG(INFO) << "Second interrupt sent";
-  secondary.WaitForInterrupt();
+  secondary->WaitForInterrupt();
   LOG(INFO) << "Second interrupt received";
-  CheckPeerStrings(&secondary);
+  CheckPeerStrings(secondary);
   LOG(INFO) << "Verified peer's secondary strings";
 
   // Test signals
-  EXPECT_FALSE(secondary.HasIncomingInterrupt());
+  EXPECT_FALSE(secondary->HasIncomingInterrupt());
   LOG(INFO) << "Verified no early second signal";
   vsoc::layout::Sides side;
   side.value_ = vsoc::layout::Sides::Peer;
-  primary.SendSignal(side, &primary.data()->guest_to_host_signal);
+  primary->SendSignal(side, &primary->data()->guest_to_host_signal);
   LOG(INFO) << "Signal sent. Waiting for first signal from peer";
-  primary.WaitForInterrupt();
+  primary->WaitForInterrupt();
   int count = 0;  // counts the number of signals received.
-  primary.ProcessSignalsFromPeer(
+  primary->ProcessSignalsFromPeer(
       [&primary, &count](std::atomic<uint32_t>* uaddr) {
         ++count;
-        EXPECT_TRUE(uaddr == &primary.data()->host_to_guest_signal);
+        EXPECT_TRUE(uaddr == &primary->data()->host_to_guest_signal);
       });
   EXPECT_TRUE(count == 1);
   LOG(INFO) << "Signal received on primary region";
-  secondary.SendSignal(side, &secondary.data()->guest_to_host_signal);
+  secondary->SendSignal(side, &secondary->data()->guest_to_host_signal);
   LOG(INFO) << "Signal sent. Waiting for second signal from peer";
-  secondary.WaitForInterrupt();
+  secondary->WaitForInterrupt();
   count = 0;
-  secondary.ProcessSignalsFromPeer(
+  secondary->ProcessSignalsFromPeer(
       [&secondary, &count](std::atomic<uint32_t>* uaddr) {
         ++count;
-        EXPECT_TRUE(uaddr == &secondary.data()->host_to_guest_signal);
+        EXPECT_TRUE(uaddr == &secondary->data()->host_to_guest_signal);
       });
   EXPECT_TRUE(count == 1);
   LOG(INFO) << "Signal received on secondary region";
 
-  EXPECT_FALSE(primary.HasIncomingInterrupt());
-  EXPECT_FALSE(secondary.HasIncomingInterrupt());
+  EXPECT_FALSE(primary->HasIncomingInterrupt());
+  EXPECT_FALSE(secondary->HasIncomingInterrupt());
   LOG(INFO) << "PASS: BasicPeerTests";
 }
 
 TEST(RegionTest, MissingRegionDeathTest) {
-  vsoc::E2EUnfindableRegionView test;
   // EXPECT_DEATH creates a child for the test, so we do it out here.
   // DeathTestGuestRegion will actually do the deadly call after ensuring
   // that we don't create an unwanted tombstone.
-  EXPECT_EXIT(DeathTestView(&test), testing::ExitedWithCode(2),
+  EXPECT_EXIT(DeathTestView<vsoc::E2EUnfindableRegionView>(),
+              testing::ExitedWithCode(2),
               ".*" DEATH_TEST_MESSAGE ".*");
 }
 
+// Region view classes to allow calling the Open() function from the test.
+class E2EManagedTestRegionView
+    : public vsoc::TypedRegionView<E2EManagedTestRegionLayout> {
+ public:
+  bool Open() {
+    return vsoc::TypedRegionView<E2EManagedTestRegionLayout>::Open();
+  }
+};
+class E2EManagerTestRegionView
+    : public vsoc::ManagerRegionView<E2EManagerTestRegionLayout> {
+ public:
+  bool Open() {
+    return vsoc::ManagerRegionView<E2EManagerTestRegionLayout>::Open();
+  }
+};
+
 class ManagedRegionTest {
  public:
   void testManagedRegionFailMap() {
-    vsoc::TypedRegionView<E2EManagedTestRegionLayout> managed_region;
+    E2EManagedTestRegionView managed_region;
     disable_tombstones();
     // managed_region.Open should never return.
     EXPECT_FALSE(managed_region.Open());
@@ -204,7 +222,7 @@
   ManagedRegionTest() {}
 
  private:
-  vsoc::ManagerRegionView<E2EManagerTestRegionLayout> manager_region_;
+  E2EManagerTestRegionView manager_region_;
 };
 
 TEST(ManagedRegionTest, ManagedRegionFailMap) {
@@ -223,9 +241,9 @@
   testing::InitGoogleTest(&argc, argv);
   int rval = RUN_ALL_TESTS();
   if (!rval) {
-    vsoc::E2EPrimaryRegionView region;
-    region.Open();
-    region.guest_status(vsoc::layout::e2e_test::E2E_MEMORY_FILLED);
+    std::shared_ptr<vsoc::E2EPrimaryRegionView> region =
+        vsoc::E2EPrimaryRegionView::GetInstance();
+    region->guest_status(vsoc::layout::e2e_test::E2E_MEMORY_FILLED);
     LOG(INFO) << "stage_1_guest_region_e2e_tests PASSED";
   }
   return rval;
diff --git a/host/commands/launch/fb_bcast_region_handler.cc b/host/commands/launch/fb_bcast_region_handler.cc
index 4e89b79..03f20b7 100644
--- a/host/commands/launch/fb_bcast_region_handler.cc
+++ b/host/commands/launch/fb_bcast_region_handler.cc
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#include <glog/logging.h>
 #include <gflags/gflags.h>
+#include <glog/logging.h>
 
 #include "common/vsoc/lib/fb_bcast_region_view.h"
 #include "host/commands/launch/pre_launch_initializers.h"
@@ -26,12 +26,14 @@
 DEFINE_int32(dpi, 160, "Pixels per inch for the screen");
 
 void InitializeFBBroadcastRegion() {
-  vsoc::framebuffer::FBBroadcastRegionView region;
-  if (!region.Open(vsoc::GetDomain().c_str())) {
+  std::shared_ptr<vsoc::framebuffer::FBBroadcastRegionView> region =
+      vsoc::framebuffer::FBBroadcastRegionView::GetInstance(
+          vsoc::GetDomain().c_str());
+  if (!region) {
     LOG(INFO) << "Framebuffer region was not found";
     return;
   }
-  auto dest = region.data();
+  auto dest = region->data();
   dest->x_res = FLAGS_x_res;
   dest->y_res = FLAGS_y_res;
   dest->dpi = FLAGS_dpi;
diff --git a/host/commands/launch/ril_region_handler.cc b/host/commands/launch/ril_region_handler.cc
index df31735..853c418 100644
--- a/host/commands/launch/ril_region_handler.cc
+++ b/host/commands/launch/ril_region_handler.cc
@@ -162,7 +162,7 @@
     return;
   }
 
-  vsoc::ril::RilRegionView* region =
+  auto region =
       vsoc::ril::RilRegionView::GetInstance(vsoc::GetDomain().c_str());
 
   if (!region) {
diff --git a/host/frontend/vnc_server/main.cpp b/host/frontend/vnc_server/main.cpp
index 65971d4..2616202 100644
--- a/host/frontend/vnc_server/main.cpp
+++ b/host/frontend/vnc_server/main.cpp
@@ -31,9 +31,6 @@
   using ::android::base::ERROR;
   ::android::base::InitLogging(argv, android::base::StderrLogger);
   ::gflags::ParseCommandLineFlags(&argc, &argv, true);
-  if (!cvd::vnc::GetFBBroadcastRegionView()->Open(vsoc::GetDomain().c_str())) {
-    LOG(FATAL) << "Unable to open FBBroadcastRegion";
-  }
   cvd::vnc::VncServer vnc_server(FLAGS_port, FLAGS_agressive);
   vnc_server.MainLoop();
 }
diff --git a/host/frontend/vnc_server/vnc_utils.cpp b/host/frontend/vnc_server/vnc_utils.cpp
index 883a9d1..d4c6dd6 100644
--- a/host/frontend/vnc_server/vnc_utils.cpp
+++ b/host/frontend/vnc_server/vnc_utils.cpp
@@ -15,15 +15,20 @@
  */
 
 #include "common/vsoc/lib/fb_bcast_region_view.h"
+#include "host/libs/config/host_config.h"
 
 using vsoc::framebuffer::FBBroadcastRegionView;
 
 namespace cvd {
 namespace vnc {
 
-FBBroadcastRegionView* GetFBBroadcastRegionView() {
-  static FBBroadcastRegionView instance;
-  return &instance;
+std::shared_ptr<FBBroadcastRegionView> GetFBBroadcastRegionView() {
+  std::shared_ptr<FBBroadcastRegionView> region =
+      FBBroadcastRegionView::GetInstance(vsoc::GetDomain().c_str());
+  if (!region) {
+    LOG(FATAL) << "Unable to open FBBroadcastRegion";
+  }
+  return region;
 }
 
 }  // namespace vnc
diff --git a/host/frontend/vnc_server/vnc_utils.h b/host/frontend/vnc_server/vnc_utils.h
index 61ec6d1..f6bb44a 100644
--- a/host/frontend/vnc_server/vnc_utils.h
+++ b/host/frontend/vnc_server/vnc_utils.h
@@ -61,7 +61,8 @@
   ScreenOrientation orientation{};
 };
 
-vsoc::framebuffer::FBBroadcastRegionView* GetFBBroadcastRegionView();
+std::shared_ptr<vsoc::framebuffer::FBBroadcastRegionView>
+GetFBBroadcastRegionView();
 
 inline int BytesPerPixel() {
   return GetFBBroadcastRegionView()->bytes_per_pixel();
diff --git a/host/vsoc/lib/gralloc_buffer_region_view.cpp b/host/vsoc/lib/gralloc_buffer_region_view.cpp
index c2a8d87..f171396 100644
--- a/host/vsoc/lib/gralloc_buffer_region_view.cpp
+++ b/host/vsoc/lib/gralloc_buffer_region_view.cpp
@@ -16,23 +16,12 @@
 
 #include "host/vsoc/lib/gralloc_buffer_region_view.h"
 
+#include <memory>
 #include <mutex>
 #include "glog/logging.h"
 
 using vsoc::gralloc::GrallocBufferRegionView;
 
-// static
-GrallocBufferRegionView* GrallocBufferRegionView::GetInstance(const char* domain) {
-  static std::mutex mutex;
-  static std::map<std::string, GrallocBufferRegionView*> gralloc_regions;
-
-  std::lock_guard<std::mutex> guard(mutex);
-  if (!gralloc_regions.count(domain)) {
-    gralloc_regions[domain] = new GrallocBufferRegionView(domain);
-  }
-  return gralloc_regions[domain];
-}
-
 uint8_t* GrallocBufferRegionView::OffsetToBufferPtr(vsoc_reg_off_t offset) {
   if (offset <= control_->region_desc().offset_of_region_data ||
       offset >= control_->region_size()) {
@@ -44,6 +33,11 @@
   return region_offset_to_pointer<uint8_t>(offset);
 }
 
-GrallocBufferRegionView::GrallocBufferRegionView(const char* domain) {
-  is_open_ = Open(domain);
+std::shared_ptr<GrallocBufferRegionView> GrallocBufferRegionView::GetInstance(
+    const char* domain) {
+  return RegionView::GetInstanceImpl<GrallocBufferRegionView>(
+      [](std::shared_ptr<GrallocBufferRegionView> region, const char* domain) {
+        return region->Open(domain);
+      },
+      domain);
 }
diff --git a/host/vsoc/lib/gralloc_buffer_region_view.h b/host/vsoc/lib/gralloc_buffer_region_view.h
index f2d10b4..071694c 100644
--- a/host/vsoc/lib/gralloc_buffer_region_view.h
+++ b/host/vsoc/lib/gralloc_buffer_region_view.h
@@ -34,13 +34,15 @@
 class GrallocBufferRegionView
     : vsoc::TypedRegionView<vsoc::layout::gralloc::GrallocBufferLayout> {
  public:
-  static GrallocBufferRegionView* GetInstance(const char* domain);
+  GrallocBufferRegionView() = default;
+  GrallocBufferRegionView(const GrallocBufferRegionView&) = delete;
+  GrallocBufferRegionView& operator=(const GrallocBufferRegionView&) = delete;
 
   uint8_t* OffsetToBufferPtr(vsoc_reg_off_t offset);
- protected:
-  GrallocBufferRegionView(const char* domain);
-  bool is_open_{};
+
+  static std::shared_ptr<GrallocBufferRegionView> GetInstance(
+      const char* domain);
 };
 
-}
-}
+}  // namespace gralloc
+}  // namespace vsoc
diff --git a/host/vsoc/lib/host_region_e2e_test.cpp b/host/vsoc/lib/host_region_e2e_test.cpp
index 64cb2a6..4502381 100644
--- a/host/vsoc/lib/host_region_e2e_test.cpp
+++ b/host/vsoc/lib/host_region_e2e_test.cpp
@@ -38,7 +38,7 @@
 // 12. Confirm that no interrupt is pending in the second region
 
 template <typename View>
-void SetHostStrings(View* in) {
+void SetHostStrings(std::shared_ptr<View> in) {
   size_t num_data = in->string_size();
   EXPECT_LE(static_cast<size_t>(2), num_data);
   for (size_t i = 0; i < num_data; ++i) {
@@ -50,7 +50,7 @@
 }
 
 template <typename View>
-void CheckPeerStrings(View* in) {
+void CheckPeerStrings(std::shared_ptr<View> in) {
   size_t num_data = in->string_size();
   EXPECT_LE(static_cast<size_t>(2), num_data);
   for (size_t i = 0; i < num_data; ++i) {
@@ -59,69 +59,72 @@
 }
 
 TEST(RegionTest, PeerTests) {
-  vsoc::E2EPrimaryRegionView primary;
-  ASSERT_TRUE(primary.Open(vsoc::GetDomain().c_str()));
-  vsoc::E2ESecondaryRegionView secondary;
-  ASSERT_TRUE(secondary.Open(vsoc::GetDomain().c_str()));
+  std::shared_ptr<vsoc::E2EPrimaryRegionView> primary =
+      vsoc::E2EPrimaryRegionView::GetInstance(vsoc::GetDomain().c_str());
+  ASSERT_TRUE(!!primary);
+  std::shared_ptr<vsoc::E2ESecondaryRegionView> secondary =
+      vsoc::E2ESecondaryRegionView::GetInstance(vsoc::GetDomain().c_str());
+  ASSERT_TRUE(!!secondary);
   LOG(INFO) << "Regions are open";
-  SetHostStrings(&primary);
-  EXPECT_FALSE(secondary.HasIncomingInterrupt());
-  EXPECT_TRUE(primary.MaybeInterruptPeer());
+  SetHostStrings(primary);
+  EXPECT_FALSE(secondary->HasIncomingInterrupt());
+  EXPECT_TRUE(primary->MaybeInterruptPeer());
   LOG(INFO) << "Waiting for first interrupt from peer";
-  primary.WaitForInterrupt();
+  primary->WaitForInterrupt();
   LOG(INFO) << "First interrupt received";
-  CheckPeerStrings(&primary);
-  SetHostStrings(&secondary);
-  EXPECT_TRUE(secondary.MaybeInterruptPeer());
+  CheckPeerStrings(primary);
+  SetHostStrings(secondary);
+  EXPECT_TRUE(secondary->MaybeInterruptPeer());
   LOG(INFO) << "Waiting for second interrupt from peer";
-  secondary.WaitForInterrupt();
+  secondary->WaitForInterrupt();
   LOG(INFO) << "Second interrupt received";
-  CheckPeerStrings(&secondary);
+  CheckPeerStrings(secondary);
 
   // Test signals
-  EXPECT_FALSE(secondary.HasIncomingInterrupt());
+  EXPECT_FALSE(secondary->HasIncomingInterrupt());
   LOG(INFO) << "Verified no early second signal";
   vsoc::layout::Sides side;
   side.value_ = vsoc::layout::Sides::Peer;
-  primary.SendSignal(side, &primary.data()->host_to_guest_signal);
+  primary->SendSignal(side, &primary->data()->host_to_guest_signal);
   LOG(INFO) << "Signal sent. Waiting for first signal from peer";
-  primary.WaitForInterrupt();
+  primary->WaitForInterrupt();
   int count = 0;  // counts the number of signals received.
-  primary.ProcessSignalsFromPeer(
+  primary->ProcessSignalsFromPeer(
       [&primary, &count](std::atomic<uint32_t>* uaddr) {
         ++count;
-        EXPECT_TRUE(uaddr == &primary.data()->guest_to_host_signal);
+        EXPECT_TRUE(uaddr == &primary->data()->guest_to_host_signal);
       });
   EXPECT_TRUE(count == 1);
   LOG(INFO) << "Signal received on primary region";
-  secondary.SendSignal(side, &secondary.data()->host_to_guest_signal);
+  secondary->SendSignal(side, &secondary->data()->host_to_guest_signal);
   LOG(INFO) << "Signal sent. Waiting for second signal from peer";
-  secondary.WaitForInterrupt();
+  secondary->WaitForInterrupt();
   count = 0;
-  secondary.ProcessSignalsFromPeer(
-      [&secondary, &count](std::atomic<uint32_t>* uaddr) {
+  secondary->ProcessSignalsFromPeer(
+      [secondary, &count](std::atomic<uint32_t>* uaddr) {
         ++count;
-        EXPECT_TRUE(uaddr == &secondary.data()->guest_to_host_signal);
+        EXPECT_TRUE(uaddr == &secondary->data()->guest_to_host_signal);
       });
   EXPECT_TRUE(count == 1);
   LOG(INFO) << "Signal received on secondary region";
 
-  EXPECT_FALSE(primary.HasIncomingInterrupt());
-  EXPECT_FALSE(secondary.HasIncomingInterrupt());
+  EXPECT_FALSE(primary->HasIncomingInterrupt());
+  EXPECT_FALSE(secondary->HasIncomingInterrupt());
 }
 
 TEST(RegionTest, MissingRegionCausesDeath) {
-  vsoc::E2EUnfindableRegionView test;
-  EXPECT_DEATH(test.Open(vsoc::GetDomain().c_str()), ".*");
+  EXPECT_DEATH(
+      vsoc::E2EUnfindableRegionView::GetInstance(vsoc::GetDomain().c_str()),
+      ".*");
 }
 
 int main(int argc, char** argv) {
   testing::InitGoogleTest(&argc, argv);
   int rval = RUN_ALL_TESTS();
   if (!rval) {
-    vsoc::E2EPrimaryRegionView region;
-    region.Open(vsoc::GetDomain().c_str());
-    region.host_status(vsoc::layout::e2e_test::E2E_MEMORY_FILLED);
+    std::shared_ptr<vsoc::E2EPrimaryRegionView> region =
+        vsoc::E2EPrimaryRegionView::GetInstance(vsoc::GetDomain().c_str());
+    region->host_status(vsoc::layout::e2e_test::E2E_MEMORY_FILLED);
   }
   return rval;
 }