Adds a WaylandScreenConnector to VNC Server

Creates a ScreenConnector which runs a minimal WaylandServer compositing server
to receive frame updates from the device.

Note: This changes the interface of ScreenConnector to require clients to
provide a callback functor which can be run within the WaylandServer event
loop. Unlike the existing ScreenConnectors, the Wayland compositing server
must explicitly acknowledge and notify the source when the server is done
with a given buffer so the source can reuse that buffer. The reference
Wayland server implementation also does not appear to be thread safe with
in a single Wayland client so ScreenConnector clients can not be responsible
for acknowledging and notifying the source.

Bug: b/128842306
Test: locally built and ran cuttlefish with crosvm<-wayland->vnc
Change-Id: Iada180cc4acafc2bf2f41c8d0981f38d509858a3
diff --git a/host/frontend/vnc_server/Android.bp b/host/frontend/vnc_server/Android.bp
index 0e82b2f..344e47b 100644
--- a/host/frontend/vnc_server/Android.bp
+++ b/host/frontend/vnc_server/Android.bp
@@ -34,12 +34,17 @@
         "libcuttlefish_utils",
         "cuttlefish_tcp_socket",
         "libbase",
+        "liblog",
     ],
     static_libs: [
         "libcuttlefish_host_config",
+        "libcuttlefish_wayland_server",
+        "libffi",
         "libjsoncpp",
         "libjpeg",
         "libgflags",
+        "libwayland_server",
+        "libwayland_extension_server_protocols",
     ],
     defaults: ["cuttlefish_host_only"],
 }
diff --git a/host/frontend/vnc_server/screen_connector.cpp b/host/frontend/vnc_server/screen_connector.cpp
index 35cf22f..04d4f33 100644
--- a/host/frontend/vnc_server/screen_connector.cpp
+++ b/host/frontend/vnc_server/screen_connector.cpp
@@ -24,6 +24,7 @@
 #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, "");
 
@@ -31,6 +32,7 @@
 namespace vnc {
 
 namespace {
+
 // TODO(b/128852363): Substitute with one based on memory shared with the
 //  wayland mock
 class SocketBasedScreenConnector : public ScreenConnector {
@@ -39,7 +41,18 @@
     screen_server_thread_ = std::thread([this]() { ServerLoop(); });
   }
 
-  int WaitForNewFrameSince(std::uint32_t* seq_num) override {
+  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);
@@ -48,15 +61,12 @@
     return newest_buffer_;
   }
 
-  void* GetBuffer(int buffer_idx) override {
+  void* GetBuffer(int buffer_idx) {
     if (buffer_idx < 0) return nullptr;
     buffer_idx %= NUM_BUFFERS_;
     return &buffer_[buffer_idx * ScreenSizeInBytes()];
   }
 
- private:
-  static constexpr int NUM_BUFFERS_ = 4;
-
   void ServerLoop() {
     if (FLAGS_frame_server_fd < 0) {
       LOG(FATAL) << "Invalid file descriptor: " << FLAGS_frame_server_fd;
@@ -120,6 +130,31 @@
   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() {
diff --git a/host/frontend/vnc_server/screen_connector.h b/host/frontend/vnc_server/screen_connector.h
index 9c7b9e0..ef62a4a 100644
--- a/host/frontend/vnc_server/screen_connector.h
+++ b/host/frontend/vnc_server/screen_connector.h
@@ -17,18 +17,24 @@
 #pragma once
 
 #include <cstdint>
+#include <functional>
 
 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();
 
   virtual ~ScreenConnector() = default;
 
-  virtual int WaitForNewFrameSince(std::uint32_t* seq_num) = 0;
-  virtual void* GetBuffer(int buffer_idx) = 0;
+  // Runs the given callback on the next available frame after the given
+  // frame number and returns true if successful.
+  virtual bool OnFrameAfter(std::uint32_t frame_number,
+                            const FrameCallback& frame_callback) = 0;
 
  protected:
   ScreenConnector() = default;
diff --git a/host/frontend/vnc_server/simulated_hw_composer.cpp b/host/frontend/vnc_server/simulated_hw_composer.cpp
index 96702e8..8eb6d39 100644
--- a/host/frontend/vnc_server/simulated_hw_composer.cpp
+++ b/host/frontend/vnc_server/simulated_hw_composer.cpp
@@ -68,16 +68,14 @@
 }
 
 void SimulatedHWComposer::MakeStripes() {
-  std::uint32_t previous_seq_num{};
+  std::uint32_t previous_frame_number = 0;
   auto screen_height = ActualScreenHeight();
   Message raw_screen;
   std::uint64_t stripe_seq_num = 1;
-  while (!closed()) {
-    bb_->WaitForAtLeastOneClientConnection();
-    int buffer_idx = screen_connector_->WaitForNewFrameSince(&previous_seq_num);
-    const char* frame_start =
-        static_cast<char*>(screen_connector_->GetBuffer(buffer_idx));
-    raw_screen.assign(frame_start, frame_start + ScreenSizeInBytes());
+
+  const FrameCallback frame_callback = [&](uint32_t frame_number,
+                                           uint8_t* frame_pixels) {
+    raw_screen.assign(frame_pixels, frame_pixels + ScreenSizeInBytes());
 
     for (int i = 0; i < kNumStripes; ++i) {
       ++stripe_seq_num;
@@ -98,7 +96,7 @@
       // on klp
       Stripe s{};
       s.index = i;
-      s.frame_id = previous_seq_num;
+      s.frame_id = frame_number;
       s.x = 0;
       s.y = y;
       s.width = ActualScreenWidth();
@@ -109,6 +107,14 @@
       s.orientation = ScreenOrientation::Portrait;
       stripes_.Push(std::move(s));
     }
+
+    previous_frame_number = frame_number;
+  };
+
+  while (!closed()) {
+    bb_->WaitForAtLeastOneClientConnection();
+
+    screen_connector_->OnFrameAfter(previous_frame_number, frame_callback);
   }
 }