Extract screen connectors from vnc server

The webrtc streamer also needs to use this stuff, by extracting from
here code duplication is avoided.

Bug: 141887532
Test: m; launch_cvd
Change-Id: Ie7494dceb9166105c2783c53626d90f78e47cde6
diff --git a/host/frontend/vnc_server/Android.bp b/host/frontend/vnc_server/Android.bp
index 344e47b..3df8d5f 100644
--- a/host/frontend/vnc_server/Android.bp
+++ b/host/frontend/vnc_server/Android.bp
@@ -20,7 +20,6 @@
         "frame_buffer_watcher.cpp",
         "jpeg_compressor.cpp",
         "main.cpp",
-        "screen_connector.cpp",
         "simulated_hw_composer.cpp",
         "virtual_inputs.cpp",
         "vnc_client_connection.cpp",
@@ -38,6 +37,7 @@
     ],
     static_libs: [
         "libcuttlefish_host_config",
+        "libcuttlefish_screen_connector",
         "libcuttlefish_wayland_server",
         "libffi",
         "libjsoncpp",
diff --git a/host/frontend/vnc_server/frame_buffer_watcher.cpp b/host/frontend/vnc_server/frame_buffer_watcher.cpp
index 592b88e..126fb6b 100644
--- a/host/frontend/vnc_server/frame_buffer_watcher.cpp
+++ b/host/frontend/vnc_server/frame_buffer_watcher.cpp
@@ -27,6 +27,7 @@
 
 #include <glog/logging.h>
 #include "host/frontend/vnc_server/vnc_utils.h"
+#include "host/libs/screen_connector/screen_connector.h"
 
 using cvd::vnc::FrameBufferWatcher;
 
@@ -70,17 +71,17 @@
   Message rotated(raw.size(), 0xAA);
   for (std::uint16_t i = 0; i < w; ++i) {
     for (std::uint16_t j = 0; j < h; ++j) {
-      size_t to = (i * h + j) * BytesPerPixel();
-      size_t from = (w - (i + 1)) * BytesPerPixel() + s * j;
+      size_t to = (i * h + j) * ScreenConnector::BytesPerPixel();
+      size_t from = (w - (i + 1)) * ScreenConnector::BytesPerPixel() + s * j;
       CHECK(from < raw.size());
       CHECK(to < rotated.size());
-      std::memcpy(&rotated[to], &raw[from], BytesPerPixel());
+      std::memcpy(&rotated[to], &raw[from], ScreenConnector::BytesPerPixel());
     }
   }
   std::swap(stripe.x, stripe.y);
   std::swap(stripe.width, stripe.height);
   // The new stride after rotating is the height, as it is not aligned again.
-  stripe.stride = stripe.width * BytesPerPixel();
+  stripe.stride = stripe.width * ScreenConnector::BytesPerPixel();
   stripe.raw_data = std::move(rotated);
   stripe.orientation = ScreenOrientation::Landscape;
   return stripe;
diff --git a/host/frontend/vnc_server/jpeg_compressor.cpp b/host/frontend/vnc_server/jpeg_compressor.cpp
index 2d57707..3bd3753 100644
--- a/host/frontend/vnc_server/jpeg_compressor.cpp
+++ b/host/frontend/vnc_server/jpeg_compressor.cpp
@@ -20,6 +20,7 @@
 #include <glog/logging.h>
 #include "host/frontend/vnc_server/jpeg_compressor.h"
 #include "host/frontend/vnc_server/vnc_utils.h"
+#include "host/libs/screen_connector/screen_connector.h"
 
 using cvd::vnc::JpegCompressor;
 
@@ -31,7 +32,7 @@
 
   cinfo->image_width = width;
   cinfo->image_height = height;
-  cinfo->input_components = cvd::vnc::BytesPerPixel();
+  cinfo->input_components = cvd::ScreenConnector::BytesPerPixel();
   cinfo->in_color_space = JCS_EXT_RGBX;
 
   jpeg_set_defaults(cinfo);
@@ -57,7 +58,7 @@
     auto row = static_cast<JSAMPROW>(const_cast<std::uint8_t*>(
         &frame[(y * stride) +
                (cinfo.next_scanline * stride) +
-               (x * BytesPerPixel())]));
+               (x * cvd::ScreenConnector::BytesPerPixel())]));
     jpeg_write_scanlines(&cinfo, &row, 1);
   }
   jpeg_finish_compress(&cinfo);
diff --git a/host/frontend/vnc_server/screen_connector.cpp b/host/frontend/vnc_server/screen_connector.cpp
deleted file mode 100644
index 333c03e..0000000
--- a/host/frontend/vnc_server/screen_connector.cpp
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2019 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/frontend/vnc_server/screen_connector.h"
-
-#include <atomic>
-#include <condition_variable>
-#include <thread>
-
-#include <glog/logging.h>
-#include <gflags/gflags.h>
-
-#include "host/frontend/vnc_server/vnc_utils.h"
-#include "host/libs/wayland/wayland_server.h"
-
-DEFINE_int32(frame_server_fd, -1, "");
-
-namespace cvd {
-namespace vnc {
-
-namespace {
-
-// TODO(b/128852363): Substitute with one based on memory shared with the
-//  wayland mock
-class SocketBasedScreenConnector : public ScreenConnector {
- public:
-  SocketBasedScreenConnector() {
-    screen_server_thread_ = std::thread([this]() { ServerLoop(); });
-  }
-
-  bool OnFrameAfter(std::uint32_t frame_number,
-                    const FrameCallback& frame_callback) override {
-    int buffer_idx = WaitForNewFrameSince(&frame_number);
-    void* buffer = GetBuffer(buffer_idx);
-    frame_callback(frame_number, reinterpret_cast<uint8_t*>(buffer));
-    return true;
-  }
-
- private:
-  static constexpr int NUM_BUFFERS_ = 4;
-
-  int WaitForNewFrameSince(std::uint32_t* seq_num) {
-    std::unique_lock<std::mutex> lock(new_frame_mtx_);
-    while (seq_num_ == *seq_num) {
-      new_frame_cond_var_.wait(lock);
-    }
-    *seq_num = seq_num_;
-    return newest_buffer_;
-  }
-
-  void* GetBuffer(int buffer_idx) {
-    if (buffer_idx < 0) return nullptr;
-    buffer_idx %= NUM_BUFFERS_;
-    return &buffer_[buffer_idx * ScreenSizeInBytes()];
-  }
-
-  void ServerLoop() {
-    if (FLAGS_frame_server_fd < 0) {
-      LOG(FATAL) << "Invalid file descriptor: " << FLAGS_frame_server_fd;
-      return;
-    }
-    auto server = SharedFD::Dup(FLAGS_frame_server_fd);
-    close(FLAGS_frame_server_fd);
-    if (!server->IsOpen()) {
-      LOG(FATAL) << "Unable to dup screen server: " << server->StrError();
-      return;
-    }
-
-    int current_buffer = 0;
-
-    while (1) {
-      LOG(INFO) << "Screen Connector accepting connections...";
-      auto conn = SharedFD::Accept(*server);
-      if (!conn->IsOpen()) {
-        LOG(ERROR) << "Disconnected fd returned from accept";
-        continue;
-      }
-      while (conn->IsOpen()) {
-        int32_t size = 0;
-        if (conn->Read(&size, sizeof(size)) < 0) {
-          LOG(ERROR) << "Failed to read from hwcomposer: "
-                      << conn->StrError();
-          break;
-        }
-        auto buff = reinterpret_cast<uint8_t*>(GetBuffer(current_buffer));
-        while (size > 0) {
-          auto read = conn->Read(buff, size);
-          if (read < 0) {
-            LOG(ERROR) << "Failed to read from hwcomposer: "
-                       << conn->StrError();
-            conn->Close();
-            break;
-          }
-          size -= read;
-          buff += read;
-        }
-        BroadcastNewFrame(current_buffer);
-        current_buffer = (current_buffer + 1) % NUM_BUFFERS_;
-      }
-    }
-  }
-
-  void BroadcastNewFrame(int buffer_idx) {
-    {
-      std::lock_guard<std::mutex> lock(new_frame_mtx_);
-      seq_num_++;
-      newest_buffer_ = buffer_idx;
-    }
-    new_frame_cond_var_.notify_all();
-  }
-
-  std::vector<std::uint8_t> buffer_ =
-      std::vector<std::uint8_t>(NUM_BUFFERS_ * ScreenSizeInBytes());
-  std::uint32_t seq_num_{0};
-  int newest_buffer_ = 0;
-  std::condition_variable new_frame_cond_var_;
-  std::mutex new_frame_mtx_;
-  std::thread screen_server_thread_;
-};
-
-class WaylandScreenConnector : public ScreenConnector {
- public:
-  WaylandScreenConnector() {
-    int wayland_fd = fcntl(FLAGS_frame_server_fd, F_DUPFD_CLOEXEC, 3);
-    CHECK(wayland_fd != -1) << "Unable to dup server, errno " << errno;
-    close(FLAGS_frame_server_fd);
-
-    server_.reset(new wayland::WaylandServer(wayland_fd));
-  }
-
-  bool OnFrameAfter(std::uint32_t frame_number,
-                    const FrameCallback& frame_callback) override {
-    std::future<void> frame_callback_completed_future =
-      server_->OnFrameAfter(frame_number, frame_callback);
-
-    frame_callback_completed_future.get();
-
-    return true;
-  }
-
- private:
-  std::unique_ptr<wayland::WaylandServer> server_;
-};
-
-}  // namespace
-
-ScreenConnector* ScreenConnector::Get() {
-  auto config = vsoc::CuttlefishConfig::Get();
-  if (config->gpu_mode() == vsoc::kGpuModeDrmVirgl) {
-    return new WaylandScreenConnector();
-  } else {
-    return new SocketBasedScreenConnector();
-  }
-}
-
-}  // namespace vnc
-}  // namespace cvd
diff --git a/host/frontend/vnc_server/simulated_hw_composer.cpp b/host/frontend/vnc_server/simulated_hw_composer.cpp
index 8eb6d39..7b478f4 100644
--- a/host/frontend/vnc_server/simulated_hw_composer.cpp
+++ b/host/frontend/vnc_server/simulated_hw_composer.cpp
@@ -16,9 +16,13 @@
 
 #include "host/frontend/vnc_server/simulated_hw_composer.h"
 
+#include <gflags/gflags.h>
+
 #include "host/frontend/vnc_server/vnc_utils.h"
 #include "host/libs/config/cuttlefish_config.h"
 
+DEFINE_int32(frame_server_fd, -1, "");
+
 using cvd::vnc::SimulatedHWComposer;
 
 SimulatedHWComposer::SimulatedHWComposer(BlackBoard* bb)
@@ -27,7 +31,8 @@
       engine_{std::random_device{}()},
 #endif
       bb_{bb},
-      stripes_(kMaxQueueElements, &SimulatedHWComposer::EraseHalfOfElements) {
+      stripes_(kMaxQueueElements, &SimulatedHWComposer::EraseHalfOfElements),
+      screen_connector_(ScreenConnector::Get(FLAGS_frame_server_fd)) {
   stripe_maker_ = std::thread(&SimulatedHWComposer::MakeStripes, this);
 }
 
@@ -69,13 +74,14 @@
 
 void SimulatedHWComposer::MakeStripes() {
   std::uint32_t previous_frame_number = 0;
-  auto screen_height = ActualScreenHeight();
+  auto screen_height = ScreenConnector::ScreenHeight();
   Message raw_screen;
   std::uint64_t stripe_seq_num = 1;
 
   const FrameCallback frame_callback = [&](uint32_t frame_number,
                                            uint8_t* frame_pixels) {
-    raw_screen.assign(frame_pixels, frame_pixels + ScreenSizeInBytes());
+    raw_screen.assign(frame_pixels,
+                      frame_pixels + ScreenConnector::ScreenSizeInBytes());
 
     for (int i = 0; i < kNumStripes; ++i) {
       ++stripe_seq_num;
@@ -86,10 +92,11 @@
       std::uint16_t height =
           screen_height / kNumStripes +
           (i + 1 == kNumStripes ? screen_height % kNumStripes : 0);
-      const auto* raw_start =
-          &raw_screen[y * ActualScreenWidth() * BytesPerPixel()];
+      const auto* raw_start = &raw_screen[y * ScreenConnector::ScreenWidth() *
+                                          ScreenConnector::BytesPerPixel()];
       const auto* raw_end =
-          raw_start + (height * ActualScreenWidth() * BytesPerPixel());
+          raw_start + (height * ScreenConnector::ScreenWidth() *
+                       ScreenConnector::BytesPerPixel());
       // creating a named object and setting individual data members in order
       // to make klp happy
       // TODO (haining) construct this inside the call when not compiling
@@ -99,8 +106,8 @@
       s.frame_id = frame_number;
       s.x = 0;
       s.y = y;
-      s.width = ActualScreenWidth();
-      s.stride = ActualScreenStride();
+      s.width = ScreenConnector::ScreenWidth();
+      s.stride = ScreenConnector::ScreenStride();
       s.height = height;
       s.raw_data.assign(raw_start, raw_end);
       s.seq_number = StripeSeqNumber{stripe_seq_num};
diff --git a/host/frontend/vnc_server/simulated_hw_composer.h b/host/frontend/vnc_server/simulated_hw_composer.h
index 802cc7f..4a51f78 100644
--- a/host/frontend/vnc_server/simulated_hw_composer.h
+++ b/host/frontend/vnc_server/simulated_hw_composer.h
@@ -26,7 +26,7 @@
 #include "common/libs/thread_safe_queue/thread_safe_queue.h"
 #include "common/libs/threads/thread_annotations.h"
 #include "host/frontend/vnc_server/blackboard.h"
-#include "host/frontend/vnc_server/screen_connector.h"
+#include "host/libs/screen_connector/screen_connector.h"
 
 namespace cvd {
 namespace vnc {
@@ -60,7 +60,7 @@
   BlackBoard* bb_{};
   ThreadSafeQueue<Stripe> stripes_;
   std::thread stripe_maker_;
-  std::shared_ptr<ScreenConnector> screen_connector_{ScreenConnector::Get()};
+  std::shared_ptr<ScreenConnector> screen_connector_;
 };
 }  // namespace vnc
 }  // namespace cvd
diff --git a/host/frontend/vnc_server/vnc_client_connection.cpp b/host/frontend/vnc_server/vnc_client_connection.cpp
index b81bb88..8394e65 100644
--- a/host/frontend/vnc_server/vnc_client_connection.cpp
+++ b/host/frontend/vnc_server/vnc_client_connection.cpp
@@ -37,6 +37,7 @@
 #include "host/frontend/vnc_server/mocks.h"
 #include "host/frontend/vnc_server/vnc_utils.h"
 #include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/screen_connector/screen_connector.h"
 
 using cvd::Message;
 using cvd::vnc::Stripe;
@@ -475,7 +476,7 @@
     std::lock_guard<std::mutex> guard(m_);
     if (current_orientation_ == ScreenOrientation::Landscape) {
       std::tie(x_pos, y_pos) =
-          std::make_pair(ActualScreenWidth() - y_pos, x_pos);
+          std::make_pair(ScreenConnector::ScreenWidth() - y_pos, x_pos);
     }
   }
   virtual_inputs_->HandlePointerEvent(button_mask, x_pos, y_pos);
@@ -505,14 +506,14 @@
 
 int VncClientConnection::ScreenWidth() const {
   return current_orientation_ == ScreenOrientation::Portrait
-             ? ActualScreenWidth()
-             : ActualScreenHeight();
+             ? ScreenConnector::ScreenWidth()
+             : ScreenConnector::ScreenHeight();
 }
 
 int VncClientConnection::ScreenHeight() const {
   return current_orientation_ == ScreenOrientation::Portrait
-             ? ActualScreenHeight()
-             : ActualScreenWidth();
+             ? ScreenConnector::ScreenHeight()
+             : ScreenConnector::ScreenWidth();
 }
 
 void VncClientConnection::SetScreenOrientation(ScreenOrientation orientation) {
diff --git a/host/frontend/vnc_server/vnc_utils.h b/host/frontend/vnc_server/vnc_utils.h
index db88131..7a80518 100644
--- a/host/frontend/vnc_server/vnc_utils.h
+++ b/host/frontend/vnc_server/vnc_utils.h
@@ -63,28 +63,5 @@
   ScreenOrientation orientation{};
 };
 
-inline constexpr int BytesPerPixel() {
-  return sizeof(uint32_t);
-}
-
-// The width of the screen regardless of orientation. Does not change.
-inline int ActualScreenWidth() {
-  return vsoc::CuttlefishConfig::Get()->x_res();
-}
-
-// The length of the screen stride regardless of orientation. Does not change.
-inline int ActualScreenStride() {
-  return AlignToPowerOf2(ActualScreenWidth() * BytesPerPixel(), 4);
-}
-
-// The height of the screen regardless of orientation. Does not change.
-inline int ActualScreenHeight() {
-  return vsoc::CuttlefishConfig::Get()->y_res();
-}
-
-inline int ScreenSizeInBytes() {
-  return ActualScreenWidth() * ActualScreenHeight() * BytesPerPixel();
-}
-
 }  // namespace vnc
 }  // namespace cvd
diff --git a/host/libs/screen_connector/Android.bp b/host/libs/screen_connector/Android.bp
new file mode 100644
index 0000000..69fa002
--- /dev/null
+++ b/host/libs/screen_connector/Android.bp
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 2020 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.
+
+cc_library_host_static {
+    name: "libcuttlefish_screen_connector",
+    srcs: [
+        "screen_connector.cpp",
+        "socket_based_screen_connector.cpp",
+        "wayland_screen_connector.cpp",
+    ],
+    header_libs: [
+        "cuttlefish_glog",
+    ],
+    shared_libs: [
+        "libcuttlefish_fs",
+        "libbase",
+        "liblog",
+    ],
+    static_libs: [
+        "libcuttlefish_host_config",
+        "libcuttlefish_utils",
+        "libcuttlefish_wayland_server",
+        "libjsoncpp",
+    ],
+    defaults: ["cuttlefish_host_only"],
+}
diff --git a/host/libs/screen_connector/screen_connector.cpp b/host/libs/screen_connector/screen_connector.cpp
new file mode 100644
index 0000000..906435a
--- /dev/null
+++ b/host/libs/screen_connector/screen_connector.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 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/libs/screen_connector/screen_connector.h"
+
+#include <glog/logging.h>
+
+#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/screen_connector/socket_based_screen_connector.h"
+#include "host/libs/screen_connector/wayland_screen_connector.h"
+
+namespace cvd {
+
+ScreenConnector* ScreenConnector::Get(int frames_fd) {
+  auto config = vsoc::CuttlefishConfig::Get();
+  if (config->gpu_mode() == vsoc::kGpuModeDrmVirgl) {
+    return new WaylandScreenConnector(frames_fd);
+  } else if (config->gpu_mode() == vsoc::kGpuModeGuestSwiftshader) {
+    return new SocketBasedScreenConnector(frames_fd);
+  } else {
+      LOG(ERROR) << "Invalid gpu mode: " << config->gpu_mode();
+      return nullptr;
+  }
+}
+
+}  // namespace cvd
diff --git a/host/frontend/vnc_server/screen_connector.h b/host/libs/screen_connector/screen_connector.h
similarity index 66%
rename from host/frontend/vnc_server/screen_connector.h
rename to host/libs/screen_connector/screen_connector.h
index ef62a4a..c369ab0 100644
--- a/host/frontend/vnc_server/screen_connector.h
+++ b/host/libs/screen_connector/screen_connector.h
@@ -19,15 +19,17 @@
 #include <cstdint>
 #include <functional>
 
+#include "common/libs/utils/size_utils.h"
+#include "host/libs/config/cuttlefish_config.h"
+
 namespace cvd {
-namespace vnc {
 
 using FrameCallback = std::function<void(std::uint32_t /*frame_number*/,
                                          std::uint8_t* /*frame_pixels*/)>;
 
 class ScreenConnector {
  public:
-  static ScreenConnector* Get();
+  static ScreenConnector* Get(int frames_fd);
 
   virtual ~ScreenConnector() = default;
 
@@ -36,9 +38,28 @@
   virtual bool OnFrameAfter(std::uint32_t frame_number,
                             const FrameCallback& frame_callback) = 0;
 
+  static inline constexpr int BytesPerPixel() {
+      return sizeof(int32_t);
+  }
+
+  static inline int ScreenHeight() {
+      return vsoc::CuttlefishConfig::Get()->y_res();
+  }
+
+  static inline int ScreenWidth() {
+      return vsoc::CuttlefishConfig::Get()->x_res();
+  }
+
+  static inline int ScreenStride() {
+      return AlignToPowerOf2(ScreenWidth() * BytesPerPixel(), 4);
+  }
+
+  static inline int ScreenSizeInBytes() {
+      return ScreenStride() * ScreenHeight() * BytesPerPixel();
+  }
+
  protected:
   ScreenConnector() = default;
 };
 
-}  // namespace vnc
 }  // namespace cvd
\ No newline at end of file
diff --git a/host/libs/screen_connector/socket_based_screen_connector.cpp b/host/libs/screen_connector/socket_based_screen_connector.cpp
new file mode 100644
index 0000000..7e6333a
--- /dev/null
+++ b/host/libs/screen_connector/socket_based_screen_connector.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2019 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/libs/screen_connector/socket_based_screen_connector.h"
+
+#include <glog/logging.h>
+
+#include "common/libs/fs/shared_fd.h"
+
+namespace cvd {
+
+SocketBasedScreenConnector::SocketBasedScreenConnector(int frames_fd) {
+screen_server_thread_ =
+    std::thread([this, frames_fd]() { ServerLoop(frames_fd); });
+}
+
+bool SocketBasedScreenConnector::OnFrameAfter(
+    std::uint32_t frame_number, const FrameCallback& frame_callback) {
+  int buffer_idx = WaitForNewFrameSince(&frame_number);
+  void* buffer = GetBuffer(buffer_idx);
+  frame_callback(frame_number, reinterpret_cast<uint8_t*>(buffer));
+  return true;
+}
+
+int SocketBasedScreenConnector::WaitForNewFrameSince(std::uint32_t* seq_num) {
+  std::unique_lock<std::mutex> lock(new_frame_mtx_);
+  while (seq_num_ == *seq_num) {
+    new_frame_cond_var_.wait(lock);
+  }
+  *seq_num = seq_num_;
+  return newest_buffer_;
+}
+
+void* SocketBasedScreenConnector::GetBuffer(int buffer_idx) {
+  if (buffer_idx < 0) return nullptr;
+  buffer_idx %= NUM_BUFFERS_;
+  return &buffer_[buffer_idx * ScreenSizeInBytes()];
+}
+
+void SocketBasedScreenConnector::ServerLoop(int frames_fd) {
+  if (frames_fd < 0) {
+    LOG(FATAL) << "Invalid file descriptor: " << frames_fd;
+    return;
+  }
+  auto server = SharedFD::Dup(frames_fd);
+  close(frames_fd);
+  if (!server->IsOpen()) {
+    LOG(FATAL) << "Unable to dup screen server: " << server->StrError();
+    return;
+  }
+
+  int current_buffer = 0;
+
+  while (1) {
+    LOG(INFO) << "Screen Connector accepting connections...";
+    auto conn = SharedFD::Accept(*server);
+    if (!conn->IsOpen()) {
+      LOG(ERROR) << "Disconnected fd returned from accept";
+      continue;
+    }
+    while (conn->IsOpen()) {
+      int32_t size = 0;
+      if (conn->Read(&size, sizeof(size)) < 0) {
+        LOG(ERROR) << "Failed to read from hwcomposer: " << conn->StrError();
+        break;
+      }
+      auto buff = reinterpret_cast<uint8_t*>(GetBuffer(current_buffer));
+      while (size > 0) {
+        auto read = conn->Read(buff, size);
+        if (read < 0) {
+          LOG(ERROR) << "Failed to read from hwcomposer: " << conn->StrError();
+          conn->Close();
+          break;
+        }
+        size -= read;
+        buff += read;
+      }
+      BroadcastNewFrame(current_buffer);
+      current_buffer = (current_buffer + 1) % NUM_BUFFERS_;
+    }
+  }
+}
+
+void SocketBasedScreenConnector::BroadcastNewFrame(int buffer_idx) {
+  {
+    std::lock_guard<std::mutex> lock(new_frame_mtx_);
+    seq_num_++;
+    newest_buffer_ = buffer_idx;
+  }
+  new_frame_cond_var_.notify_all();
+}
+} // namespace cvd
diff --git a/host/libs/screen_connector/socket_based_screen_connector.h b/host/libs/screen_connector/socket_based_screen_connector.h
new file mode 100644
index 0000000..0ed8414
--- /dev/null
+++ b/host/libs/screen_connector/socket_based_screen_connector.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2019 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 "host/libs/screen_connector/screen_connector.h"
+
+#include <atomic>
+#include <cinttypes>
+#include <condition_variable>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+namespace cvd {
+
+class SocketBasedScreenConnector : public ScreenConnector {
+ public:
+  explicit SocketBasedScreenConnector(int frames_fd);
+
+  bool OnFrameAfter(std::uint32_t frame_number,
+                    const FrameCallback& frame_callback) override;
+
+ private:
+  static constexpr int NUM_BUFFERS_ = 4;
+
+  int WaitForNewFrameSince(std::uint32_t* seq_num);
+  void* GetBuffer(int buffer_idx);
+  void ServerLoop(int frames_fd);
+  void BroadcastNewFrame(int buffer_idx);
+
+  std::vector<std::uint8_t> buffer_ =
+      std::vector<std::uint8_t>(NUM_BUFFERS_ * ScreenSizeInBytes());
+  std::uint32_t seq_num_{0};
+  int newest_buffer_ = 0;
+  std::condition_variable new_frame_cond_var_;
+  std::mutex new_frame_mtx_;
+  std::thread screen_server_thread_;
+};
+
+} // namespace cvd
\ No newline at end of file
diff --git a/host/libs/screen_connector/wayland_screen_connector.cpp b/host/libs/screen_connector/wayland_screen_connector.cpp
new file mode 100644
index 0000000..8059290
--- /dev/null
+++ b/host/libs/screen_connector/wayland_screen_connector.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 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/libs/screen_connector/wayland_screen_connector.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <future>
+
+#include <glog/logging.h>
+
+#include "host/libs/wayland/wayland_server.h"
+
+namespace cvd {
+
+WaylandScreenConnector::WaylandScreenConnector(int frames_fd) {
+  int wayland_fd = fcntl(frames_fd, F_DUPFD_CLOEXEC, 3);
+  CHECK(wayland_fd != -1) << "Unable to dup server, errno " << errno;
+  close(frames_fd);
+
+  server_.reset(new wayland::WaylandServer(wayland_fd));
+}
+
+bool WaylandScreenConnector::OnFrameAfter(
+    std::uint32_t frame_number, const FrameCallback& frame_callback) {
+  std::future<void> frame_callback_completed_future =
+      server_->OnFrameAfter(frame_number, frame_callback);
+
+  frame_callback_completed_future.get();
+
+  return true;
+}
+
+}  // namespace cvd
\ No newline at end of file
diff --git a/host/libs/screen_connector/wayland_screen_connector.h b/host/libs/screen_connector/wayland_screen_connector.h
new file mode 100644
index 0000000..537bb31
--- /dev/null
+++ b/host/libs/screen_connector/wayland_screen_connector.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 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 "host/libs/screen_connector/screen_connector.h"
+
+#include <memory>
+
+#include "host/libs/wayland/wayland_server.h"
+
+namespace cvd {
+
+class WaylandScreenConnector : public ScreenConnector {
+ public:
+  WaylandScreenConnector(int frames_fd);
+
+  bool OnFrameAfter(std::uint32_t frame_number,
+                    const FrameCallback& frame_callback) override;
+
+ private:
+  std::unique_ptr<wayland::WaylandServer> server_;
+};
+
+}
\ No newline at end of file
diff --git a/host/libs/wayland/Android.bp b/host/libs/wayland/Android.bp
index 0fd6526..6123d67 100644
--- a/host/libs/wayland/Android.bp
+++ b/host/libs/wayland/Android.bp
@@ -32,7 +32,6 @@
     static_libs: [
         "libdrm",
         "libffi",
-        "libgflags",
         "libwayland_server",
         "libwayland_extension_server_protocols",
     ],