[feedback] initial check in of the feedback data provider service

* this checks in the public FIDL API and a placeholder C++ implementation with tests
* restricted to the GetScreenshot() method, which is the most pressing feature

DX-957 #comment
DX-997 #comment

TESTED=`fx run-test feedback_agent_tests`

Change-Id: Ia1e88fb494b616bb5ae6e7f6150b14b1ddcfd0ca
diff --git a/garnet/bin/feedback_agent/BUILD.gn b/garnet/bin/feedback_agent/BUILD.gn
new file mode 100644
index 0000000..01bd869
--- /dev/null
+++ b/garnet/bin/feedback_agent/BUILD.gn
@@ -0,0 +1,47 @@
+# Copyright 2019 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/package.gni")
+import("//build/package/component.gni")
+
+package("feedback_agent") {
+  components = [ ":component" ]
+}
+
+fuchsia_component("component") {
+  binary = "feedback_agent"
+
+  manifest = "meta/feedback_agent.cmx"
+
+  deps = [
+    ":main",
+  ]
+}
+
+executable("main") {
+  output_name = "feedback_agent"
+
+  sources = [
+    "main.cc",
+  ]
+
+  deps = [
+    ":src",
+    "//garnet/public/lib/component/cpp",
+    "//garnet/public/lib/syslog/cpp",
+    "//sdk/fidl/fuchsia.feedback",
+    "//zircon/public/lib/async-loop-cpp",
+  ]
+}
+
+source_set("src") {
+  sources = [
+    "feedback_agent.cc",
+    "feedback_agent.h",
+  ]
+
+  public_deps = [
+    "//sdk/fidl/fuchsia.feedback",
+  ]
+}
diff --git a/garnet/bin/feedback_agent/OWNERS b/garnet/bin/feedback_agent/OWNERS
new file mode 100644
index 0000000..fd45165
--- /dev/null
+++ b/garnet/bin/feedback_agent/OWNERS
@@ -0,0 +1,2 @@
+frousseau@google.com
+*
diff --git a/garnet/bin/feedback_agent/feedback_agent.cc b/garnet/bin/feedback_agent/feedback_agent.cc
new file mode 100644
index 0000000..64b315d
--- /dev/null
+++ b/garnet/bin/feedback_agent/feedback_agent.cc
@@ -0,0 +1,17 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "feedback_agent.h"
+
+#include <fuchsia/feedback/cpp/fidl.h>
+
+namespace fuchsia {
+namespace feedback {
+
+void FeedbackAgent::GetPngScreenshot(GetPngScreenshotCallback callback) {
+  callback(Status::UNIMPLEMENTED, /*screenshot=*/nullptr);
+}
+
+}  // namespace feedback
+}  // namespace fuchsia
diff --git a/garnet/bin/feedback_agent/feedback_agent.h b/garnet/bin/feedback_agent/feedback_agent.h
new file mode 100644
index 0000000..22fd045
--- /dev/null
+++ b/garnet/bin/feedback_agent/feedback_agent.h
@@ -0,0 +1,23 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GARNET_BIN_FEEDBACK_DATA_FEEDBACK_AGENT_H_
+#define GARNET_BIN_FEEDBACK_DATA_FEEDBACK_AGENT_H_
+
+#include <fuchsia/feedback/cpp/fidl.h>
+
+namespace fuchsia {
+namespace feedback {
+
+// Provides data useful to attach in feedback reports (crash or user feedback).
+class FeedbackAgent : public DataProvider {
+ public:
+  // Returns a PNG image of the current view.
+  void GetPngScreenshot(GetPngScreenshotCallback callback) override;
+};
+
+}  // namespace feedback
+}  // namespace fuchsia
+
+#endif  // GARNET_BIN_FEEDBACK_DATA_FEEDBACK_AGENT_H_
diff --git a/garnet/bin/feedback_agent/main.cc b/garnet/bin/feedback_agent/main.cc
new file mode 100644
index 0000000..86c4db0
--- /dev/null
+++ b/garnet/bin/feedback_agent/main.cc
@@ -0,0 +1,29 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdlib.h>
+
+#include <fuchsia/feedback/cpp/fidl.h>
+#include <lib/async-loop/cpp/loop.h>
+#include <lib/component/cpp/startup_context.h>
+#include <lib/syslog/cpp/logger.h>
+
+#include "feedback_agent.h"
+
+int main(int argc, const char** argv) {
+  syslog::InitLogger({"feedback_agent"});
+
+  fuchsia::feedback::FeedbackAgent feedback_agent;
+
+  async::Loop loop(&kAsyncLoopConfigAttachToThread);
+  std::unique_ptr<component::StartupContext> app_context(
+      component::StartupContext::CreateFromStartupInfo());
+  fidl::BindingSet<fuchsia::feedback::DataProvider> bindings;
+  app_context->outgoing().AddPublicService(
+      bindings.GetHandler(&feedback_agent));
+
+  loop.Run();
+
+  return EXIT_SUCCESS;
+}
diff --git a/garnet/bin/feedback_agent/meta/feedback_agent.cmx b/garnet/bin/feedback_agent/meta/feedback_agent.cmx
new file mode 100644
index 0000000..9b7e67a
--- /dev/null
+++ b/garnet/bin/feedback_agent/meta/feedback_agent.cmx
@@ -0,0 +1,10 @@
+{
+    "program": {
+        "binary": "bin/feedback_agent"
+    },
+    "sandbox": {
+        "services": [
+            "fuchsia.logger.LogSink"
+        ]
+    }
+}
diff --git a/garnet/bin/feedback_agent/tests/BUILD.gn b/garnet/bin/feedback_agent/tests/BUILD.gn
new file mode 100644
index 0000000..6960795
--- /dev/null
+++ b/garnet/bin/feedback_agent/tests/BUILD.gn
@@ -0,0 +1,56 @@
+# Copyright 2019 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/test/test_package.gni")
+
+test_package("feedback_agent_tests") {
+  tests = [
+    {
+      name = "feedback_agent_unittest"
+    },
+    {
+      name = "feedback_agent_integration_test"
+    },
+  ]
+
+  deps = [
+    ":integration_test",
+    ":unittest",
+  ]
+}
+
+executable("unittest") {
+  testonly = true
+
+  output_name = "feedback_agent_unittest"
+
+  sources = [
+    "feedback_agent_unittest.cc",
+  ]
+
+  deps = [
+    "//garnet/bin/feedback_agent:src",
+    "//garnet/public/lib/fxl/test:gtest_main",
+    "//sdk/fidl/fuchsia.feedback",
+    "//third_party/googletest:gtest",
+  ]
+}
+
+executable("integration_test") {
+  testonly = true
+
+  output_name = "feedback_agent_integration_test"
+
+  sources = [
+    "feedback_agent_integration_test.cc",
+  ]
+
+  deps = [
+    "//garnet/public/lib/component/cpp/testing",
+    "//garnet/public/lib/fxl/test:gtest_main",
+    "//sdk/fidl/fuchsia.feedback",
+    "//third_party/googletest:gtest",
+    "//zircon/public/lib/zx",
+  ]
+}
diff --git a/garnet/bin/feedback_agent/tests/feedback_agent_integration_test.cc b/garnet/bin/feedback_agent/tests/feedback_agent_integration_test.cc
new file mode 100644
index 0000000..5e61097
--- /dev/null
+++ b/garnet/bin/feedback_agent/tests/feedback_agent_integration_test.cc
@@ -0,0 +1,31 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <fuchsia/feedback/cpp/fidl.h>
+#include <gtest/gtest.h>
+#include <lib/component/cpp/environment_services_helper.h>
+#include <zircon/errors.h>
+
+namespace fuchsia {
+namespace feedback {
+namespace {
+
+// Smoke-tests the real environment service for the
+// fuchsia.feedback.DataProvider FIDL interface, connecting through FIDL.
+TEST(FeedbackAgentIntegrationTest, SmokeTest) {
+  DataProviderSyncPtr feedback_data_provider;
+  auto environment_services = component::GetEnvironmentServices();
+  environment_services->ConnectToService(feedback_data_provider.NewRequest());
+
+  Status out_status;
+  std::unique_ptr<PngImage> out_image;
+  ASSERT_EQ(feedback_data_provider->GetPngScreenshot(&out_status, &out_image),
+            ZX_OK);
+  EXPECT_EQ(out_status, Status::UNIMPLEMENTED);
+  EXPECT_EQ(out_image, nullptr);
+}
+
+}  // namespace
+}  // namespace feedback
+}  // namespace fuchsia
diff --git a/garnet/bin/feedback_agent/tests/feedback_agent_unittest.cc b/garnet/bin/feedback_agent/tests/feedback_agent_unittest.cc
new file mode 100644
index 0000000..d3fdfe5
--- /dev/null
+++ b/garnet/bin/feedback_agent/tests/feedback_agent_unittest.cc
@@ -0,0 +1,34 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "garnet/bin/feedback_agent/feedback_agent.h"
+
+#include <fuchsia/feedback/cpp/fidl.h>
+#include <gtest/gtest.h>
+
+namespace fuchsia {
+namespace feedback {
+namespace {
+
+// Unit-tests the implementation of the fuchsia.feedback.DataProvider FIDL
+// interface.
+//
+// This does not test the environment service. It directly instantiates the
+// class, without connecting through FIDL.
+TEST(FeedbackAgentTest, GetPngScreenshot_Basic) {
+  FeedbackAgent agent;
+  Status out_status;
+  std::unique_ptr<PngImage> out_image;
+  agent.GetPngScreenshot([&out_status, &out_image](
+                             Status status, std::unique_ptr<PngImage> image) {
+    out_status = status;
+    out_image = std::move(image);
+  });
+  EXPECT_EQ(out_status, Status::UNIMPLEMENTED);
+  EXPECT_EQ(out_image, nullptr);
+}
+
+}  // namespace
+}  // namespace feedback
+}  // namespace fuchsia
diff --git a/garnet/bin/feedback_agent/tests/meta/feedback_agent_integration_test.cmx b/garnet/bin/feedback_agent/tests/meta/feedback_agent_integration_test.cmx
new file mode 100644
index 0000000..9fe516d
--- /dev/null
+++ b/garnet/bin/feedback_agent/tests/meta/feedback_agent_integration_test.cmx
@@ -0,0 +1,17 @@
+{
+    "program": {
+        "binary": "test/feedback_agent_integration_test"
+    },
+    "facets": {
+        "fuchsia.test": {
+            "injected-services": {
+                "fuchsia.feedback.DataProvider": "fuchsia-pkg://fuchsia.com/feedback_agent#meta/feedback_agent.cmx"
+            }
+        }
+    },
+    "sandbox": {
+        "services": [
+            "fuchsia.feedback.DataProvider"
+        ]
+    }
+}
diff --git a/garnet/bin/feedback_agent/tests/meta/feedback_agent_unittest.cmx b/garnet/bin/feedback_agent/tests/meta/feedback_agent_unittest.cmx
new file mode 100644
index 0000000..8044fc0
--- /dev/null
+++ b/garnet/bin/feedback_agent/tests/meta/feedback_agent_unittest.cmx
@@ -0,0 +1,5 @@
+{
+    "program": {
+        "binary": "test/feedback_agent_unittest"
+    }
+}
diff --git a/garnet/bin/sysmgr/config/services.config b/garnet/bin/sysmgr/config/services.config
index c84518a..a4d4429 100644
--- a/garnet/bin/sysmgr/config/services.config
+++ b/garnet/bin/sysmgr/config/services.config
@@ -18,6 +18,7 @@
     "fuchsia.devicesettings.DeviceSettingsManager": "fuchsia-pkg://fuchsia.com/device_settings_manager#meta/device_settings_manager.cmx",
     "fuchsia.device.display.Manager" : "fuchsia-pkg://fuchsia.com/display_manager#meta/display_manager.cmx",
     "fuchsia.examples.shadertoy.ShadertoyFactory": "fuchsia-pkg://fuchsia.com/shadertoy_service#meta/shadertoy_service.cmx",
+    "fuchsia.feedback.DataProvider": "fuchsia-pkg://fuchsia.com/feedback_agent#meta/feedback_agent.cmx",
     "fuchsia.fonts.Provider": "fuchsia-pkg://fuchsia.com/fonts#meta/fonts.cmx",
     "fuchsia.guest.EnvironmentManager": "fuchsia-pkg://fuchsia.com/guest_manager#meta/guest_manager.cmx",
     "fuchsia.kms.KeyManager":"fuchsia-pkg://fuchsia.com/kms#meta/key_manager.cmx",
diff --git a/garnet/packages/prod/all b/garnet/packages/prod/all
index 1dcf45f..1b3d4c4 100644
--- a/garnet/packages/prod/all
+++ b/garnet/packages/prod/all
@@ -34,6 +34,7 @@
         "garnet/packages/prod/dhcpd_test_client",
         "garnet/packages/prod/drivers",
         "garnet/packages/prod/far",
+        "garnet/packages/prod/feedback_agent",
         "garnet/packages/prod/fonts",
         "garnet/packages/prod/fortune",
         "garnet/packages/prod/guest_runner",
diff --git a/garnet/packages/prod/feedback_agent b/garnet/packages/prod/feedback_agent
new file mode 100644
index 0000000..cd9eaed
--- /dev/null
+++ b/garnet/packages/prod/feedback_agent
@@ -0,0 +1,5 @@
+{
+    "packages": [
+        "//garnet/bin/feedback_agent"
+    ]
+}
diff --git a/garnet/packages/tests/all b/garnet/packages/tests/all
index eb5ff22..f80cd8f 100644
--- a/garnet/packages/tests/all
+++ b/garnet/packages/tests/all
@@ -27,6 +27,7 @@
         "garnet/packages/tests/elflib",
         "garnet/packages/tests/escher",
         "garnet/packages/tests/examples",
+        "garnet/packages/tests/feedback_agent",
         "garnet/packages/tests/fidl_compatibility_test_bin",
         "garnet/packages/tests/fidl_compatibility_test_server_cpp",
         "garnet/packages/tests/fidl_compatibility_test_server_go",
diff --git a/garnet/packages/tests/feedback_agent b/garnet/packages/tests/feedback_agent
new file mode 100644
index 0000000..ed56282
--- /dev/null
+++ b/garnet/packages/tests/feedback_agent
@@ -0,0 +1,5 @@
+{
+    "packages": [
+        "//garnet/bin/feedback_agent/tests:feedback_agent_tests"
+    ]
+}
diff --git a/sdk/fidl/fuchsia.feedback/BUILD.gn b/sdk/fidl/fuchsia.feedback/BUILD.gn
new file mode 100644
index 0000000..7d119d0
--- /dev/null
+++ b/sdk/fidl/fuchsia.feedback/BUILD.gn
@@ -0,0 +1,17 @@
+# Copyright 2019 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/fidl/fidl.gni")
+
+fidl("fuchsia.feedback") {
+  sdk_category = "partner"
+
+  sources = [
+    "data_provider.fidl",
+  ]
+
+  public_deps = [
+    "//zircon/public/fidl/fuchsia-mem",
+  ]
+}
diff --git a/sdk/fidl/fuchsia.feedback/data_provider.fidl b/sdk/fidl/fuchsia.feedback/data_provider.fidl
new file mode 100644
index 0000000..44b1bda
--- /dev/null
+++ b/sdk/fidl/fuchsia.feedback/data_provider.fidl
@@ -0,0 +1,35 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library fuchsia.feedback;
+
+using fuchsia.mem;
+
+/// Provides data useful to attach in feedback reports (crash or user feedback).
+[Discoverable]
+interface DataProvider {
+    /// Returns a PNG image of the current view.
+    GetPngScreenshot() -> (Status status, PngImage? screenshot);
+};
+
+/// The return status to check whether to expect a payload (on OK) or not (otherwise).
+enum Status {
+    UNKNOWN = 0;
+    OK = 1;
+    ERROR = 2;
+    UNIMPLEMENTED = 3;
+};
+
+/// The PNG image payload needed to recreate the image.
+struct PngImage {
+    fuchsia.mem.Buffer data;
+    ImageDimensions dimensions;
+};
+
+/// The dimensions of an image in pixels.
+struct ImageDimensions {
+    uint32 width_in_px;
+    uint32 height_in_px;
+};
+