Add libvrflinger for use in SurfaceFlinger

A separate CL uses this code from SurfaceFlinger.

Bug: None
Test: Manually ran modified SurfaceFlinger
Change-Id: I34588df1365588c0a0265e1e2325e3dd5516206a
diff --git a/libs/vr/libvrflinger/screenshot_service.cpp b/libs/vr/libvrflinger/screenshot_service.cpp
new file mode 100644
index 0000000..e174943
--- /dev/null
+++ b/libs/vr/libvrflinger/screenshot_service.cpp
@@ -0,0 +1,181 @@
+#include "screenshot_service.h"
+
+#include <utils/Trace.h>
+
+#include <pdx/default_transport/service_endpoint.h>
+#include <private/dvr/display_types.h>
+
+using android::pdx::Message;
+using android::pdx::MessageInfo;
+using android::pdx::default_transport::Endpoint;
+using android::pdx::rpc::DispatchRemoteMethod;
+using android::pdx::rpc::RemoteMethodError;
+using android::pdx::rpc::RemoteMethodReturn;
+
+namespace android {
+namespace dvr {
+
+ScreenshotService::~ScreenshotService() { instance_ = nullptr; }
+
+int ScreenshotService::HandleMessage(pdx::Message& message) {
+  switch (message.GetOp()) {
+    case DisplayScreenshotRPC::GetFormat::Opcode:
+      DispatchRemoteMethod<DisplayScreenshotRPC::GetFormat>(
+          *this, &ScreenshotService::OnGetFormat, message);
+      return 0;
+
+    case DisplayScreenshotRPC::TakeScreenshot::Opcode:
+      DispatchRemoteMethod<DisplayScreenshotRPC::TakeScreenshot>(
+          *this, &ScreenshotService::OnTakeScreenshot, message);
+      return 0;
+
+    default:
+      return Service::HandleMessage(message);
+  }
+}
+
+int ScreenshotService::OnGetFormat(pdx::Message&) {
+  return HAL_PIXEL_FORMAT_RGB_888;
+}
+
+ScreenshotData ScreenshotService::OnTakeScreenshot(pdx::Message& message,
+                                                   int layer_index) {
+  AddWaiter(std::move(message), layer_index);
+  return {};
+}
+
+void ScreenshotService::AddWaiter(pdx::Message&& message, int layer_index) {
+  std::lock_guard<std::mutex> lock(mutex_);
+  waiters_.emplace_back(std::move(message), layer_index);
+}
+
+void ScreenshotService::TakeIfNeeded(
+    std::array<Layer*, HardwareComposer::kMaxHardwareLayers>& hw_layers,
+    Compositor& compositor) {
+  std::lock_guard<std::mutex> lock(mutex_);
+
+  // Send the buffer contents to all of our waiting clients.
+  for (auto& waiter : waiters_) {
+    if (waiter.IsDone())
+      continue;
+
+    if (waiter.layer_index() == 0) {
+      ALOGE(
+          "ScreenshotService::TakeIfNeeded: Capturing the composited display "
+          "output is not yet supported.");
+
+      waiter.Error(EINVAL);
+      continue;
+    }
+
+    if (waiter.layer_index() > 0) {
+      // Check for hardware layer screenshot requests.
+      // Hardware layers are requested with positive indices starting at 1.
+      const size_t layer_index = static_cast<size_t>(waiter.layer_index() - 1);
+
+      if (layer_index >= hw_layers.size()) {
+        waiter.Error(EINVAL);
+        continue;
+      }
+
+      auto buffer = hw_layers[layer_index]->GetBuffer();
+      if (!buffer) {
+        waiter.Error(ENOBUFS);
+        continue;
+      }
+
+      auto data = compositor.ReadBufferPixels(buffer);
+      if (data.empty()) {
+        waiter.Error(ENOBUFS);
+        continue;
+      }
+
+      Take(&waiter, data.data(), buffer->width(), buffer->height(),
+           buffer->width());
+    } else {
+      // Check for compositor input layer screenshot requests.
+      // Prewarp surfaces are requested with negative indices starting at -1.
+      const size_t layer_index = static_cast<size_t>(-waiter.layer_index() - 1);
+
+      if (layer_index >= compositor.GetLayerCount()) {
+        waiter.Error(EINVAL);
+        continue;
+      }
+
+      int width = 0;
+      int height = 0;
+      auto data = compositor.ReadLayerPixels(layer_index, &width, &height);
+      if (data.empty()) {
+        waiter.Error(ENOBUFS);
+        continue;
+      }
+
+      Take(&waiter, data.data(), width, height, width);
+    }
+  }
+
+  // Reply with error to requests that did not match up with a source layer.
+  for (auto& waiter : waiters_) {
+    if (!waiter.IsDone())
+      waiter.Error(EAGAIN);
+  }
+  waiters_.clear();
+}
+
+void ScreenshotWaiter::Reply(const ScreenshotData& screenshot) {
+  ALOGI("Returning screenshot: size=%zu recv_size=%zu",
+        screenshot.buffer.size(), message_.GetReceiveLength());
+  RemoteMethodReturn<DisplayScreenshotRPC::TakeScreenshot>(message_,
+                                                           screenshot);
+}
+
+void ScreenshotWaiter::Error(int error) { RemoteMethodError(message_, error); }
+
+void ScreenshotService::Take(ScreenshotWaiter* waiter, const void* rgba_data,
+                             int32_t width, int32_t height, int buffer_stride) {
+  ATRACE_NAME(__PRETTY_FUNCTION__);
+
+  bool is_portrait = height > width;
+  if (is_portrait) {
+    std::swap(width, height);
+  }
+  int response_stride = width;
+
+  // Convert from RGBA to RGB and if in portrait, rotates to landscape; store
+  // the result in the response buffer.
+  ScreenshotData screenshot{width, height,
+                            std::vector<uint8_t>(width * height * 3)};
+
+  const auto rgba_bytes = static_cast<const uint8_t*>(rgba_data);
+  for (int j = 0; j < height; ++j) {
+    for (int i = 0; i < width; ++i) {
+      // If the screenshot is in portrait mode, rotate into landscape mode.
+      const int response_index = is_portrait
+                                     ? (height - j - 1) * response_stride + i
+                                     : j * response_stride + i;
+      const int buffer_index =
+          is_portrait ? i * buffer_stride + j : j * buffer_stride + i;
+      screenshot.buffer[response_index * 3 + 0] =
+          rgba_bytes[buffer_index * 4 + 0];
+      screenshot.buffer[response_index * 3 + 1] =
+          rgba_bytes[buffer_index * 4 + 1];
+      screenshot.buffer[response_index * 3 + 2] =
+          rgba_bytes[buffer_index * 4 + 2];
+    }
+  }
+
+  waiter->Reply(screenshot);
+}
+
+ScreenshotService::ScreenshotService()
+    : BASE("ScreenshotService",
+           Endpoint::Create(DisplayScreenshotRPC::kClientPath)) {
+  instance_ = this;
+}
+
+ScreenshotService* ScreenshotService::GetInstance() { return instance_; }
+
+ScreenshotService* ScreenshotService::instance_ = nullptr;
+
+}  // namespace dvr
+}  // namespace android