Added PlatformHandle thunks.

Added thunks for exchanging PlatformHandles (file descriptors) between mojo services as MojoHandles. Basically a port of https://codereview.chromium.org/1113393002 plus some testing code. This is intended to be used to allow cross-process sharing of GPU buffers

Change-Id: I5c77f0ed0381c0b03ce0280314f7fbef3551d895

BUG=
R=viettrungluu@chromium.org

Review URL: https://codereview.chromium.org/1578423002 .
diff --git a/mojo/BUILD.gn b/mojo/BUILD.gn
index 1909cb3..16fdbba 100644
--- a/mojo/BUILD.gn
+++ b/mojo/BUILD.gn
@@ -67,6 +67,7 @@
     "//mojo/file_utils:file_utils_apptests",
     "//mojo/gles2:mgl_unittests",
     "//mojo/public/cpp/bindings/tests:versioning_apptests",
+    "//mojo/public/platform/native:tests",
     "//mojo/services/files/c:apptests",
     "//mojo/services/files/cpp:files_impl_apptests",
     "//mojo/services/log/cpp:log_client_apptests",
diff --git a/mojo/public/platform/native/BUILD.gn b/mojo/public/platform/native/BUILD.gn
index e9c6034..e88ac01 100644
--- a/mojo/public/platform/native/BUILD.gn
+++ b/mojo/public/platform/native/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import("../../mojo_sdk.gni")
+import("../../mojo_application.gni")
 
 mojo_sdk_source_set("system") {
   sources = [
@@ -125,3 +126,51 @@
 
   mojo_sdk_deps = [ "mojo/public/c/gpu:MGL_onscreen" ]
 }
+
+mojo_sdk_source_set("platform_handle") {
+  sources = [
+    "platform_handle_private_thunks.c",
+    "platform_handle_private_thunks.h",
+  ]
+
+  mojo_sdk_deps = [
+    "mojo/public/platform/native:platform_handle_api",
+    "mojo/public/c/system",
+  ]
+}
+
+# Only targets that are calling the thunks should depend upon this.
+mojo_sdk_source_set("platform_handle_api") {
+  sources = [
+    "platform_handle_private.h",
+  ]
+  mojo_sdk_deps = [ "mojo/public/c/system:system" ]
+}
+
+mojo_native_application("platform_handle_private_apptest") {
+  output_name = "platform_handle_private_apptests"
+
+  testonly = true
+
+  sources = [
+    "platform_handle_private_apptest.cc",
+  ]
+
+  deps = [
+    ":platform_handle",
+    ":platform_handle_api",
+    "../../cpp/application:standalone",
+    "../../cpp/application:test_support_standalone",
+    "../../cpp/environment",
+    "../../cpp/system",
+  ]
+}
+
+group("tests") {
+  testonly = true
+
+  deps = [
+    ":platform_handle_private_apptest",
+    ":system_impl_private_tests",
+  ]
+}
diff --git a/mojo/public/platform/native/platform_handle_private.h b/mojo/public/platform/native/platform_handle_private.h
new file mode 100644
index 0000000..e81d572
--- /dev/null
+++ b/mojo/public/platform/native/platform_handle_private.h
@@ -0,0 +1,35 @@
+// Copyright 2016 The Chromium 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 MOJO_PUBLIC_PLATFORM_NATIVE_PLATFORM_HANDLE_PRIVATE_H_
+#define MOJO_PUBLIC_PLATFORM_NATIVE_PLATFORM_HANDLE_PRIVATE_H_
+
+#include "mojo/public/c/system/types.h"
+
+typedef int MojoPlatformHandle;  // Unix file descriptor
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Wraps |platform_handle| in a MojoHandle so that it can transported. Returns
+// MOJO_RESULT_OK on success, all other results indicate failure. This takes
+// ownership of |platform_handle|, regardless of whether this succeeds.
+MojoResult MojoCreatePlatformHandleWrapper(MojoPlatformHandle platform_handle,
+                                           MojoHandle* wrapper);
+
+// Extracts |platform_handle| from |wrapper|. Returns MOJO_RESULT_OK on success,
+// all other results indicate failure. If this succeeds, it causes |wrapper| to
+// relinquish ownership of |platform_handle|, so MojoClose'ing |wrapper| will no
+// longer close the underlying |platform_handle|. Never the less, it is still
+// neccessary to MojoClose |wrapper|, but this will not affect the underlying
+// descriptor after this call.
+MojoResult MojoExtractPlatformHandle(MojoHandle wrapper,
+                                     MojoPlatformHandle* platform_handle);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // MOJO_PUBLIC_PLATFORM_NATIVE_PLATFORM_HANDLE_PRIVATE_H_
diff --git a/mojo/public/platform/native/platform_handle_private_apptest.cc b/mojo/public/platform/native/platform_handle_private_apptest.cc
new file mode 100644
index 0000000..28e1b47
--- /dev/null
+++ b/mojo/public/platform/native/platform_handle_private_apptest.cc
@@ -0,0 +1,66 @@
+// Copyright 2016 The Chromium 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 "mojo/public/platform/native/platform_handle_private.h"
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "mojo/public/cpp/application/application_impl.h"
+#include "mojo/public/cpp/application/application_test_base.h"
+#include "mojo/public/cpp/environment/logging.h"
+#include "mojo/public/cpp/system/macros.h"
+
+namespace mojo {
+namespace {
+
+class PlatformHandlePrivateApplicationTest : public test::ApplicationTestBase {
+ public:
+  PlatformHandlePrivateApplicationTest() : ApplicationTestBase() {}
+  ~PlatformHandlePrivateApplicationTest() override {}
+
+ private:
+  MOJO_DISALLOW_COPY_AND_ASSIGN(PlatformHandlePrivateApplicationTest);
+};
+
+TEST_F(PlatformHandlePrivateApplicationTest, WrapAndUnwrapFileDescriptor) {
+  MojoPlatformHandle original_handle = -1;
+  MojoPlatformHandle unwrapped_handle = -1;
+  MojoHandle wrapper = MOJO_HANDLE_INVALID;
+
+  int pipe_fds[2] = {-1, -1};
+
+  uint64_t write_buffer = 0xDEADBEEF;
+  uint64_t read_buffer = 0;
+
+  ASSERT_EQ(0, pipe(pipe_fds));
+
+  // Pass second FD through wrapper.
+  original_handle = pipe_fds[1];
+
+  EXPECT_EQ(MOJO_RESULT_OK,
+            MojoCreatePlatformHandleWrapper(original_handle, &wrapper));
+  EXPECT_EQ(MOJO_RESULT_OK,
+            MojoExtractPlatformHandle(wrapper, &unwrapped_handle));
+
+  // Write to wrapped/unwrapped FD.
+  ssize_t bytes_written =
+      write(unwrapped_handle, &write_buffer, sizeof(write_buffer));
+  ASSERT_EQ(sizeof(write_buffer), static_cast<size_t>(bytes_written));
+
+  // Read from other end of pipe.
+  ssize_t bytes_read = read(pipe_fds[0], &read_buffer, sizeof(read_buffer));
+  ASSERT_EQ(sizeof(read_buffer), static_cast<size_t>(bytes_read));
+
+  EXPECT_EQ(bytes_read, bytes_written);
+  EXPECT_EQ(write_buffer, read_buffer);
+
+  EXPECT_EQ(0, close(pipe_fds[0]));
+  EXPECT_EQ(0, close(unwrapped_handle));
+  EXPECT_EQ(MOJO_RESULT_OK, MojoClose(wrapper));
+}
+
+}  // namespace
+}  // namespace mojo
diff --git a/mojo/public/platform/native/platform_handle_private_thunks.c b/mojo/public/platform/native/platform_handle_private_thunks.c
new file mode 100644
index 0000000..9c0b35b
--- /dev/null
+++ b/mojo/public/platform/native/platform_handle_private_thunks.c
@@ -0,0 +1,30 @@
+// Copyright 2016 The Chromium 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 "mojo/public/platform/native/platform_handle_private_thunks.h"
+
+#include "mojo/public/platform/native/thunk_export.h"
+
+#include <assert.h>
+
+static struct MojoPlatformHandlePrivateThunks g_thunks = {0};
+
+MojoResult MojoCreatePlatformHandleWrapper(MojoPlatformHandle platform_handle,
+                                           MojoHandle* wrapper) {
+  assert(g_thunks.CreatePlatformHandleWrapper);
+  return g_thunks.CreatePlatformHandleWrapper(platform_handle, wrapper);
+}
+
+MojoResult MojoExtractPlatformHandle(MojoHandle wrapper,
+                                     MojoPlatformHandle* platform_handle) {
+  assert(g_thunks.ExtractPlatformHandle);
+  return g_thunks.ExtractPlatformHandle(wrapper, platform_handle);
+}
+
+THUNK_EXPORT size_t MojoSetPlatformHandlePrivateThunks(
+    const struct MojoPlatformHandlePrivateThunks* thunks) {
+  if (thunks->size >= sizeof(g_thunks))
+    g_thunks = *thunks;
+  return sizeof(g_thunks);
+}
\ No newline at end of file
diff --git a/mojo/public/platform/native/platform_handle_private_thunks.h b/mojo/public/platform/native/platform_handle_private_thunks.h
new file mode 100644
index 0000000..0a19b0d
--- /dev/null
+++ b/mojo/public/platform/native/platform_handle_private_thunks.h
@@ -0,0 +1,33 @@
+// Copyright 2016 The Chromium 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 MOJO_PUBLIC_PLATFORM_NATIVE_PLATFORM_HANDLE_PRIVATE_THUNKS_H_
+#define MOJO_PUBLIC_PLATFORM_NATIVE_PLATFORM_HANDLE_PRIVATE_THUNKS_H_
+
+#include <stddef.h>
+
+#include "mojo/public/platform/native/platform_handle_private.h"
+
+#pragma pack(push, 8)
+struct MojoPlatformHandlePrivateThunks {
+  size_t size;  // Should be set to sizeof(PlatformHandleThunks).
+  MojoResult (*CreatePlatformHandleWrapper)(MojoPlatformHandle, MojoHandle*);
+  MojoResult (*ExtractPlatformHandle)(MojoHandle, MojoPlatformHandle*);
+};
+#pragma pack(pop)
+
+#ifdef __cplusplus
+inline struct MojoPlatformHandlePrivateThunks
+MojoMakePlatformHandlePrivateThunks() {
+  struct MojoPlatformHandlePrivateThunks system_thunks = {
+      sizeof(struct MojoPlatformHandlePrivateThunks),
+      MojoCreatePlatformHandleWrapper, MojoExtractPlatformHandle};
+  return system_thunks;
+}
+#endif  // __cplusplus
+
+typedef size_t (*MojoSetPlatformHandlePrivateThunksFn)(
+    const struct MojoPlatformHandlePrivateThunks* thunks);
+
+#endif  // MOJO_PUBLIC_PLATFORM_NATIVE_PLATFORM_HANDLE_PRIVATE_THUNKS_H_
diff --git a/shell/BUILD.gn b/shell/BUILD.gn
index 3068cff..3732d0a 100644
--- a/shell/BUILD.gn
+++ b/shell/BUILD.gn
@@ -269,6 +269,7 @@
   sources = [
     "native_application_support.cc",
     "native_application_support.h",
+    "platform_handle_impl.cc",
   ]
 
   public_deps = [
@@ -280,6 +281,7 @@
     "//mojo/gles2:control_thunks",
     "//mojo/gles2:gles2",
     "//mojo/gles2:mgl",
+    "//mojo/public/platform/native:platform_handle_api",
   ]
 
   # This target has to include the public thunk headers, which generally
diff --git a/shell/native_application_support.cc b/shell/native_application_support.cc
index ce171dc..11482fe 100644
--- a/shell/native_application_support.cc
+++ b/shell/native_application_support.cc
@@ -24,6 +24,7 @@
 #include "mojo/public/platform/native/mgl_onscreen_thunks.h"
 #include "mojo/public/platform/native/mgl_signal_sync_point_thunks.h"
 #include "mojo/public/platform/native/mgl_thunks.h"
+#include "mojo/public/platform/native/platform_handle_private_thunks.h"
 #include "mojo/public/platform/native/system_impl_private_thunks.h"
 #include "mojo/public/platform/native/system_thunks.h"
 
@@ -74,6 +75,10 @@
     return false;
   }
 
+  // TODO(freiling): enforce the private nature of this API, somehow?
+  SetThunks(&MojoMakePlatformHandlePrivateThunks,
+            "MojoSetPlatformHandlePrivateThunks", app_library);
+
   // TODO(ncbray): enforce the private nature of this API, somehow?
   SetThunks(&MojoMakeSystemImplControlThunksPrivate,
             "MojoSetSystemImplControlThunksPrivate", app_library);
diff --git a/shell/platform_handle_impl.cc b/shell/platform_handle_impl.cc
new file mode 100644
index 0000000..1c1cfea
--- /dev/null
+++ b/shell/platform_handle_impl.cc
@@ -0,0 +1,34 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains implementations for the platform handle thunks
+// (see //mojo/public/platform/native/platform_handle_private.h)
+
+#include "base/logging.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/public/platform/native/platform_handle_private.h"
+
+using mojo::platform::PlatformHandle;
+using mojo::platform::ScopedPlatformHandle;
+
+MojoResult MojoCreatePlatformHandleWrapper(MojoPlatformHandle platform_handle,
+                                           MojoHandle* wrapper) {
+  PlatformHandle platform_handle_wrapper(platform_handle);
+  ScopedPlatformHandle scoped_platform_handle(platform_handle_wrapper);
+  return mojo::embedder::CreatePlatformHandleWrapper(
+      scoped_platform_handle.Pass(), wrapper);
+}
+
+MojoResult MojoExtractPlatformHandle(MojoHandle wrapper,
+                                     MojoPlatformHandle* platform_handle) {
+  ScopedPlatformHandle scoped_platform_handle;
+  MojoResult result = mojo::embedder::PassWrappedPlatformHandle(
+      wrapper, &scoped_platform_handle);
+  if (result != MOJO_RESULT_OK)
+    return result;
+
+  DCHECK(scoped_platform_handle.is_valid());
+  *platform_handle = scoped_platform_handle.release().fd;
+  return MOJO_RESULT_OK;
+}